0

I'm trying to write a function where I have to pass an Activity object to a method that requires such an argument. Usually in such case I'm supposed to just type "this" and it automatically recognizes which type of object it's supposed to create. But sometimes this doesn't work and it for whatever reason reassings a different type of object than the one that is required. For example, I actually use the exact same method in both of these cases:

if (checkLocationPermission(this)){

In this first one, the program automatically recognizes "this" as an Activity object. Here's the second one:

@Override
            public void onSuccess(Location location) {
                if (location == null || !checkLocationPermission(this)){

In this case the exact same method recognizes "this" as an OnSuccessListener instead of an Activity. Another example I have in the same program is one where "this" object is supposed to be a Looper but instead it again gets recognized as an OnSuccessListener:

fusedLocationClient.requestLocationUpdates(locationRequest,new LocationCallback(),this);

I don't know how to actually select the proper type of object for "this" argument since I can only type the same damn word.


EDIT:

Here's the full code. I used Looper.this just so you can find it easier. I also tried with MapsActivity.this and it doesn't work:

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

private GoogleMap mMap;
private GoogleApiClient googleApiClient;
public static final String TAG = MapsActivity.class.getSimpleName();
private FusedLocationProviderClient fusedLocationClient;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; //Request code to send to Google Play Services
private LocationRequest locationRequest;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    setUpMapIfNeeded();
    googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
    locationRequest = LocationRequest.create().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(10*1000).setFastestInterval(1*1000);
}

private void setUpMapIfNeeded(){
    if (mMap==null){
        SupportMapFragment mapFragment = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
        mapFragment.getMapAsync(this);
    }
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
    //setUpMap();

    // Add a marker in Sydney and move the camera
    LatLng sydney = new LatLng(-34, 151);
    mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
    mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}

@Override
public void onConnected(Bundle bundle) {
    Log.i(TAG,"Location Services Connected");
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    if (checkLocationPermission(this)){
        fusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
            @Override
            public void onSuccess(Location location) {
                if (location == null || !checkLocationPermission(MapsActivity.this)){
                    fusedLocationClient.requestLocationUpdates(locationRequest,new LocationCallback(),Looper.this);
                }
                else{
                    handleNewLocation(location);
                }
            }
        });
    }

}
public static boolean checkLocationPermission(Activity activity){
    if(ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED
            || ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_COARSE_LOCATION)
            != PackageManager.PERMISSION_GRANTED){

        ActivityCompat.requestPermissions(activity, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION,
                android.Manifest.permission.ACCESS_COARSE_LOCATION},0);
        return false;
    }
    return true;
}

private void handleNewLocation(Location location){
    Log.d(TAG,location.toString());
}

@Override
public void onConnectionSuspended(int i) {
    Log.i(TAG,"Location Services suspended. Please reconnect.");
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    if (connectionResult.hasResolution()){
        //Starts an Activity that tries to resolve the error
        try {
            connectionResult.startResolutionForResult(this,CONNECTION_FAILURE_RESOLUTION_REQUEST);
        } catch (IntentSender.SendIntentException e) {
            e.printStackTrace();
        }
    }
    else{
        Log.i(TAG,"Location services connection failed code: " + connectionResult.getErrorCode());
    }
}

@Override
protected void onResume(){
    super.onResume();
    setUpMapIfNeeded();
    googleApiClient.connect();
}

@Override
protected void onPause(){
    super.onPause();
    if (googleApiClient.isConnected()){
        googleApiClient.disconnect();
    }
}

@Override
public void onLocationChanged(Location location) {
    handleNewLocation(location);
}
}
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Lepotec
  • 13
  • 6

3 Answers3

0

this corresponds to the object in which it is used. onSuccess is a method of OnSuccessListener class and hence this refers to OnSuccessListener. You need to use ActivityName.this. For example if you activity name is MainActivity, then

