Come far comunicare il servizio Android con Activity


251

Sto scrivendo la mia prima applicazione Android e sto cercando di orientarmi nella comunicazione tra servizi e attività. Ho un servizio che verrà eseguito in background e fare alcuni gps e registrazione basata sul tempo. Avrò un'attività che verrà utilizzata per avviare e interrompere il servizio.

Quindi, prima, devo essere in grado di capire se il servizio è in esecuzione all'avvio dell'attività. Ci sono altre domande qui a riguardo, quindi penso di poterlo capire (ma sentiti libero di offrire consigli).

Il mio vero problema: se l'attività è in esecuzione e il servizio è avviato, ho bisogno di un modo per il servizio di inviare messaggi all'attività. Stringhe semplici e numeri interi a questo punto - per lo più messaggi di stato. I messaggi non accadranno regolarmente, quindi non credo che il polling del servizio sia un buon modo di procedere se esiste un altro modo. Voglio questa comunicazione solo quando l'attività è stata avviata dall'utente: non desidero avviare l'attività dal servizio. In altre parole, se avvii l'attività e il servizio è in esecuzione, vedrai alcuni messaggi di stato nell'interfaccia utente dell'attività quando accade qualcosa di interessante. Se non avvii l'attività, non vedrai questi messaggi (non sono così interessanti).

Sembra che dovrei essere in grado di determinare se il servizio è in esecuzione e, in tal caso, aggiungere l'attività come listener. Quindi rimuovere l'attività come ascoltatore quando l'attività viene messa in pausa o interrotta. È davvero possibile? L'unico modo in cui riesco a capire è fare in modo che Activity attui Parcelable e crei un file AIDL in modo da poterlo passare attraverso l'interfaccia remota del Servizio. Sembra però eccessivo, e non ho idea di come l'attività dovrebbe implementare writeToParcel () / readFromParcel ().

C'è un modo più semplice o migliore? Grazie per qualsiasi aiuto.

MODIFICARE:

Per chiunque sia interessato a questo in seguito, esiste un codice di esempio di Google per la gestione tramite AIDL nella directory degli esempi: /apis/app/RemoteService.java

Risposte:


94

Esistono tre modi ovvi per comunicare con i servizi:

  1. Usando gli intenti
  2. Utilizzando AIDL
  3. Utilizzo dell'oggetto di servizio stesso (come singleton)

Nel tuo caso, andrei con l'opzione 3. Fai un riferimento statico al servizio stesso e lo popolerei in onCreate ():

void onCreate(Intent i) {
  sInstance = this;
}

Crea una funzione statica MyService getInstance(), che restituisce la statica sInstance.

Quindi, quando Activity.onCreate()si avvia il servizio, attendere in modo asincrono fino a quando il servizio non viene effettivamente avviato (è possibile fare in modo che il servizio informi l'app che è pronta inviando un intento all'attività) e ottenere la sua istanza. Quando hai l'istanza, registra il tuo oggetto listener di servizio sul tuo servizio e sei pronto. NOTA: quando si modificano le viste all'interno dell'attività, è necessario modificarle nel thread dell'interfaccia utente, il servizio probabilmente eseguirà il proprio thread, quindi è necessario chiamare Activity.runOnUiThread().

L'ultima cosa che devi fare è rimuovere il riferimento al tuo oggetto listener Activity.onPause(), altrimenti verrà fuoriuscita un'istanza del tuo contesto di attività, non va bene.

NOTA: questo metodo è utile solo quando l'applicazione / attività / attività è l'unico processo che accederà al servizio. In caso contrario, è necessario utilizzare l'opzione 1. o 2.


2
Come posso busy-waitl'attività? Puoi spiegare per favore?
iTurki

1
Quindi, dopo onCreate o dopo onStartCommand nella classe di servizio, imposta una variabile statica pubblica, chiamala isConnected o qualcosa su true. Quindi, nella tua attività, fai questo: Intent intent = new Intent (act, YourService.class); StartService (intento); while (! YourService.isConnected) {sleep (300); } Dopo quel ciclo il tuo servizio è in esecuzione e puoi comunicare con esso. Nella mia esperienza ci sono sicuramente alcune limitazioni all'interazione con un servizio come questo.
Matt Wolfe,

Perché può essere avviato solo in Activity.onCreate()?
skywall

Qualche parola sul perché non vorresti usare Intentsinviando dati attraverso Parcellablemessaggi tra loro?
Aman Alam,

