Mon Android 4+ est connectée à un service Web personnalisé qui est utilisé pour synchroniser les données toutes les quelques minutes. Pour m'assurer que les données en ligne sont toujours à jour, je souhaite déclencher la synchroniser à chaque fois que l'application est fermée/envoyée en arrière-plan.
Sous iOS, c'est assez simple:
applicationDidEnterBackground:
Dans AppDelegatebeginBackgroundTaskWithName:
Pour démarrer une tâche en arrière-plan de longue durée et pour éviter d'être suspendu pendant que la tâche est en cours d'exécutionComment faire cela sur Android?
Premier problème est qu'il n'y a rien d'équivalent à applicationDidEnterBackground:
. Toutes les solutions que j'ai trouvées jusqu'à présent proposent d'utiliser la méthode principale Activités onPause()
. Cependant, cela est appelé à chaque fois que le Activity
principal est suspendu, ce qui est également le cas lorsqu'un autre Activity
est démarré dans l'application. Ceci est vrai pour la méthode onActivityPaused()
à partir de l'interface ActivityLifecycleCallbacks
.
Alors, comment détecter que app (pas seulement un Activity
) est fermé ou envoyé en arrière-plan?
Deuxième problème est que je n'ai trouvé aucune information sur la façon d'exécuter la tâche en arrière-plan. Toutes les solutions pointent simplement pour démarrer un AsyncTask
, mais est-ce vraiment la bonne solution?
AsyncTask
démarrera une nouvelle tâche, mais cette tâche s'exécutera-t-elle également lorsque l'application sera fermée/inactive? Que dois-je faire pour éviter que l'application et la tâche ne soient suspendues après quelques secondes? Comment puis-je m'assurer que la tâche peut se terminer avant que l'application ne soit complètement suspendue?
Le code suivant vous aidera à publier votre contenu lorsque votre application est fermée ou en arrière-plan:
import Android.app.Service;
import Android.content.Intent;
import Android.os.Binder;
import Android.os.Handler;
import Android.os.IBinder;
import Android.widget.Toast;
public class SendDataService extends Service {
private final LocalBinder mBinder = new LocalBinder();
protected Handler handler;
protected Toast mToast;
public class LocalBinder extends Binder {
public SendDataService getService() {
return SendDataService .this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
// write your code to post content on server
}
});
return Android.app.Service.START_STICKY;
}
}
Plus d'explication de mon code est:
Le service s'exécute en arrière-plan même si votre application est en arrière-plan, mais n'oubliez pas qu'il s'exécute toujours sur le thread principal à cause duquel j'ai créé un thread séparé pour effectuer vos opérations en arrière-plan.
Le service est démarré comme collant car même si, pour une raison quelconque, votre service a été détruit en arrière-plan, il sera automatiquement redémarré.
Plus de détails peuvent être trouvés ici: https://developer.Android.com/guide/components/services.html
Et pour vérifier si votre application est au premier plan/arrière-plan, le code suivant vous aidera:
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
// Use like this:
boolean foregroud = new ForegroundCheckTask().execute(context).get();
Happy Coding !!!!
La réponse acceptée n'est pas correcte.
Malheureusement, l'auteur estime que la publication d'une nouvelle tâche exécutable dans le gestionnaire () crée un thread séparé - "J'ai créé un thread séparé pour effectuer vos opérations d'arrière-plan":
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
// write your code to post content on server
}
});
return Android.app.Service.START_STICKY;
}
le rappel onStartCommand () est toujours appelé sur le thread principal et le nouveau Handler () est attaché au thread actuel (qui est "principal"). La tâche exécutable est donc publiée à la fin de la file d'attente principale des threads.
Pour résoudre le problème et exécuter Runnable dans un thread vraiment séparé, vous pouvez utiliser AsyncTask comme solution la plus simple:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
// ...
}
});
return Android.app.Service.START_STICKY;
}
Pensez-vous avant de copier-coller quoi que ce soit ...
Vous pouvez utiliser les services pour ce que vous voulez réaliser. Un service continuera de fonctionner en arrière-plan même lorsque le composant d'activité a été détruit , à condition que vous n'ayez pas appelé stopService (..) ou stopSelf () méthodes.
Dans le service, vous pouvez effectuer un appel réseau Async, de préférence à l'aide de la modification, puis vous pouvez mettre à jour votre stockage local comme Sqlite DB avec les dernières données extraites de votre service Web.
Ici est le lien officiel, vous pouvez simplement utiliser un service illimité pour ce que vous voulez réaliser.