具有PendingIntent的FusedLocationApi仅触发一次,并且其null [英] FusedLocationApi with PendingIntent is fired only once and its null

查看:76
本文介绍了具有PendingIntent的FusedLocationApi仅触发一次,并且其null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正在处理需要经常更新位置的应用程序,即使该应用程序在后台也是如此.按照文档

Am working on an app that needs location update frequently even when its in the background. Following the documentation here, am working with pending intent not locationlistener. My code is below

/**
 * Created by philip on 7/30/16.
 */
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;

    public static final long UPDATE_INTERVAL_IN_MILLISECONDS =  1000 * 30; //1 minute;
    /**
     * The fastest rate for active location updates. Exact. Updates will never be more frequent
     * than this value.
     */
    public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
            UPDATE_INTERVAL_IN_MILLISECONDS / 2;

    private String mLastUpdateTime;
    private Location mCurrentLocation;

    private GeoFire mGeoFire = null;
    private String uuid = null;
    private Intent intentService;
    private PendingIntent mPendingIntent;

    @Override
    public void onCreate() {
        super.onCreate();
        Firebase.setAndroidContext(this);
        buildGoogleApiClient();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (!mGoogleApiClient.isConnected()) {
            mGoogleApiClient.connect();
        }
        createLocationRequest();
        if(intent != null){
            intentService = new Intent(this, LocationBroadcastReceiver.class);
            intentService.putExtra("UUID", intent.getStringExtra("UUID"));
            intentService.setAction("foo.LOCATION_UPDATE_INTENT");
            mPendingIntent = PendingIntent.getBroadcast(this, 0, intentService, PendingIntent.FLAG_UPDATE_CURRENT);
        }
        return START_REDELIVER_INTENT;
    }

    /********************************************** Google api connection callback below **************************************/

    /***
     * callback fired once connection has been established
     * @param bundle
     */
    @Override
    public void onConnected(Bundle bundle) {
        startLocationUpdates();
        Log.i(this.getClass().getSimpleName(), "Location Service api has been connected");
    }


    /***
     * callback fired when connection fails
     * @param connectionResult
     */
    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.i(this.getClass().getSimpleName(), "Location Service disconnected");
    }


    /**
     * callback fired when connection is temporary suspended
     * @param i
     */
    @Override
    public void onConnectionSuspended(int i) {
        if (mGoogleApiClient != null) {
            mGoogleApiClient.connect();
        }
    }

    /************************************** Ease methods ************************************************/

    /**
     * Builds a GoogleApiClient. Uses the {@code #addApi} method to request the
     * LocationServices API.
     */
    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(API)
                .build();
    }

    /**
     * Requests location updates from the FusedLocationApi.
     */
    protected void startLocationUpdates() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            return;
        }
        FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
    }

    protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();

        // Sets the desired interval for active location updates. This interval is
        // inexact. You may not receive updates at all if no location sources are available, or
        // you may receive them slower than requested. You may also receive updates faster than
        // requested if other applications are requesting location at a faster interval.
        mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);

        // Sets the fastest rate for active location updates. This interval is exact, and your
        // application will never receive updates faster than this value.
        mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);

        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }


}

和我的广播接收器

@Override
    public void onReceive(Context context, Intent intent) {
        Firebase.setAndroidContext(context);
        Log.i(getClass().getSimpleName(), "broadcast has been called");

        if (intent != null) {
            String uuid = intent.getStringExtra("UUID");
            mGeoFire = new GeoFire(new Firebase("https://foo.firebaseio.com/users/" + uuid));

            LocationResult locationResult = LocationResult.extractResult(intent);

            if(locationResult == null){// check for null pointer
                Log.i(getClass().getSimpleName(), "location result is null <<<<<<<<<<<<<<<<<<");
                return;
            }

            Log.i(getClass().getSimpleName(), "location result found >>>>>>>>>>>>>>>>>>>>====>>>>>>>>>>>>>>>>>>>");

            location = locationResult.getLastLocation();
        }

        if( isBetterLocation(location, currentBestLocation)){
            currentBestLocation = location;
        }else {
            return;
        }

        if (mGeoFire != null) {
            mGeoFire.setLocation("location", new GeoLocation(location.getLatitude(), location.getLongitude()));
        }
    }

