FusedLocationApi后台位置服务停止随机接收更新

时间:2015-12-15 01:52:12

标签: android background-service location-services fusedlocationproviderapi android-fusedlocation

我试图使用具有待定意图的FusedLocationApi来获取期间位置更新,以便我可以将数据发送到某个服务器进行处理。一切正常。但是,有些情况下广播才停止接收。我需要再次重启服务才能继续。

我已经有服务onStartCommand返回START_STICKY所以即使应用程序被杀死它也应该再次启动服务。此外,我还添加了一个Boot Completed Intent Receiver,因此如果手机死机并且用户重新启动手机,它将重启我的服务。

所以似乎一切都很好并且正常工作,但在某些时候,一切都停止了。我确实注意到,当它停止工作时,我收到的最后一个位置是NULL(我在整个项目中记录每个位置更新和错误消息)。

任何有关定位服务停止工作的想法?

P.S。没有连接失败,因为我把一个消息和钩子放到该函数中并且它没有被调用。并且它也不是因特网故障,因为我也记录了它。一旦互联网恢复,它将继续正常/预期。

感谢。

这是主要活动:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ActionBar actionBar = getSupportActionBar();

    if (actionBar != null) {
        actionBar.setDisplayShowHomeEnabled(false);
        actionBar.setDisplayShowTitleEnabled(false);
        if (findViewById(android.R.id.home) != null) {
            findViewById(android.R.id.home).setVisibility(View.GONE);
        }

        LayoutInflater inflator = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflator.inflate(R.layout.header_logo, null);

        ActionBar.LayoutParams params = new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
        actionBar.setDisplayShowCustomEnabled(true);
        actionBar.setCustomView(view, params);
    }

    setContentView(R.layout.activity_main);

    TextView textView = (TextView) findViewById(R.id.status_text);

    // init preferences and status handler
    MyStatusHandler.init(getApplicationContext(), textView);

    // init web service call class
    ...;

    // check for location services
    if (!isLocationEnabled(getApplicationContext())){
        String msg = "Location services not turned on";
        MyStatusHandler.setStatusText(msg);
    }
}

public static boolean isLocationEnabled(Context context) {
    int locationMode = 0;
    String locationProviders;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
        try {
            locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);

        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }

        return locationMode != Settings.Secure.LOCATION_MODE_OFF;

    }else{
        locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
        return !TextUtils.isEmpty(locationProviders);
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        // create new intent activity for the settings page
        Intent i = new Intent(this, MySettingsActivity.class);
        startActivity(i);
        return true;
    }
    else if (id == R.id.action_about){
        // 1. Instantiate an AlertDialog.Builder with its constructor
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        // 2. Chain together various setter methods to set the dialog characteristics
        if (Constants.DEBUG_BUILD == true) {
            builder.setMessage("v." + MyStatusHandler.getReleaseVersionNum() + " dev Build: " + MyStatusHandler.getDevVersionNum())
                    .setTitle("About")
                    .setCancelable(false)
                    .setPositiveButton("OK", null);
        }
        else{
            builder.setMessage("v." + MyStatusHandler.getReleaseVersionNum())
                    .setTitle("About")
                    .setCancelable(false)
                    .setPositiveButton("OK", null);
        }

        // 3. Get the AlertDialog from create()
        AlertDialog dialog = builder.create();

        // show it
        dialog.show();

        return true;
    }

    return super.onOptionsItemSelected(item);
}

// check email entered
public boolean isSettingsEntered(){
    boolean result = true;

    if (MyStatusHandler.getEmailText().equals("") || MyStatusHandler.getPasswordText().equals("")){
        // 1. Instantiate an AlertDialog.Builder with its constructor
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        // 2. Chain together various setter methods to set the dialog characteristics
        builder.setMessage("Please ensure both email and password are entered in settings")
                .setTitle("Email and/or Password not set")
                .setCancelable(false)
                .setPositiveButton("OK",null);

        // 3. Get the AlertDialog from create()
        AlertDialog dialog = builder.create();

        // show it
        dialog.show();

        result = false;
    }

    return result;
}