2
Funziona, ma la risposta di @ MaximumGoat è molto più pulita e non comporta alcuna attesa.
Matt

262

Probabilmente l'assassino è passato da tempo, ma nel caso qualcun altro lo cerchi ...

C'è un altro modo di gestirlo, che penso potrebbe essere il più semplice.

Aggiungi a BroadcastReceiveralla tua attività. Registralo per ricevere alcuni intenti personalizzati onResumee annullare la registrazione onPause. Quindi invia quell'intento dal tuo servizio quando vuoi inviare i tuoi aggiornamenti di stato o cosa hai.

Assicurati di non essere infelice se qualche altra app ascoltasse la tua Intent(qualcuno potrebbe fare qualcosa di dannoso?), Ma oltre a ciò, dovresti essere a posto.

È stato richiesto un esempio di codice:

Al mio servizio, ho questo:

// Do stuff that alters the content of my local SQLite Database
sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));

( RefreshTask.REFRESH_DATA_INTENTè solo una stringa costante.)

Nella mia attività di ascolto, definisco il mio BroadcastReceiver:

private class DataUpdateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) {
          // Do stuff - maybe update my view based on the changed DB contents
        }
    }
}

Dichiaro il mio ricevitore ai vertici della classe:

private DataUpdateReceiver dataUpdateReceiver;

Sostituisco onResumeper aggiungere questo:

if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);

E sovrascrivo onPauseper aggiungere:

if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);

Ora la mia attività è in ascolto del mio servizio per dire "Ehi, vai ad aggiornarti." Potrei passare i dati Intentinvece di aggiornare le tabelle del database e poi tornare indietro per trovare le modifiche all'interno della mia attività, ma poiché voglio che le modifiche persistano, ha senso passare i dati tramite DB.


5
Come? Quello che descrivi è esattamente ciò di cui ho bisogno. Ma soprattutto, ho bisogno di un codice di esempio completo. Grazie in anticipo. Cordiali saluti, l'ultima volta che ho provato a scrivere un widget, la parte di messaggistica mi ha impiegato 2 mesi. Ridi se vuoi, ma i tuoi esperti devono pubblicare di più poiché IMHO Android è più complicato di iOS!

1
aaaaaaa, La Guida del programmatore occupato allo sviluppo avanzato di Android ha un eccellente capitolo sui widget. È l'unica risorsa che mi ha fatto superare quel casino. CommonsWare, l'autore, ha una reputazione di 115k su StackOverflow e consiglio vivamente il libro. commonsware.com/AdvAndroid
MaximumGoat

64
Broadcastssono fantastici e, inoltre, se non vuoi che la tua trasmissione vada oltre il tuo stesso processo, LocalBroadcast
prendi in

2
Grazie Cody, non l'avevo mai visto prima.
MaximumGoat

3
Questo è un ottimo modo di comunicare. Ma cosa fare in caso di risultati, quando l'attività era in pausa? Quindi, dopo onResume, l'attività può attendere molto tempo per i risultati. E nessun dato verrà ricevuto, perché i dati sono stati persi.
Anton-M,

39

Utilizzare LocalBroadcastManagerper registrare un ricevitore per ascoltare una trasmissione inviata dal servizio locale all'interno dell'app, il riferimento va qui:

http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html


3
Sì, una bella discussione sul link
locale

1
LocalBroadcastManagerè ora deprecato a favore LiveDatao altri strumenti di pattern di osservatori: developer.android.com/reference/androidx/localbroadcastmanager/…
Ali Nem

20

Sono sorpreso che nessuno abbia fatto riferimento alla biblioteca Bus degli eventi Otto

http://square.github.io/otto/

Ho usato questo nelle mie app Android e funziona senza problemi.


7
In alternativa, c'è la libreria EventBus di greenrobot .
Jazzer,

