android studio Service automatique appelé sur l'activité destructrice



programmation android pdf site du zero (4)

Si le processus qui exécute votre service est tué, le système Android le redémarrera automatiquement c'est le comportement par défaut.

Ce comportement est défini par la valeur de retour de onStartCommand() dans votre implémentation Service. La constante START_NOT_STICKY indique à Android de ne pas redémarrer le service si celui-ci est en cours d'exécution alors que le processus est "arrêté".

Vous devez remplacer la méthode onStartCommand() dans votre classe de service et déplacer tout votre code de la méthode onStartCommand() vers la méthode onStartCommand() .

Selon la documentation Android:

Pour les services démarrés, il existe deux modes de fonctionnement principaux supplémentaires, en fonction de la valeur onStartCommand() par onStartCommand() : START_STICKY est utilisé pour les services explicitement démarrés et arrêtés selon les besoins, alors que START_NOT_STICKY ou START_REDELIVER_INTENT sont utilisés pour les services qui ne doivent rester en cours d'exécution que lors du traitement des commandes qui leur sont envoyées

onStart() méthode onStart() appelle chaque fois que le service est redémarré mais la méthode onStartCommand() ne sera pas appelée si vous renvoyez START_NON_STICKY .

N'utilisez plus onStart (), c'est obsolète.

J'espère que ça t'aide.

Je suis bloqué avec le problème d' Activity + Service en ce que j'ai le nombre suivant d'activités et de services.

Activités:

LoginActivity => OrderListActivity => AddOrderActivity => ConfirmOrderActivity

Prestations de service:

  1. ReceivingOrderService - Réception de nouvelles données du serveur
  2. SendingOrderService - Envoi de nouvelles données au serveur

Au-dessus des deux appels de service d'un autre service séparé sur la durée de certains intervalles .

  1. CheckAutoSyncReceivingOrder - Pour appeler ReceivingOrderService (Interval 15Mins)
  2. CheckAutoSyncSendingOrder - Pour appeler SendingOrderService (Interval 3Mins)

CheckAutoSyncReceivingOrder:

public class CheckAutoSyncReceivingOrder extends Service {

    Timer timer;

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub

        if(timer != null) {
            timer.cancel();
            Log.i(TAG, "RECEIVING OLD TIMER CANCELLED>>>");
        }

        timer = new Timer();

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if(InternetConnection.checkConnection(getApplicationContext())) {
                    if(getDatabasePath(DatabaseHelper.DATABASE_NAME).exists())
                        startService(new Intent(CheckAutoSyncReceivingOrder.this, ReceivingOrderService.class));
                } else {
                    Log.d(TAG, "Connection not available");
                }
            }
        }, 0, 60000); // 1000*60*15 = 9,00,000 = 15 minutes
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();

        if(timer != null)
            timer.cancel();

        Log.d(TAG, "Stopping Receiving...");
    }
}

CheckAutoSyncSendingOrder:

public class CheckAutoSyncSendingOrder extends Service {

    Timer timer;

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub

        if(timer != null) {
            timer.cancel();
            Log.i(TAG, "OLD TIMER CANCELLED>>>");
        }

        timer = new Timer();

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                Log.i(TAG, ">>>>>>>> SENDING AUTO SYNC SERVICE >>>>>>>>");
                if(InternetConnection.checkConnection(getApplicationContext())) {
                    if(getDatabasePath(DatabaseHelper.DATABASE_NAME).exists())
                        startService(new Intent(CheckAutoSyncSendingOrder.this, SendingOrderService.class));
                } else {
                    Log.d(TAG, "connection not available");
                }
            }
        }, 0, 120000); //  1000*120*15 = 1,800,000 = 15 minutes
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();

        if(timer != null)
            timer.cancel();

        Log.d(TAG, "Stopping Sending...");
    }
}

ConfirmOrderActivity # Final Task que j'ai appelé pour insérer des données:

new AsyncTask<Void, Void, Integer>() {

    ProgressDialog progressDialog;

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();

        progressDialog = new ProgressDialog(
                ConfirmOrderProductActivity.this);
        progressDialog.setMessage("Inserting "
                + (isInquiry ? "Inquiry" : "Order") + "...");
        progressDialog.setCancelable(false);
        progressDialog
                .setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progressDialog.show();
    }

    @Override
    protected Integer doInBackground(Void... params) {
        // TODO Auto-generated method stub
        int account_id = context.getSharedPreferences(PREF_DATA,
                MODE_APPEND).getInt(DATA_ACCOUNT_ID, 0);

        /**
         * Check Whether isInquiry or not...
         */
        product_type = isWeight ? 1 : 0;
        if (isInquiry) {
            /*
             * INSERTING DATA IN INQUIRY TABLE
             */
            return m_inquiry_id;
        } else {
            /*
             * INSERTING DATA IN ORDER TABLE
             */
            return m_order_id;
        }
    }

    @Override
    protected void onPostExecute(Integer m_order_id) {
        // TODO Auto-generated method stub
        super.onPostExecute(m_order_id);

        progressDialog.dismiss();

        if (dbHelper.db.isOpen())
            dbHelper.close();

        String title = "Retry";
        String message = "There is some problem, Go Back and Try Again";

        AlertDialog.Builder alert = new AlertDialog.Builder(
                ConfirmOrderProductActivity.this);

        if (m_order_id != -1) {
            title = isInquiry ? "New Inquiry" : "New Order";
            message = isInquiry ? "Your Inquiry Send Successfully." : "Your Order Saved Successfully.";
            alert.setIcon(R.drawable.success).setCancelable(false);
        } else {
            alert.setIcon(R.drawable.fail).setCancelable(false);
        }

        alert.setTitle(title).setMessage(message)
                .setPositiveButton("OK", new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog,
                            int which) {
                        // TODO Auto-generated method stub
                        dialog.dismiss();
                        startActivity(new Intent(
                                ConfirmOrderProductActivity.this,
                                FragmentChangeActivity.class)
                                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));

                        /* Opening Left to Right Animation */
                        overridePendingTransition(R.anim.right_out,
                                R.anim.right_in);
                    }
                });

        AlertDialog alertDialog = alert.create();
        alertDialog.show();

    }
}.execute();