/** Called when the user clicks the Opt in button */
public void startService(View view) {
    // Do something in response to button

    if (isSettingsEntered() && isLocationEnabled(getApplicationContext())) {
        // send opt in to web service
        ...;
        // start service
        startService(new Intent(this, BackgroundLocationService.class));

        // update status text
        String msg = "Connecting ...";
        MyStatusHandler.setStatusText(msg);
    }
}

/** Called when the user clicks the Opt out button */
public void stopService(View view) {
    // Do something in response to button

    if (isSettingsEntered() && isLocationEnabled(getApplicationContext())) {
        // send OptOut to web service
        ...;

        // update status text
        String msg = "Connecting ...";
        MyStatusHandler.setStatusText(msg);
    }
}

public static void ...(boolean isOptIn, Location location, boolean sendOptIn){
    if (sendOptIn)
    {
        // send opt in via async task
    }
    else{
       // send location via async task
    }
}

// Handle results returned to the FragmentActivity by Google Play services
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Decide what to do based on the original request code
    switch (requestCode) {
        case Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST :
            // log the error
            MyStatusHandler.logDataToFile("Connection Failure Resolution Request - Result Code: "+String.valueOf(resultCode));
            // If the result code is Activity.RESULT_OK, try to connect again
            switch (resultCode) {
                case Activity.RESULT_OK :
                    // Try the request again
                    MyStatusHandler.logDataToFile("Attempting to re-start service");
                    // start service
                    startService(new Intent(this, BackgroundLocationService.class));
                    break;
            }
    }
}
}

以下是后台服务:

public class BackgroundLocationService extends Service implements
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener,
    LocationListener {

public static final String TAG = BackgroundLocationService.class.getSimpleName();

private GoogleApiClient mGoogleApiClient;
private boolean mInProgress;

private LocationRequest mLocationRequest;

public void onCreate(){
    super.onCreate();

    mGoogleApiClient = new GoogleApiClient.Builder(this)
         .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
}

@Override
public int onStartCommand (Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    if(mGoogleApiClient.isConnected() || mInProgress)
        return START_STICKY;


    if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) {
        mInProgress = true;
        mGoogleApiClient.connect();
    }

    return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
}

@Override
public void onConnected(Bundle bundle) {
    mLocationRequest = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
            .setFastestInterval(Constants.FASTEST_INTERVAL)
            .setInterval(Constants.UPDATE_INTERVAL);

    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
            new Intent(this, MyLocationHandler.class),
            PendingIntent.FLAG_CANCEL_CURRENT);

    if (mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, pendingIntent);
    }
    else{
        MyStatusHandler.setStatusText("Google Client Failed");
    }
}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onLocationChanged(Location location) {

}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    mInProgress = false;

    if (connectionResult.hasResolution()) {
        try {
            // Start an Activity that tries to resolve the error
            connectionResult.startResolutionForResult(null, Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST);

            // * Thrown if Google Play services canceled the original
            // * PendingIntent

        } catch (IntentSender.SendIntentException e) {
            // Log the error
            e.printStackTrace();
        }
    } else {

        //* If no resolution is available, display a dialog to the
        // * user with the error.

        Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
        MyStatusHandler.setStatusText("Location services connection failed with code " + connectionResult.getErrorCode());
    }
}

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

这是广播接收器:

public class MyLocationHandler extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);

    if (location != null && MyStatusHandler.getOptInStatus()) {
        // debug messages
        String msg = Double.toString(location.getLatitude()) + "," +
                Double.toString(location.getLongitude());
        Log.d("debug", msg);

        // log location to file
        MyStatusHandler.logDataToFile("Location: "+msg);

        // send Location to web service
        MainActivity....(MyStatusHandler.getOptInStatus(), location, false);
    }

    if (location == null){
        MyStatusHandler.logDataToFile("Location == NULL!");
    }
}
}

我将间隔设置为5分钟,将快速间隔设置为2分钟。 注意:我删除了一些函数调用和Web服务操作的代码

一切正常,我得到了预期的更新,但在某个时间点,广播接收器没有得到任何东西。当我检查日志时,OptInStatus不会改变,我收到的最后一个广播位置是NULL。

我的代码中用于调用Web服务和处理状态消息的其他部分不会触及服务或位置请求。

0 个答案:

没有答案
相关问题