3

UPDATE (1 Nov, 2017): I was able to reproduce the error in an MCV example linked herein: locationServiceMCV github repo

It seems that the location is retrieved only when I navigate to the activity the second time. So, I'm guessing that the issue has something to do with lifecycles?

I have a service that gets the user's location and broadcasts the latitude and longitude in an intent:

Service

@Override
public void onConnected(@Nullable Bundle bundle) {
    Log.d("personal", "got into onConnected");

    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);
    }
}

private void handleNewLocation(Location location) {
    Log.d("personal", "got to handleNewLocation");
    currentLatitude = location.getLatitude();
    currentLongitude = location.getLongitude();
    Log.d("personal", "lat from handleNewLocation is " + currentLatitude.toString());
    Log.d("personal", "long from handleNewLocation is " + currentLongitude.toString());
    if (currentLatitude != null && currentLongitude != null) {
        setUpGeoFire();
        sendToActivity(currentLatitude, currentLongitude);
    }
}

public void sendToActivity(Double currentLatitude, Double currentLongitude){
    Log.d("personal", "got to sendToActivity");
    Intent intent = new Intent("locationServiceUpdates");
    intent.putExtra("ServiceLatitudeUpdate", currentLatitude.toString());
    intent.putExtra("ServiceLongitudeUpdate", currentLongitude.toString());
    if(serviceContext != null){
        LocalBroadcastManager.getInstance(serviceContext).sendBroadcast(intent);
        Log.d("personal", "broadcast launched from the location service");
        Toast.makeText(this, "broadcast launched from the location service", Toast.LENGTH_SHORT).show();
    } else{
        Log.d("personal", "didn't broadcast the location updates because serviceContext is null");
    }
}

I've successfully registered a BroadcastReceiver in my mainActivity, which gets the location information just fine:

Main Activity

//Start location service//
    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;
    }
    startLocationService();
    BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // Get extra data included in the Intent
            currenLatitude = Double.parseDouble(intent.getStringExtra("ServiceLatitudeUpdate"));
            currentLongitude = Double.parseDouble(intent.getStringExtra("ServiceLongitudeUpdate"));
            Log.d("personal", "onReceive of broadcast receiver reached");
            Log.d("personal", "onReceive lat is " + currenLatitude.toString());
            Log.d("personal", "onReceive long is " + currentLongitude.toString());
            ArrayList<String> children = new ArrayList<>();
            children.add(userId + "_current");
            setUpFirebaseAdapter(children);
        }
    };
    IntentFilter intentFilter = new IntentFilter("locationServiceUpdates");
    LocalBroadcastManager.getInstance(MainActivity.this).registerReceiver(mMessageReceiver, intentFilter);

I have another activity, NewSwarmReportActivity, that also needs to receive the location broadcast. I'm hoping to keep the service active in the background even when the app gets closed, so this is what it looks like in the manifest:

manifest:

<service
        android:name=".services.LocationService"
        android:enabled="true"
        android:exported="true">
</service>

I'm not sure whether I have to start the location service again in the second activity (I'm guessing/hoping not, especially since I have no code to shut down the service in my first activity on purpose). But either way, registering a BroadcastReceiver in the NewSwarmReportActivity doesn't seem to be working:

NewSwarmReportActivity:

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

    ButterKnife.bind(this);
    ...

    getSharedPreferences();
    Log.d("personal", "newSwarm userName is " + userName);
    Log.d("personal", "newSwarm userId is " + userId);

    startLocationService(); //Don't think I should do this.
    IntentFilter intentFilter = new IntentFilter("locationServiceUpdates");

    BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // Get extra data included in the Intent
            currenLatitude = Double.parseDouble(intent.getStringExtra("ServiceLatitudeUpdate"));
            currentLongitude = Double.parseDouble(intent.getStringExtra("ServiceLongitudeUpdate"));
            Log.d("personal", "onReceive in NewSwarmReportActivity of broadcast receiver reached");
            Log.d("personal", "onReceive in NewSwarmReportActivity lat is " + currenLatitude.toString());
            Log.d("personal", "onReceive in NewSwarmReportActivity long is " + currentLongitude.toString());
            if (userId != null && userName != null && currenLatitude != 0.0 && currentLongitude != 0.0) {
                progressBar.setVisibility(View.GONE);
                reportSwarmButton.setVisibility(View.VISIBLE);
                addImageButton.setVisibility(View.VISIBLE);
            } else {
                Log.d("newSwarm", "either location or user info is null!");
            }
        }
    };
    LocalBroadcastManager.getInstance(NewSwarmReportActivity.this).registerReceiver(mMessageReceiver, intentFilter);

}

