简体   繁体   中英

Android service communicating with multiple fragments

I have an application that has a single activity that hosts several fragments in a sort of custom navigation drawer design. Two of these fragments depend on a service to return them json information to display. I want to be able to start the service on my splash screen to load the data I need then asynchronously communicate the json to these fragments.

I am new to android and programming in general so excuse me if my actions were ill informed but I first tried to register the fragments as receivers and then simply broadcast intents containing the json information in a bundle. This seemed to not work because sometimes the fragments would not be running when the service would broadcast the intent and miss the intent.

Then I decided to go with sticky intents but this resulted in stale information not to mention the inherit security concern.

What is the best way to have a service perform a background network request upon launching the app and then display the returned information later by any activity or fragment?

Believe me, I tried a lot of third party approaches (service buses, observes, ...) in large enterprise projects and it turned out the native Android mechanisms are the fastest and robust ones, since they take advantage of the framework's benefits.

Thats why I would recommend the usage of LocalBroadcastManager along with BroadcastReceiver. In your activity (or your can event do this per fragment! ) register in onStart and unregister in onPause a dedicated Receiver.

Use the LocalBroadcastManager in your service to communicate to all potential subscribers.

Example:

 public class YourActivity extends Activity{

        private BroadcastReceiver receiver = new BroadcastReceiver(){

        @Override
        public void onReceive(Context context, Intent intent) {
            //...do the stuff you need to do depending on the received broadcas

        }

};

  private IntentFilter filter = new IntentFilter(UploadService.INTENT_ACTION_UPLOAD);

  protected onStart(){
      LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
  }

  protected onPause(){
      LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
  }
}

public class UploadService extends IntentService{
   public static final String INTENT_ACTION_UPLOAD = "com.your.package.INTENT_ACTION_UPLOAD";

   public onHandleIntent(){
      //upload
      LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(INTENT_ACTION_UPLOAD));
   }
}

In the BroadcastReceiver's onReceive you can then do the stuff you need to do depending on the received broadcast. If you need to differentiate more, you can use different actions or extras, for instance in your service:

...send(new Intent(INTENT_ACTION_SOMETHING_ELSE));

or

send(new Intent(...).putExtra(WAS_SUCCESSFUL, false));
send(new Intent(...).putExtra(DOWNLOADED_CONTENT, downloadedStuff);

You could call startService() not only from your splash screen, but from your fragments: getActivity().startService() .

Derive your service from Service (not from IntentService). In the onStartCommand() it will read data from network, then broadcast the result. If result already loaded, service could simply broadcast the result.

When you call startService() from your splashscreen, service loads data from network and broadcast it to fragments that are shown at the moment. When new fragment created, it calls startService() again and service broadcasts cached data.

Another approach is bindService . Your fragment could bind to service on onCreate() and unbind from it on onDestroy() . In this case fragment could call service's methods directly.

使用事件总线而不是广播意图,如绿色机器人EventBus (也支持粘性广播)

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