15
Ma ricorda che EventBus e otto sono sempre in un unico processo. Quando si utilizza un servizio che è nel proprio processo (iniziato con l'impostazione, android:process=":my_service"non sono in grado di comunicare.
Ron

20

L'uso di Messenger è un altro modo semplice per comunicare tra un servizio e un'attività.

Nell'attività, creare un gestore con un Messenger corrispondente. Questo gestirà i messaggi dal tuo Servizio.

class ResponseHandler extends Handler {
    @Override public void handleMessage(Message message) {
            Toast.makeText(this, "message from service",
                    Toast.LENGTH_SHORT).show();
    }
}
Messenger messenger = new Messenger(new ResponseHandler());

Messenger può essere passato al servizio allegandolo a un messaggio:

Message message = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER);
message.replyTo = messenger;
try {
    myService.send(message);
catch (RemoteException e) {
    e.printStackTrace();
}

Un esempio completo è disponibile nelle demo API: MessengerService e MessengerServiceActivity . Fare riferimento all'esempio completo per come funziona MyService.


1
Molto apprezzato! Funziona perfettamente. Solo un dettaglio nel codice: myService.send(message);dovrebbe essere messenger.send(message);invece.
Federico Cristina,


9

Puoi anche usare LiveDataquello che funziona come un EventBus.

class MyService : LifecycleService() {
    companion object {
        var BUS = MutableLiveData<Object>()
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)

        val testItem : Object

        // expose your data
        if (BUS.hasActiveObservers()) {
            BUS.postValue(testItem)
        }

        return START_NOT_STICKY
    }
}

Quindi aggiungi un osservatore dal tuo Activity.

MyService.BUS.observe(this, Observer {
    it?.let {
        // Do what you need to do here
    }
})

Puoi leggere di più da questo blog.


2

Un altro modo potrebbe essere quello di utilizzare osservatori con una classe di modello falsa attraverso l'attività e il servizio stesso, implementando una variazione del modello MVC. Non so se sia il modo migliore per raggiungere questo obiettivo, ma è il modo in cui ha funzionato per me. Se hai bisogno di qualche esempio, chiedilo e posterò qualcosa.


Sto lottando con pensieri simili. Ho attività e 2 servizi che hanno lo stesso modello. Il modello può essere aggiornato in entrambe le attività o in qualsiasi servizio, quindi ho pensato di utilizzare gli osservatori in qualche modo, ma non riesco a capirlo. Puoi pubblicare un esempio per mostrare la tua idea?
pzo,

2

Il mio metodo:

Classe per gestire l'invio e la ricezione di messaggi da / a servizio / attività:

import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class MessageManager {

    public interface IOnHandleMessage{
        // Messages
        int MSG_HANDSHAKE = 0x1;

        void onHandleMessage(Message msg);
    }

    private static final String LOGCAT = MessageManager.class.getSimpleName();

    private Messenger mMsgSender;
    private Messenger mMsgReceiver;
    private List<Message> mMessages;

    public MessageManager(IOnHandleMessage callback, IBinder target){
        mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_ACTIVITY));
        mMsgSender = new Messenger(target);
        mMessages = new ArrayList<>();
    }

    public MessageManager(IOnHandleMessage callback){
        mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_SERVICE));
        mMsgSender = null;
        mMessages = new ArrayList<>();
    }

    /* START Getter & Setter Methods */
    public Messenger getMsgSender() {
        return mMsgSender;
    }

    public void setMsgSender(Messenger sender) {
        this.mMsgSender = sender;
    }

    public Messenger getMsgReceiver() {
        return mMsgReceiver;
    }

    public void setMsgReceiver(Messenger receiver) {
        this.mMsgReceiver = receiver;
    }

    public List<Message> getLastMessages() {
        return mMessages;
    }

    public void addMessage(Message message) {
        this.mMessages.add(message);
    }
    /* END Getter & Setter Methods */

    /* START Public Methods */
    public void sendMessage(int what, int arg1, int arg2, Bundle msgData){
        if(mMsgSender != null && mMsgReceiver != null) {
            try {
                Message msg = Message.obtain(null, what, arg1, arg2);
                msg.replyTo = mMsgReceiver;
                if(msgData != null){
                    msg.setData(msgData);
                }
                mMsgSender.send(msg);
            } catch (RemoteException rE) {
                onException(rE);
            }
        }
    }

    public void sendHandshake(){
        if(mMsgSender != null && mMsgReceiver != null){
            sendMessage(IOnHandleMessage.MSG_HANDSHAKE, 0, 0, null);
        }
    }
    /* END Public Methods */

    /* START Private Methods */
    private void onException(Exception e){
        Log.e(LOGCAT, e.getMessage());
        e.printStackTrace();
    }
    /* END Private Methods */

    /** START Private Classes **/
    private class MessageHandler extends Handler {

        // Types
        final static int TYPE_SERVICE = 0x1;
        final static int TYPE_ACTIVITY = 0x2;

        private IOnHandleMessage mCallback;
        private int mType;

        public MessageHandler(IOnHandleMessage callback, int type){
            mCallback = callback;
            mType = type;
        }

        @Override
        public void handleMessage(Message msg){
            addMessage(msg);
            switch(msg.what){
                case IOnHandleMessage.MSG_HANDSHAKE:
                    switch(mType){
                        case TYPE_SERVICE:
                            setMsgSender(msg.replyTo);
                            sendHandshake();
                            break;
                        case TYPE_ACTIVITY:
                            Log.v(LOGCAT, "HERE");
                            break;
                    }
                    break;
                default:
                    if(mCallback != null){
                        mCallback.onHandleMessage(msg);
                    }
                    break;
            }
        }

    }
    /** END Private Classes **/

}