I hope you'll forgive my newness. onReceive never seems to get called in NewSwarmReportActivity. I can't quite figure out why not. Any help is much appreciated.

Here's my module's gradle file:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "fisherdynamic.locationservicemcv"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    compile 'com.google.android.gms:play-services-location:10.0.1'
}
Atticus29
  • 4,190
  • 18
  • 47
  • 84
  • When do you unregister the receiver? Unregistering is recommended during certain transitions in the activity's life cycle. See [this doc](https://developer.android.com/guide/components/broadcasts.html#context-registered_receivers). Is it possible that your activity is paused/stopped/destroyed and the receiver has been unregistered or the context is not longer valid? – Cheticamp Nov 01 '17 at 12:59
  • @Cheticamp, mMessageReceiver gets registered in the main activity, but never gets unregistered. I initially did this on purpose. Do you suppose it's leaking the receiver, and that's part of the problem? Does it make sense that the leakage would interfere with a new declaration of a broadcast receiver in the second activity? – Atticus29 Nov 01 '17 at 17:34
  • 1
    You should at least unregister the receiver in the main activity's `onDestroy()` to avoid leakage but I don't think that's your issue. I assume that you are causing your swarm activity to execute its `onCreate()` before expecting the broadcast. An [MCVE](https://stackoverflow.com/help/mcve) would speed along an answer from the community. – Cheticamp Nov 01 '17 at 17:41
  • Thanks for the advice @Cheticamp! I linked to an MCVE github repo on the bottom. – Atticus29 Nov 01 '17 at 19:27
  • Are you testing on an emulator or real device? Also, which API are you testing with? – Cheticamp Nov 01 '17 at 20:36
  • Emulator. I'm not sure what you mean by which API I'm testing with. Do you mean the GoogleApiClient? – Atticus29 Nov 01 '17 at 20:57
  • The version of Android. – Cheticamp Nov 01 '17 at 21:10
  • Ah. The emulator is a Nexus 5X API 25x86. – Atticus29 Nov 01 '17 at 21:21
  • 1
    Why are you expecting to get the broadcast in your Swarm activity? The service is started once, the location will be fetched once, and will be notified once. Afterwards, you will receive the updates only when there's a change in location. Are you moving while you are in Swarm activity? Also, you need to listen to the location updates. I don't see a location update listener in your location service. Try registering a LocationListener with your locationupdate request. – Rahul Shukla Nov 03 '17 at 18:36
  • @Rahual Shukla the problem I'm experiencing is that I need the extras in the intent sent by the broadcast in more than one activity. Is it not appropriate to register a receiver in each actvitiy? If not, how do I get the extras in both activities? And good point about listening for location updates. – Atticus29 Nov 03 '17 at 18:58
  • @Atticus29 yes, you have to register the receiver in each activity, only then you would receive the broadcasts. But only registering the receiver won't do, you need to make sure it is fired periodically or as and when required. – Rahul Shukla Nov 06 '17 at 15:33

1 Answers1

-1

Try this code to send broadcast to Activity form service,

        Intent intent = new Intent(getPackageName());
        intent.putExtra(LOCATION_UPDATED, location);
        sendBroadcast(intent);

In My Activity here is to code to receive broadcast,

private BroadcastReceiver broadcastReceiver;

registering Receiver,

broadcastReceiver = createBroadcastReceiver();
registerReceiver(broadcastReceiver, new IntentFilter(getPackageName()));


private BroadcastReceiver createBroadcastReceiver() {
        return new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {

                if (intent.hasExtra(LocationService.LOCATION_UPDATED)) {
                    //Log.e(TAG, "##--Location Updated--##");
                    Bundle b = intent.getExtras();
                    if (b != null) {
                        mCurrentLocation = (Location) b.get(LocationService.LOCATION_UPDATED);
                    }
                }

        }
     };
}
SHIDHIN TS
  • 1,557
  • 3
  • 26
  • 58