0

I'm working on an app that finds user's position and locates near access points and signal area.

When I'm manually requesting location updates via button it just doesn't calls the callback function.

This is my activity:

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener, OnMapReadyCallback, LocationListener{

//LOG tag
private static final String LOG = MainActivity.class.getSimpleName();
private static final String DEBUG = "Debugging MainActivity:";
private static final String TEST = "Test";
private static final float ZOOM_LEVEL = 15.5f;
//The map
private GoogleMap mGmap;
private LocationManager mLocationManager;
private Location mLocation;
private WifiManager mWifiManager;
private BroadcastReceiver mBroadcastReceiver;
private List<ScanResult> mResultList;
private String mProvider;
private Criteria mCriteria;
//Controller
private AccessPointController mController;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //Toolbar
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.setDrawerListener(toggle);
    toggle.syncState();

    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);

    mController = new AccessPointController();

    startReceivingLocationUpdates();
    mCriteria = new Criteria();
    mCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
    mCriteria.setPowerRequirement(Criteria.POWER_MEDIUM);
    mProvider = mLocationManager.getBestProvider(mCriteria, false);
    Log.i(DEBUG, mProvider);
    mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context c, Intent intent) {
            if(intent.getAction() == WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) {
                mResultList = mWifiManager.getScanResults();
                mController.setApList(mResultList);
            }
        }
    };

    mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    registerReceiver(mBroadcastReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
    mWifiManager.startScan();

    //Map handling
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

private void startReceivingLocationUpdates() {
    if(mLocationManager == null) {
        mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    }
}

@Override
public void onLocationChanged(Location location) {
    Log.i(DEBUG, "onLocationChanged");
    mLocation = new Location(location);
    mController.setCurrentPosition(mLocation);
    Log.i(DEBUG, "setted new position");
    mController.showOnMap(mGmap);
    mGmap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(mLocation.getLatitude(), mLocation.getLongitude()), ZOOM_LEVEL));
}

@Override
protected void onResume() {
    super.onResume();
    try {
        mLocationManager.requestSingleUpdate(mProvider, this, null);
    } catch(SecurityException e) {
        System.out.println("OnResume Error: " + e.getMessage());
    }
}

@Override
protected void onPause() {
    super.onPause();
    mLocationManager.removeUpdates(this);
}

@Override
public void onMapReady(GoogleMap googleMap) {
    Log.i(DEBUG, "onMapReady");
    mGmap = googleMap;
    try {
        mLocation = mLocationManager.getLastKnownLocation(mProvider);
        mController.setCurrentPosition(mLocation);
    } catch(SecurityException e) {
        e.printStackTrace();
    }
    mGmap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(mLocation.getLatitude(), mLocation.getLongitude()), ZOOM_LEVEL));
}

@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
    // Handle navigation view item clicks here.
    int id = item.getItemId();

    if (id == R.id.nav_explore) {
        try {
            if(mLocationManager != null) {
                try {
                    Log.i(DEBUG, "manual update request");
                    mLocationManager.requestSingleUpdate(mProvider, this, null);
                } catch (SecurityException e) {
                    Toast.makeText(this, "Failed to request location updates, ignore: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                } catch (IllegalArgumentException e) {
                    Toast.makeText(this, "Provider does not exist: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                }
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    } else if (id == R.id.nav_open_networks) {
        Toast.makeText(this, "Open network pressed", Toast.LENGTH_SHORT).show();

    } else if (id == R.id.nav_closed_networks) {
        Toast.makeText(this, "Closed network pressed", Toast.LENGTH_SHORT).show();
    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}

}

Basically when the user presses the explore button the app should locate the user and show him on the map.

Here is the logcat:

/Debugging MainActivity:: network

/Debugging MainActivity:: onMapReady

/Debugging controller:: set position

/Debugging MainActivity:: manual update request

and the /Debugging MainActivity:: onLocationChanged never shows up.

I tried also to use a variable as a LocationListener, it does not work. And yes, my permissions in the manifest are fine.

I really don't understand what I'm doing wrong.

  • Looks to me like you use the 'old' approach and not fused location updates. Not that it shouldn't work still, but can you give this library a try: https://github.com/mcharmas/Android-ReactiveLocation ? Also if your targetSdk is greater than 23, you need to setup runtime permissions – cYrixmorten Jul 10 '17 at 23:19
  • There are great libraries for that as well, just fyi :) – cYrixmorten Jul 10 '17 at 23:31
  • Yes I've forgot to mention I have a "splash_activity" that requests the permissions. I'll try to use the fusedLocation, since it's for a school exam and I need to explain in theory what happens in my code. Thanks for the advice – Luca Effe Federzoni Jul 11 '17 at 00:20
  • [Solved] Thanks for the advice, using FusedLocation I solved the problem, moving the "populate map" job to the "onConnected()" method instead of the onMapReady, so that the app waits for the connection before doing anything. That was why it kept crashing. – Luca Effe Federzoni Jul 11 '17 at 14:52
  • Super :) happy coding – cYrixmorten Jul 11 '17 at 15:09

1 Answers1

0

Since the map was loaded asynchronously, asking to do stuff in the onMapReady() method was too early.

Replacing the LocationManager approach with the FusedLocation approach allows me to wait until a connection is established and then calculate.