Comment utiliser PendingIntent pour communiquer d'un Service à un client / activité?
J'ai lu le texte suivant sur le site des Développeurs Android, en particulier sous les sujets du Cadre - > Services - > Démarrer un Service .
Il indique 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 livrer au service dans l'intention qui démarre le service. Le service peut alors utiliser la diffusion pour fournir un résultat.
J'ai quelques questions à ce sujet:
- ce texte Ne s'appliquent tous deux à
Service
s etIntentService
s ? - Comment (codewise) cela devrait-il être réalisé de l'intérieur du
Service
; le service peut alors utiliser la diffusion pour fournir un résultat. et aussi où la diffusion mentionnée livrerait-elle le résultat au client/à l'activité d'origine? Y a-t-il une méthode qui devrait être écrasée (commeonActivityResult()
) ou quelque chose?
3 réponses
Question a été posée il y a quelques mois, mais au cas où quelqu'un est toujours à la recherche de réponse, j'espère que je peux aider.
Dans l'exemple ci-dessous, nous avons de service, responsable de l'exécution de certaines opérations fastidieuses. Activity effectue les requêtes au service, mais ne s'y lie pas - envoie simplement l'intention avec la requête. En outre, Activity inclut les informations de BroadcastReceiver qui doivent être rappelées lorsque le service est effectué avec la tâche demandée. L'information est passé par PendingIntent. Le service gère la tâche dans le thread d'arrière-plan et lorsque la tâche est terminée, le service 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 averti du service, lorsque la tâche est 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);
}
Eh bien, la partie la plus importante est dans la méthode handleMessage (). Le Service fait simplement l'opération de diffusions pour la livraison résultats au récepteur de diffusion.
3. Vous devez également enregistrer votre récepteur de diffusion 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, faites une demande à 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. Fournir une réponse au client/à l'activité initial.
Vous pouvez avoir une activité Abstraite À partir de laquelle toutes vos activités s'étendront. Cette activité abstrct peut automatiquement s'Enregistrer / se désenregistrer en tant qu'écouteur de réponse dans le récepteur de diffusion. Pas beaucoup d'options ici en fait, mais il est important que si vous gardez des références statiques à votre activité, vous devez supprimer la référence lorsque l'activité est détruite.
Cordialement,
Rampes
Afin de réaliser la communication entre les 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
Comme l'écrit ici
La Communication entre le service et L'activité peut se faire en utilisant PendingIntent.Pour cela, nous pouvons utiliser createPendingResult () .createPendingResult() crée un nouvel objet PendingIntent que vous pouvez remettre au service à utiliser et à envoyer les données de résultat à votre activité dans onActivityResult (int, int, L'intention) de rappel.Depuis un PendingIntent est Parcelable, et peut par conséquent, être mis dans une Intention supplémentaire,votre activité peut passer cette PendingIntent au service.Le service, à son tour, peut appeler envoyer() méthode sur le PendingIntent pour notifier l'activité via onActivityResult d'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); } }
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); } } } } }