@Override
public void onSuccess(Location location) {
    if (location == null || !checkLocationPermission(MainActivity.this)){
nupadhyaya
  • 1,909
  • 1
  • 14
  • 14
  • I tried using Activity.this but it says "android.app.Activity" is not an enclosing class.. :/ – Lepotec Oct 07 '18 at 18:20
  • Not Activity.this, YourActivityName.this. (YouActivityName is "your activity name", whatever that is) – nupadhyaya Oct 07 '18 at 18:23
  • Which activity do you have your onSuccess in? – nupadhyaya Oct 07 '18 at 18:24
  • I'm using the onSuccess method inside the method:public void onConnected(Bundle bundle) – Lepotec Oct 07 '18 at 18:28
  • No i meant what is the Activity name? – nupadhyaya Oct 07 '18 at 18:28
  • Sorry I'm a beginner in Android Studio.. If you mean the class in which I'm using these methods, it's called MapsActvity – Lepotec Oct 07 '18 at 18:31
  • Yes., So you need to use MapsActivity.this – nupadhyaya Oct 07 '18 at 18:31
  • This works for the Activity case but still doesn't work for the Looper object – Lepotec Oct 07 '18 at 18:32
  • Can you post the complete Looper code – nupadhyaya Oct 07 '18 at 18:33
  • Sure. I used the Looper.this just so you can find it. I tried with MapsActivity.this aswell @Override public void onSuccess(Location location) { if (location == null || !checkLocationPermission(MapsActivity.this)){ fusedLocationClient.requestLocationUpdates(locationRequest,new LocationCallback(),Looper.this); } else{ handleNewLocation(location); } } – Lepotec Oct 07 '18 at 18:35
  • Sorry about the messy paste.. I'll try editing the question – Lepotec Oct 07 '18 at 18:35
  • Post it as edit in your question. Post the complete code, including the part where you create and use the Looper object – nupadhyaya Oct 07 '18 at 18:37
  • I posted it as an edit. I only use the Looper object in that one instance where "this" is present. I didn't try to create it anywhere else. – Lepotec Oct 07 '18 at 18:38
  • i don't see the looper in your code.. Post the complete code.. A little extra code doesn't hurt anyone (unless you have copyrighted code which i doubt) – nupadhyaya Oct 07 '18 at 18:40
  • I actually did add an edit.. I edited it again this time by making the text bold. You should definitely see it now. If not I can even screenshot it – Lepotec Oct 07 '18 at 18:43
  • No i meant more code. What is outside onSuccess? You might as well post you complete activity – nupadhyaya Oct 07 '18 at 18:44
  • Oh right.. sorry. The method is inside another method called onConnected. I updated the code. Again sorry for the misunderstanding. – Lepotec Oct 07 '18 at 18:48
  • Where is you looper? – nupadhyaya Oct 07 '18 at 18:49
  • You can use MyLooper.this only if your code is inside the Looper class.. Post your complete class so that i get an idea of what you are doing – nupadhyaya Oct 07 '18 at 18:49
  • I posted the entire code. I hope you will be able to understand everything now. – Lepotec Oct 07 '18 at 18:56
  • Ok i get what you are trying to do. Just beacause `requestLocationUpdates` expects a looper as third parameter doesn't mean you pass `Looper.this`. The third parameter is required only if you are using a `Looper`. In your case you are not, so pass null. `fusedLocationClient.requestLocationUpdates(locationRequest,new LocationCallback(),null);` – nupadhyaya Oct 07 '18 at 18:59
  • Oh wow. Thank you so much! :) – Lepotec Oct 07 '18 at 19:00
0

When you use an anonymous inner class, such as a listener, and use this, it refers to the anonymous inner class, because that's your current location.

For instance, with an OnClickListener:

view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //"this" here will refer to the OnClickListener instance you create
    }
}

Nothing is being "created" with a this argument. It's a direct reference to the current enclosing class. If you need to reference the Activity, you can use:

ActivityClassName.this

as long as you're in an inner class and not a static class.

If you use a lambda (only available for API 24+):

view.setOnClickListener((v) -> {
    //"this" will reference your Activity because there's no inner class anymore
}
TheWanderer
  • 16,775
  • 6
  • 49
  • 63
  • The class I'm using is only declared public, not static. I tried passing Activity.this as an argument but it says "android.app.Activity" is not an enclosing class.. :/ – Lepotec Oct 07 '18 at 18:23
  • No, you need to use the exact name of the class that encloses it. If it's MainActivity, then you use MainActivity.this. – TheWanderer Oct 07 '18 at 18:31
0

the this refers to the object of the immediate enclosing class. So, if you have some interface or class as an argument to a function, we usually do like this :

functionThatTakesInterfaceOrClassAsArgument( new TheInterfaceOrClass {
    @Override
    public void someMethod () {
        // if you use `this` here, it refers to the object of `TheInterfaceOrClass`
    }

});

If you want to use the object corresponding to an enclosing class (yet not the immediate enclosing class) using <className>.this

So, if the name of the enclosing Activity is MyActivity, one would need to use MyActivity.this.

zeekhuge
  • 1,594
  • 1
  • 13
  • 23
  • I tried passing Activity.this as an argument but it says "android.app.Activity" is not an enclosing class... :/ – Lepotec Oct 07 '18 at 18:25
  • it has to be the name of the class. not `Activity.this`. Read the last line of the answer. – zeekhuge Oct 07 '18 at 18:26