Nell'esempio di attività:

public class activity extends AppCompatActivity
      implements     ServiceConnection,
                     MessageManager.IOnHandleMessage { 

    [....]

    private MessageManager mMessenger;

    private void initMyMessenger(IBinder iBinder){
        mMessenger = new MessageManager(this, iBinder);
        mMessenger.sendHandshake();
    }

    private void bindToService(){
        Intent intent = new Intent(this, TagScanService.class);
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        /* START THE SERVICE IF NEEDED */
    }

    private void unbindToService(){
    /* UNBIND when you want (onDestroy, after operation...)
        if(mBound) {
            unbindService(mServiceConnection);
            mBound = false;
        }
    }

    /* START Override MessageManager.IOnHandleMessage Methods */
    @Override
    public void onHandleMessage(Message msg) {
        switch(msg.what){
            case Constants.MSG_SYNC_PROGRESS:
                Bundle data = msg.getData();
                String text = data.getString(Constants.KEY_MSG_TEXT);
                setMessageProgress(text);
                break;
            case Constants.MSG_START_SYNC:
                onStartSync();
                break;
            case Constants.MSG_END_SYNC:
                onEndSync(msg.arg1 == Constants.ARG1_SUCCESS);
                mBound = false;
                break;
        }
    }
    /* END Override MessageManager.IOnHandleMessage Methods */

    /** START Override ServiceConnection Methods **/
    private class BLEScanServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            initMyMessenger(iBinder);
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mMessenger = null;
            mBound = false;
        }
    }
    /** END Override ServiceConnection Methods **/

In servizio Esempio:

public class Blablabla extends Service
    implements     MessageManager.IOnHandleMessage {

    [...]

    private MessageManager mMessenger;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        super.onBind(intent);
        initMessageManager();
        return mMessenger.getMsgReceiver().getBinder();
    }

    private void initMessageManager(){
        mMessenger = new MessageManager(this);
    }

    /* START Override IOnHandleMessage Methods */
    @Override
    public void onHandleMessage(Message msg) {
    /* Do what you want when u get a message looking the "what" attribute */
    }
    /* END Override IOnHandleMessage Methods */

Invia un messaggio da Attività / Servizio:

mMessenger.sendMessage(what, arg1, arg2, dataBundle);

Come funziona:

sull'attività avviata o vincolante il servizio. I metodi di servizio "OnBind" restituiscono il Raccoglitore al suo MessageManager, mentre nell'attività tramite l'implementazione dei metodi dell'interfaccia "Connessione servizio" "OnServiceConnected" si ottiene questo IBinder e si avvia MessageManager che lo utilizza. Dopo che l'attività ha avviato il suo MessageManager, MessageHandler invia e Handshake al servizio in modo che possa impostare il suo mittente "MessageHandler" (il "Messenger privato mMsgSender;" in MessageManager). In questo modo il servizio sa a chi inviare i suoi messaggi.

Puoi anche implementarlo usando un "mittente" Elenco / Coda di Messenger nel MessageManager in modo da poter inviare più messaggi a diverse Attività / Servizi oppure puoi utilizzare un "destinatario" Elenco / Coda di Messenger nel MessageManager in modo da poter ricevere più messaggio da diverse attività / servizi.

Nell'istanza "MessageManager" hai un elenco di tutti i messaggi ricevuti.

Come puoi vedere la connessione tra "Activity's Messenger" e "Service Messenger" usando questa istanza "MessageManager" è automatica, è fatta attraverso il metodo "OnServiceConnected" e attraverso l'uso dell'handshake.

Spero che questo ti sia utile :) Grazie mille! Ciao: D


2