我面临的问题是

  1. 我的广播只有一次,
  2. 当我确实收到意图时,LocationResult locationResult = LocationResult.extractResult(intent);返回null
  1. My broadcast is only ever called once,
  2. When i do receive the intent, LocationResult locationResult = LocationResult.extractResult(intent); returns null

那是我的广播接收器中听到的最后一个

and that is the last i hear from my broadcast reveiver

推荐答案

我基本上将侦听器移到了onConnected并检查了null.从那以后,它运行良好.

I basically moved my listener to onConnected and checked for null. It worked fine after then.

package com.github.robophil.location_service;

import android.Manifest;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.widget.Toast;

import com.firebase.client.Firebase;
import com.firebase.geofire.GeoFire;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;

import static com.google.android.gms.location.LocationServices.API;
import static com.google.android.gms.location.LocationServices.FusedLocationApi;

/**
 * Created by philip on 7/30/16.
 */
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;

    public static final String prefName = "com.github.robophil.pref";

    public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000 * 60; //1 minute;
    /**
     * The fastest rate for active location updates. Exact. Updates will never be more frequent
     * than this value.
     */
    public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
            UPDATE_INTERVAL_IN_MILLISECONDS / 2;

    private String mLastUpdateTime;
    private Location mCurrentLocation;

    private GeoFire mGeoFire = null;
    private String uuid = null;
    private Intent intentService;
    private PendingIntent mPendingIntent;

    @Override
    public void onCreate() {
        super.onCreate();
        Firebase.setAndroidContext(this);
        buildGoogleApiClient();
    }

    @Override
    public void onDestroy() {
        if(mGoogleApiClient != null){
            if(mGoogleApiClient.isConnected()){
                mGoogleApiClient.disconnect();
                FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mPendingIntent);
            }
        }
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            if(!intent.hasExtra("UUID") || !intent.hasExtra("URL")){
                Log.i(getClass().getSimpleName(), "Service has stopped itself");
                Toast.makeText(this, "stopself called", Toast.LENGTH_SHORT).show();
                stopSelf();
            }

            SharedPreferences.Editor editor = getSharedPreferences(LocationService.prefName, getApplicationContext().MODE_PRIVATE).edit();
            editor.putString("UUID", intent.getStringExtra("UUID"));
            editor.putString("URL", intent.getStringExtra("URL"));
            editor.apply();

            intentService = new Intent(this, LocationIntentService.class);
            intentService.setExtrasClassLoader(LocationResult.class.getClassLoader());
            mPendingIntent = PendingIntent.getService(getApplicationContext(), 0, intentService, PendingIntent.FLAG_UPDATE_CURRENT);
        }

        if (!mGoogleApiClient.isConnected()) {
            mGoogleApiClient.connect();
        }

        return START_REDELIVER_INTENT;
    }

    /********************************************** Google api connection callback below **************************************/

    /***
     * callback fired once connection has been established
     * @param bundle
     */
    @Override
    public void onConnected(Bundle bundle) {
        createLocationRequest();
        startLocationUpdates();
        Log.i(this.getClass().getSimpleName(), "Location Service api has been connected");
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            return;
        }
        Location location = FusedLocationApi.getLastLocation(mGoogleApiClient);
        if (location == null){
            Log.i(getClass().getSimpleName(), "init location is null");
            return;
        }
        Log.i(getClass().getSimpleName(), "init location ==> "+location.getAccuracy()+" "+location.getProvider());
    }


    /***
     * callback fired when connection fails
     * @param connectionResult
     */
    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.i(this.getClass().getSimpleName(), "Location Service disconnected");
    }


    /**
     * callback fired when connection is temporary suspended
     * @param i
     */
    @Override
    public void onConnectionSuspended(int i) {
        if (mGoogleApiClient != null) {
            mGoogleApiClient.connect();
        }
    }

    /************************************** Ease methods ************************************************/

    /**
     * Builds a GoogleApiClient. Uses the {@code #addApi} method to request the
     * LocationServices API.
     */
    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(API)
                .build();
    }

    /**
     * Requests location updates from the FusedLocationApi.
     */
    protected void startLocationUpdates() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            return;
        }