Tout fonctionne correctement selon le flux d'insertion d'enregistrements dans la base de données.

Après avoir ajouté une demande:

Détruire l'activité et se mettre à la suite de Logcat:

Problème principal:

Lorsque j'ai passé la commande avec succès à partir de ConfirmOrderActivity , il affiche AlertDialog du message Success qui peut être annulé false . Lorsque CheckAutoSyncReceivingOrder application de cette activité, elle appelle à la fois CheckAutoSyncReceivingOrder et CheckAutoSyncSendingOrder automatiquement.

Édité:

LoginActivity deux Service de LoginActivity seulement, après qu'il sera appelé automatiquement après des intervalles donnés Mais le problème se produit quand je détruis ConfirmOrderActivity quand la boîte de dialogue est montrée.

Je ne savais pas pourquoi il arrive que Pourquoi il fonctionne automatiquement lorsque j'arrête l'activité directement.

J'ai essayé onStartCommand() avec START_NON_STICKY dans Service mais ne fonctionne pas. (comme START_STICKY est la valeur par défaut.)

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_NOT_STICKY;
}

y-a-t'il une solution?


(1) Pour votre boîte de dialogue:

La solution consiste à appeler dismiss() sur le Dialog vous avez créé avant de quitter l' Activity , par exemple dans onDestroy() . Toutes les fenêtres et dialogues doivent être fermés avant de quitter une Activity .

(2) Pour votre service autostart:

vous devez regarder la valeur que le service renvoie de sa méthode onStartCommand. La valeur par défaut est START_STICKY qui redémarre le service après sa destruction. Jetez un oeil à la documentation onStartCommand pour plus de détails:


Les services ont été onStartCommand() lorsque l'application a été onStartCommand() (ajoutez les journaux dans les fonctions onStartCommand() et onDestroy() et essayez d'effacer l'application de la liste récente et vous verrez que onDestroy() est onDestroy() redémarrera le service si vous avez retourné l'intention START_STICKY onStartCommand() ).

Il existe deux approches pour résoudre votre problème.

  1. Faites vos deux services en tant que service de premier plan .

  2. Au lieu d'utiliser CheckAutoSyncReceivingOrder et CheckAutoSyncSendingOrder pour planifier le démarrage d'un autre service, vous devez utiliser AlarmManager pour planifier votre tâche.


Vous devez soit exécuter votre service au premier plan de sorte que lorsque l'activité est détruite, le service ou utiliser un service lié et gérer la liaison avec le cycle de vie de l'activité, il n'est pas redémarré continuellement lorsque l'activité est détruite.

A partir de ce didacticiel docs android Bound Services

Vous devez le faire pour chaque service.

public class CheckAutoSyncReceivingOrder extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        CheckAutoSyncReceivingOrder getService() {
        return CheckAutoSyncReceivingOrder.this;
    }
}

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

De votre activité qui crée et appelle le service, quand il est détruit, vous voulez que votre service soit détruit.

public class BindingActivity extends Activity {
    CheckAutoSyncReceivingOr mService;
    boolean mBound = false;


    @Override
    protected void onStart() {
        super.onStart();
        // Bind to CheckAutoSyncReceivingOr
        Intent intent = new Intent(this, CheckAutoSyncReceivingOr.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    /** Defines callbacks for service binding, passed to bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
            IBinder service) {
            // We've bound to CheckAutoSyncReceivingOr, cast the IBinder and get CheckAutoSyncReceivingOr instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}   

Et gérer le cycle de vie du service . Redémarrez le même service avec votre minuteur, ne créez pas un nouveau service.

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Remarque START_NOT_STICKY empêche uniquement le redémarrage du service si le périphérique manque de mémoire.

Sachez que lorsque vous démarrez des services, commencez-la une seule fois et permettez au service de maintenir son propre cycle de vie jusqu'à ce que vous le détruisiez avec votre activité.

Ceci est en réponse à votre question originale non éditée, quand l'application se brisait mystérieusement:

Vous devez détruire la boîte de dialogue avant la fenêtre contextuelle à laquelle la boîte de dialogue est attachée. Cela va causer un problème. C'est donc là que le déroulement du programme et l'ordre de fermeture et de nettoyage des ressources sont importants. Ils doivent souvent être détruits dans l'ordre inverse où ils ont été créés s'ils dépendent des fenêtres des parents (ce qui est souvent sous la forme d'une activité particulière).

Il est difficile de tracer votre code, c'est donc une réponse générique.

Exploitez onPause et onDestroy dans vos activités.

Dans toutes vos activités, gérez toutes les ressources que vous avez créées dans cette activité et, avec une vérification nulle, fermez-les. Comme vous l'avez dans votre classe de service. Si vous souhaitez remplacer le parent onDestroy, placez votre code personnalisé avant super.onDestroy.

protected void onDestroy() {

    if(timer != null)
        timer.cancel();

    Log.d(TAG, "Stopping Sending...");

    super.onDestroy();
}




android-intentservice