1

В настоящее время я разрабатываю приложение для Android. Одним из требований является обширный журнал о том, как приложение используется. В частности, должно появиться сообщение о том, когда пользователь закрывает приложение. Это ведение журнала состоит из взаимодействия с сервером. Что касается этого конкретного требования я наткнулся на:Служба Android выполняет AsyncTask после закрытия приложения

Detect Application Exit(1) и Detect application Exit (2)

Оба вопроса имеют общепринятый ответ, опираясь на Service#onTaskRemoved(Intent).

В моем случае, однако, это решение, похоже, не работает, то есть AsyncTask s, которые запускаются в этом методе, являются только иногда выполнен. В частности, onPreExecute исполняется всегда, но doInBackground нет. Я тестировал это на Nexus 5 с установленным Android 6 (Marshmallow).

public class SomeService extends Service { 

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

    @Override 
    public void onTaskRemoved(Intent aRootIntent) { 
    new DoSomethingTask().executeOnExecutor(Asyntask.THREAD_POOL_EXECUTOR); 
    } 

    private static final class DoSomethingTask extends AsyncTask<Void, Void, Void> { 

    @Override 
    protected void onPreExecute() { 
     Log.e(DoSomethingTask.class.getName(), "This is executed always"); 
    } 

    @Override 
    protected Void doInBackground(Void... aParams) { 
     Log.e(DoSomethingTask.class.getName(), "This appears to be executed only sometimes... "); 
     // here an actual call to a Rest API should be made to inform the server that the user has closed the application. 
    } 

    @Override 
    protected void onCancelled(Void result) { 
     super.onCancelled(result); 
     Log.e(DoSomethingTask.class.getName(), "Never invoked"); 
    } 

    @Override 
    protected void onCancelled() { 
     super.onCancelled(); 
     Log.e(DoSomethingTask.class.getName(), "Never invoked"); 
    } 
    } 
} 

Вот краткий обзор всего, что я попытался в дополнение к указанной выше примере кода:

  • Я пробовал различные варианты onStartCommand (START_STICKY, START_NOT_STICKY и т.д.) не увенчались успехом.
  • Я также попытался перезапустить службу в методе onTaskRemoved, а затем выполнил команду AsyncTask в onStartCommand.
  • Запуск IntentService в методе onTaskRemoved (который запускает AsyncTask в своем методе onHandleIntent) не решает проблему ни.
  • с использованием BroadcastReceiver в сочетании с местной широковещательной рассылкой (LocalBroadcastManager#sendBroadcast) также не работает (я дважды проверил, что широковещательный приемник фактически зарегистрирован в качестве приемника для отправленной передачи).

EDIT:

Я также принял взглянуть на обратных вызовах в Application классе: - onTerminate: этот метод вызывается только в эмулируемой среде и, следовательно, бесполезно - onTrimMemory(int): этот метод может используется для обнаружения, когда приложение переходит в фоновый режим, но не имеет отдельного случая, когда приложение выходит.

Я мог бы хранить стек действий (который будет обновлен в Activity#onPause() и т. Д.). Но это требует довольно много работы в каждом Activity вместо вышеописанного подхода Service, который включает только помехи в одном месте.

+0

Возможно, вы сможете это сделать, расширив класс Application и переопределив onTerminate() onDestroy() onLowMemory() и все такое. – napkinsterror

+0

Я тоже пробовал это, но я забыл упомянуть об этом в сообщении. Я сделал это сейчас внизу, см. Раздел ** Редактировать **. –

ответ

0

Прежде всего: в Android вы не можете гарантировать выполнение своих требований. Период. Система бесплатна для ваших классов или убивает ваш процесс в любое время. Кроме того, концепция Android на самом деле не имеет концепции действий «закрытия приложения» так же, как и у сайтов. Поэтому, прежде чем продолжить чтение, я призываю вас пересмотреть свои требования.

Это считая. Вот несколько советов: Мое понимание Service#onTaskRemoved(Intent) заключается в том, что оно выполняется только в том случае, если вы убили приложение с помощью переключателя задач, поэтому я не знаю, полезно ли это для вас.В вашем случае я бы сохранил активность ref counter в объекте приложения (+1 для каждого onResume(), -1 для каждого onPause() любого действия). С помощью этого вы можете проверить, имеет ли пользователь активный пользовательский интерфейс. Обычно, если вы нажмете на последнее действие, которое приближается к парадигме «закрытие» приложения. Затем просто запустите свою задачу в этой точке из объекта приложения (это, вероятно, будет последним, чтобы получить gc), или если это не работает, попробуйте несвязанный сервис самый несвязанный компонент, который вы можете сгенерировать.

Другое, Очень плохое решение переопределяет метод finalize() в объекте (например, в вашей деятельности). Есть только очень и очень мало причин использовать его, поскольку он вызовет дополнительный gc-цикл, и ваш код будет запущен в основном потоке, но это способ выполнить код, если объект будет готов к gc'ed. Поэтому не рекомендуется использовать команду android, используйте ее только в том случае, если у вас есть оружие.

Смежные вопросы