//        FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
    }

    protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();

        // Sets the desired interval for active location updates. This interval is
        // inexact. You may not receive updates at all if no location sources are available, or
        // you may receive them slower than requested. You may also receive updates faster than
        // requested if other applications are requesting location at a faster interval.
        mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);

        // Sets the fastest rate for active location updates. This interval is exact, and your
        // application will never receive updates faster than this value.
        mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);

        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }


}

用于我的待定意图的LocationsIntentService保持不变,只是在执行任何操作之前检查null

LocationsIntentService used for my pending intent stays the same, just checking for null before doing anything

package com.github.robophil.location_service;

import android.app.IntentService;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;

import com.firebase.client.Firebase;
import com.firebase.geofire.GeoFire;
import com.firebase.geofire.GeoLocation;
import com.google.android.gms.location.LocationResult;

import java.util.Set;

/**
 * Created by philip on 8/7/16.
 */
public class LocationIntentService extends IntentService {
    private GeoFire mGeoFire;
    private Location location, currentBestLocation;

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public LocationIntentService(String name) {
        super("i am a value");
    }

    public LocationIntentService(){
        super("i am a value");
    }



    @Override
    protected void onHandleIntent(Intent intent) {
        Firebase.setAndroidContext(this);
        Log.i(getClass().getSimpleName(), "intent service has been called");

        SharedPreferences pref = getSharedPreferences(LocationService.prefName, getApplicationContext().MODE_PRIVATE);
        String uuid = pref.getString("UUID", null);
        String url = pref.getString("URL", null);

        if(uuid == null || url==null){
            stopSelf();
            return;
        }

        if (intent != null) {

            mGeoFire = new GeoFire(new Firebase(url +"/"+ uuid));
            Log.i(getClass().getSimpleName(), "user id found ==> "+uuid+", "+url);

            Bundle extra = intent.getExtras();
            Set<String> extraKeySet = extra.keySet();
            for(String key: extraKeySet){
                Log.i(getClass().getSimpleName(), "key found ==> "+ key);
            }

            if(LocationResult.hasResult(intent)){
                Log.i(getClass().getSimpleName(), "intent contains location");
            }

            LocationResult locationResult = LocationResult.extractResult(intent);

            if(locationResult == null){// check for null pointer
                Log.i(getClass().getSimpleName(), "location result is null ...");
                return;
            }

            Log.i(getClass().getSimpleName(), "location result found");

            location = locationResult.getLastLocation();
        }

        if( isBetterLocation(location, currentBestLocation)){
            currentBestLocation = location;
        }else {
            return;
        }

        if (mGeoFire != null) {
            mGeoFire.setLocation("location", new GeoLocation(location.getLatitude(), location.getLongitude()));
        }
    }

    private static final int TWO_MINUTES = 1000 * 60 * 2;

    /** Determines whether one Location reading is better than the current Location fix
     * @param location  The new Location that you want to evaluate
     * @param currentBestLocation  The current Location fix, to which you want to compare the new one
     */
    protected boolean isBetterLocation(Location location, Location currentBestLocation) {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return true;
        }

        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
        boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
        boolean isNewer = timeDelta > 0;

        // If it's been more than two minutes since the current location, use the new location
        // because the user has likely moved
        if (isSignificantlyNewer) {
            return true;
            // If the new location is more than two minutes older, it must be worse
        } else if (isSignificantlyOlder) {
            return false;
        }

        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;

        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                currentBestLocation.getProvider());

        // Determine location quality using a combination of timeliness and accuracy
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }

    /** Checks whether two providers are the same */
    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
            return provider2 == null;
        }
        return provider1.equals(provider2);
    }
}

这篇关于具有PendingIntent的FusedLocationApi仅触发一次,并且其null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