6

保留中の意図で FusedLocationApi を使用して、期間の場所の更新を取得しようとしているので、処理のためにデータをサーバーに送信できます。すべてが機能します。ただし、ブロードキャストの受信が停止する場合があります。サービスを続行するには、サービスを再起動する必要があります。

START_STICKY を返すサービス onStartCommand が既にあるため、アプリが強制終了された場合でも、サービスを再度開始する必要があります。さらに、Boot Completed Intent Receiver も追加したので、電話が故障してユーザーが電話を再起動した場合、サービスが再起動されます。

したがって、すべてが正常に機能しているように見えますが、ある時点ですべてが停止します。動作を停止すると、最後に受け取った場所が NULL であることに何度か気付きました (プロジェクト全体ですべての場所の更新とエラー メッセージをログに記録します)。

位置情報サービスが機能しなくなる理由はありますか?

PSメッセージを入れてその関数にフックし、呼び出されていないため、接続障害はありません。また、私もそれを記録しているので、それはインターネットの障害ではありません。インターネットが復元されると、通常/期待どおりに続行されます。

ありがとう。

主な活動は次のとおりです。

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 サービスを呼び出してステータス メッセージを処理するコードの他の部分は、サービスや位置情報の要求には触れていません。

4

0 に答える 0