简体   繁体   中英

LocationServices.FusedLocationApi.requestLocationUpdates never calls onLocationChanged

New to Android, so apologies in advance.

I'm attempting to retrieve the user's location using a location request. I'm using SDK 25, which I believe means that I have to request permission during run time.

The emulator works as expected (ie, gathers location info) when it's running on a speedy, well-connected machine, but onLocationChanged never seems to get called when I'm using an actual device or a slower laptop on weak wifi. It's not clear to me why.

Similar posts have not yielded useful insights in my case.

I've created a simplified example that reproduces the issue here . Emulator I'm using is a Nexus5X API 25 x86 running Android 7.1.1.

My manifest file looks like:

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />


<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

My gradle file:

    apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion '25.0.3'
    defaultConfig {
        applicationId "com.epicodus.so_locationtest"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
    compile 'com.google.android.gms:play-services-maps:10.0.0'
    compile 'com.google.android.gms:play-services-location:10.0.0'
    compile 'com.google.android.gms:play-services-auth:10.0.0'
    compile 'com.google.firebase:firebase-auth:10.0.1'
    compile 'com.android.support:design:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.jakewharton:butterknife:7.0.1'
    compile 'com.google.firebase:firebase-database:10.0.1'
    compile 'com.firebaseui:firebase-ui-database:0.4.1'
    compile 'com.google.firebase:firebase-messaging:10.0.1'
    testCompile 'junit:junit:4.12'
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.squareup.okhttp3:okhttp:3.2.0'

}

And my activity (see below). The idea was to use a google map API call if location services failed. I am aware that getCityFromHttpCall is incomplete. I'd like to see whether there's something in the Location services that I can improve before investing more energy in the google map api call. I have a bunch of Log.d statements that helped me trace to the line LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); . I believe onLocationChanged is supposed to be the callback for that, but it never seems to get called.

package com.epicodus.so_locationtest;

import android.Manifest;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.support.v7.app.AppCompatActivity;
import com.epicodus.so_locationtest.Services.GeoCodingService;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.Query;

import org.json.JSONException;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity
        implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
    private static final int MY_PERMISSIONS_REQUEST_FINE_LOCATION = 111;

    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;
    private String city;
    private Query swarmReportQuery;
    private FirebaseRecyclerAdapter mFirebaseAdapter;
    private Double currenLatitude;
    private Double currentLongitude;
    private String userName;
    private String userId;
    private FirebaseAuth auth;
    private FirebaseAuth.AuthStateListener authListener;

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

        setUpBlankAdapter();

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
                .setInterval(10 * 1000)
                .setFastestInterval(1 * 1000);
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        Log.d("personal", "got into onConnected");
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_FINE_LOCATION);
            return;
        }
        Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        if (location == null) {
            Log.d("personal", "location null");
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        } else {
            Log.d("personal", "location not null");
            handleNewLocation(location);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        Log.d("personal", "got into permissionResults");
        Log.d("personal", "request code is " + Integer.toString(requestCode) );
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_FINE_LOCATION: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d("personal", "permission was granted");
                    Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
                    if (location == null) {
                        Log.d("personal", "location is null inside permission");
                        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
                    } else {
                        Log.d("personal", "about to call new location");
                        handleNewLocation(location);
                    }
                }
            }
        }
    }

    private void handleNewLocation(Location location) {
        Log.d("personal", "got to new location");
        currenLatitude = location.getLatitude();
        currentLongitude = location.getLongitude();

        Geocoder gcd = new Geocoder(MainActivity.this, Locale.getDefault());
        try {
            List<Address> addresses = gcd.getFromLocation(currenLatitude, currentLongitude, 1);
            if (addresses.size() > 0) {
                city = addresses.get(0).getLocality() + ", " + addresses.get(0).getAdminArea();

                if (currenLatitude != null && currentLongitude != null) {
                    Log.d("personal", "Got lat and long");
                    setUpFirebaseAdapter(city);
                }
            } else {
                city = "unknown";
                Log.d("personal", "couldnt' get an address from the location");
            }
        } catch (IOException e) {
            Log.d("personal", "getFromLocation didn't work");
            e.printStackTrace();
            getCityFromHttpCall();

        }

    }

    public void getCityFromHttpCall() {
        if (currenLatitude != null && currentLongitude != null) {
            final GeoCodingService geoCodingService = new GeoCodingService();
            geoCodingService.getCity(Double.toString(currenLatitude), Double.toString(currentLongitude), new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    try {
                        String jsonData = response.body().string();
                        Log.d("personal", jsonData);
                        if (response.isSuccessful()) {
                            city = GeoCodingService.processResults(jsonData);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.d("personal", "IO exception");
                        city = "all";
                    } catch (JSONException e) {
                        Log.d("personal", "JSON exception");
                        city = "all";
                    }
                    setUpFirebaseAdapter(city);
                }
            });
        }
    }


    private void setUpFirebaseAdapter(final String city) {
        Log.d("personal", "got to setUpFirebaseAdapter");
    }

    private void setUpBlankAdapter() {
        Log.d("personal", "setUpBlankAdapter done");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mFirebaseAdapter != null) {
            mFirebaseAdapter.cleanup();
        }

    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.d("personal", "Location services suspended. Please reconnect");

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        if (connectionResult.hasResolution()) {
            try {
                connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }
        } else {
            Log.d("personal", "Location services failed with code " + connectionResult.getErrorCode());
        }
    }


    @Override
    public void onStart() {
        super.onStart();
        mGoogleApiClient.connect();
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mGoogleApiClient.isConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            mGoogleApiClient.disconnect();
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.d("personal", "location changed");
        handleNewLocation(location);
    }

}

Many thanks in advance for any help, and please let me know how I can better facilitate this.

确保在未调用onLocationChanged()的那些设备上连接了GoogleApiClient(检查您的日志)。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM