web-dev-qa-db-fra.com

Comment utiliser PendingIntent pour communiquer d'un service à un client/une activité?

J'ai lu le texte suivant sur le site des développeurs Android, plus précisément dans les rubriques Framework -> Services -> Démarrer un service .

Il y est indiqué ce qui suit:

Si le service ne fournit pas également de liaison, l'intention fournie avec startService () est le seul mode de communication entre le composant d'application et le service. Toutefois, si vous souhaitez que le service renvoie un résultat, le client qui démarre le service peut créer un PendingIntent pour une diffusion (avec getBroadcast ()) et le remettre au service dans l'intention qui lance le service. Le service peut ensuite utiliser la diffusion pour fournir un résultat.

J'ai quelques questions à ce sujet:

  1. Ce texte s’applique-t-il à Services etIntentServices?
  2. Comment (de manière codifiée) cela devrait-il être réalisé à l'intérieur de la Service; Le service peut ensuite utiliser la diffusion pour fournir un résultat. et aussi où la diffusion mentionnée fournirait-elle le résultat au client/activité d'origine? Y at-il une méthode qui devrait être écrasée (comme onActivityResult()) ou quelque chose?
25
TiGer


La question a été posée il y a quelques mois, mais si quelqu'un cherche toujours une réponse, j'espère pouvoir vous aider.

Dans l'exemple ci-dessous, nous avons un service local, chargé d'effectuer certaines opérations fastidieuses. Activity envoie les demandes au service, mais ne s'y associe pas - envoie simplement l'intention avec la demande. De plus, Activity inclut les informations de BroadcastReceiver qui doivent être rappelées lorsque le service est terminé avec la tâche demandée. Les informations sont transmises par PendingIntent. Le service gère la tâche en arrière-plan et lorsque la tâche est terminée, il diffuse BroadcastReceiver avec une réponse. 

1. Créer une sous-classe BroadcastReceiver:  

public class DataBroadcastReceiver extends BroadcastReceiver {
   static Logger log = LoggerFactory.getLogger(DataRequestService.class);   
   @Override
   public void onReceive(Context context, Intent intent) {
      log.info(" onReceive");
   }
}

Ce récepteur de diffusion sera avisé du service une fois la tâche terminée.

2. Créer un service

public class DataRequestService extends Service {

   private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
         super(looper);
      }

      @Override
      public void handleMessage(Message msg) {
         log.info("handleMessage");
         //... performing some time-consuming operation         
         Bundle bundle = msg.getData();
         PendingIntent receiver = bundle.getParcelable("receiver");
         // Perform the operation associated with PendingIntent
         try {            
            //you can attach data from the operation in the intent.
            Intent intent = new Intent();
            Bundle b = new Bundle();
            //b.putString("key", value);
            intent.putExtras(b);
            receiver.send(getApplicationContext(), status, intent);
         } catch (CanceledException e) {         
         e.printStackTrace();
         }         
      }
   }

   @Override
   public void onStart(Intent intent, int startId) {
      Bundle bundle = intent.getExtras();
      msg.setData(bundle);
      mServiceHandler.sendMessage(msg);
   }

La partie la plus importante est dans la méthode handleMessage (). Le service effectue simplement l'opération de diffusion pour fournir les résultats au récepteur de radiodiffusion.

3. Vous devez également enregistrer votre récepteur de radiodiffusion et votre service dans Manifest.xml

<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
    package="com.ramps.servicetest"
    Android:versionCode="1"
    Android:versionName="1.0" >
   ....
       <service Android:name=".service.DataRequestService" Android:exported="false"/>
       <receiver Android:name=".service.DataBroadcastReceiver"></receiver>
    </application>
</manifest><br>

4. Et enfin, demandez à votre service de l'activité:

Intent serviceIntent = new Intent(context, DataRequestService.class);   
   @Override
   public void onClick(View v) {
      //this is the intent that will be broadcasted by service.
      Intent broadcastReceiverIntent = new Intent(context, DataBroadcastReceiver.class);      
      //create pending intent for broadcasting the DataBroadcastReceiver
      PendingIntent pi = PendingIntent.getBroadcast(context, 0, broadcastReceiverIntent, 0);      
      Bundle bundle = new Bundle();            
      bundle.putParcelable("receiver", pi);
      //we want to start our service (for handling our time-consuming operation)
      Intent serviceIntent = new Intent(context, DataRequestService.class);
      serviceIntent.putExtras(bundle);
      context.startService(serviceIntent);
   }



5. Réponse fournie au client/activité d'origine .

Vous pouvez avoir une activité abstraite à partir de laquelle toutes vos activités seront étendues. Cette activité abstraite peut s'inscrire/désenregistrer automatiquement comme écouteur de réponse dans le récepteur de radiodiffusion. En réalité, il n’ya pas beaucoup d’options ici, mais il est important que si vous gardiez des références statiques à votre activité, vous devez supprimer le référent lorsque l’activité est détruite.

Cordialement,
Rampes

45
Ramps

Pour effectuer la communication entre service et activité . Vous pouvez également utiliser Binder comme mentionné dans l'exemple Android officiel http://developer.Android.com/reference/Android/app/Service.html#LocalServiceSample

Pour une explication détaillée, voir cette réponse https://stackoverflow.com/a/36983011/4754141

0
shanraisshan

Comme écrit ici

La communication entre service et activité peut être effectuée à l'aide de PendingIntent.For qui peut utiliser createPendingResult () . CreatePendingResult () crée un nouvel objet PendingIntent que vous pouvez remettre au service. à utiliser et à renvoyer les données de résultat à votre activité dans callActivityResult (int, int, Intent) callback. Depuis un PendingIntent est colis, et peut donc être placé dans une Intention extra, votre activité peut transmettre ce PendingIntent au service. Le service, à son tour, peut appeler la méthode send () Du PendingIntent pour notifier l’activité via OnActivityResult of un évènement.

Activité

public class PendingIntentActivity extends AppCompatActivity
{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

PendingIntent pendingResult = createPendingResult(
100, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), PendingIntentService.class);
intent.putExtra("pendingIntent", pendingResult);
startService(intent);

}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100 && resultCode==200) {
Toast.makeText(this,data.getStringExtra("name"),Toast.LENGTH_LONG).show();
}
super.onActivityResult(requestCode, resultCode, data);
}
}

Un service

public class PendingIntentService extends Service {

    private static final String[] items= { "lorem", "ipsum", "dolor",
            "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
            "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
            "vel", "erat", "placerat", "ante", "porttitor", "sodales",
            "pellentesque", "augue", "purus" };
    private PendingIntent data;

    @Override
    public void onCreate() {
        super.onCreate();
    }

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

        data = intent.getParcelableExtra("pendingIntent");

        new LoadWordsThread().start();
        return START_NOT_STICKY;
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    class LoadWordsThread extends Thread {
        @Override
        public void run() {
            for (String item : items) {
                if (!isInterrupted()) {

                    Intent result = new Intent();
                    result.putExtra("name", item);
                    try {
                        data.send(PendingIntentService.this,200,result);
                    } catch (PendingIntent.CanceledException e) {

                        e.printStackTrace();
                    }
                    SystemClock.sleep(400);

                }
            }
        }
    }
}
0