Per dare seguito alla risposta di @MrSnowflake con un esempio di codice. Questo è il XABBER ora open source Applicationdi classe . La Applicationclasse sta centralizzando e coordinando Listenerse ManagerInterfaces e altro. I gestori di ogni genere vengono caricati in modo dinamico. Activity´savviato in Xabber riporterà in che tipo di Listeneressi sono. E quando Serviceinizia, segnala all'inizio della Applicationlezione. Ora per inviare un messaggio a Activitytutto ciò che devi fare è Activitytrasformarti in un listenertipo di cui hai bisogno. Nel OnStart() OnPause()registro / unreg. L' Servicepuò chiedere la Applicationclasse per solo che listenerha bisogno di parlare e se è lì allora l'attività è pronto a ricevere.

Durante la Applicationlezione vedrai che c'è ancora molto da fare.


Il link fornito ora risulta in un github 404. Si è spostato?
JE Carter II,

Sì, sembra funzionare ora. Deve essere stato un problema temporaneo su github.
JE Carter II

1

Il legame è un altro modo di comunicare

Crea un callback

public interface MyCallBack{

   public void getResult(String result);

}

Lato attività:

  1. Implementare l'interfaccia nell'Attività

  2. Fornire l'implementazione per il metodo

  3. Associare l'attività al servizio

  4. Registrare e annullare la registrazione della richiamata quando il servizio viene associato e non associato a Activity.

    public class YourActivity extends AppCompatActivity implements MyCallBack{
    
          private Intent notifyMeIntent;
          private GPSService gpsService;
          private boolean bound = false;
    
          @Override
          public void onCreate(Bundle sis){
    
              // activity code ...
    
              startGPSService();
    
          }
    
          @Override
          public void getResult(String result){
           // show in textView textView.setText(result);
          }
    
          @Override
          protected void onStart()
          {
              super.onStart();
              bindService();
          }
    
          @Override
          protected void onStop() {
              super.onStop();
              unbindService();
          }
    
          private ServiceConnection serviceConnection = new ServiceConnection() {
    
                @Override
                public void onServiceConnected(ComponentName className, IBinder service) {
    
                      GPSService.GPSBinder binder = (GPSService.GPSBinder) service;
                      gpsService= binder.getService();
                      bound = true;
                      gpsService.registerCallBack(YourActivity.this); // register
    
               }
    
               @Override
               public void onServiceDisconnected(ComponentName arg0) {
                      bound = false;
               }
          };
    
          private void bindService() {
    
               bindService(notifyMeIntent, serviceConnection, Context.BIND_AUTO_CREATE);
          }
    
          private void unbindService(){
               if (bound) {
                     gpsService.registerCallBack(null); // unregister            
                     unbindService(serviceConnection);
                     bound = false;
                }
          }
    
          // Call this method somewhere to start Your GPSService
          private void startGPSService(){
               notifyMeIntent = new Intent(this, GPSService.class);
               startService(myIntent );
          }
    
     }

Lato servizio:

  1. Inizializza callback

  2. Richiamare il metodo di callback ogni volta che è necessario

     public class GPSService extends Service{
    
         private MyCallBack myCallback;
         private IBinder serviceBinder = new GPSBinder();
    
         public void registerCallBack(MyCallBack myCallback){
              this.myCallback= myCallback;
         }
    
         public class GPSBinder extends Binder{
    
             public GPSService getService(){
                  return GPSService.this;
             }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent){
             return serviceBinder;
        }
     }

il tuo serviceConnectionè fuori onCreate. Per favore, modificalo.
Adeel Zafar,

Non deve essere dentro onCreate
Rohit Singh il


0

Oltre a LocalBroadcastManager, Event Bus e Messenger che hanno già risposto a questa domanda, possiamo utilizzare Pending Intent per comunicare dal servizio.

Come menzionato qui nel mio post sul blog

La comunicazione tra servizio e attività può essere effettuata tramite PendingIntent.Per cui possiamo usare createPendingResult () .createPendingResult () crea un nuovo oggetto PendingIntent che puoi consegnare al servizio per utilizzare e inviare i dati dei risultati alla tua attività all'interno di onActivityResult (int, int, Intent) callback. Dato che un PendingIntent è parcelabile e può quindi essere inserito in un intento extra, la tua attività può passare questo PendingIntent al servizio. Il servizio, a sua volta, può chiamare il metodo send () sul PendingIntent per notificare il attività tramite onActivityResult di un evento.

Attività

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

Servizio

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

                }
            }
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.