我目前正在开发Android应用程序。其中一个要求是广泛记录应用程序的使用方式。更具体地说,应该记录用户关闭应用的时间。此日志记录包含服务器交互。关于这个具体要求,我偶然发现:
Detect Application Exit(1)和Detect application Exit (2)
这两个问题都依赖Service#onTaskRemoved(Intent)
来接受答案。
在我的情况下,此解决方案似乎不起作用,即在此方法中启动的AsyncTask
仅偶尔执行。更具体地说,onPreExecute
执行始终,但doInBackground
不执行。我在安装了Android 6(Marshmallow)的Nexus 5上进行了测试。
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
方法中重新启动服务,然后在onStartCommand中执行AsyncTask
。IntentService
方法中启动onTaskRemoved
(在AsyncTask
方法中启动onHandleIntent
)解决了这个问题。BroadcastReceiver
与本地广播(LocalBroadcastManager#sendBroadcast
)结合使用也不起作用(我仔细检查了广播接收器是否已被有效注册为发送广播的接收方)。修改:
我还看了Application
类中的回调:
- onTerminate
:此方法仅在模拟环境中调用,因此无用
- onTrimMemory(int)
:此方法可用于检测应用程序何时进入后台,但在应用程序退出时没有明显的大小写。
我可以保留一个活动堆栈(可以在Activity#onPause()
中更新等)。但是,这需要在每个Activity
而不是上述Service
方法中进行大量工作,而这只涉及单个地方的干扰。
答案 0 :(得分:0)
首先:在Android中,您不能保证执行您的要求。期。系统可以随时使用gc你的课程或杀死你的过程。此外,Android概念并没有真正具有“关闭应用程序”操作的概念,就像网站没有它一样。所以在你继续阅读之前,我敦促你重新考虑你的要求。
话虽如此。以下是一些提示:
我对Service#onTaskRemoved(Intent)
的理解是,它只会在您通过任务切换器终止应用程序时执行,因此我不知道这对您是否有用。在你的实例中,我会在应用程序对象中保留一个活动引用计数器(每个onResume()为+1,对于任何活动的每个onPause()都为-1)。有了这个,您可以检查您的用户是否具有活动的UI。通常,如果你按下最后一个活动,那就是接近“关闭”应用程序的范例。然后只需从应用程序对象启动您的任务(这可能是获取gc的最后一个),或者如果这不起作用,请尝试未绑定服务您可以生成的最多解耦组件。< / p>
另一个非常糟糕的解决方案会覆盖对象中的finalize()方法(例如您的活动)。使用它的原因很少,因为它会触发一个额外的gc循环,你的代码将在主线程上运行,但如果对象即将被gc化,它是一种执行代码的方法。因此,不鼓励使用安卓团队,只有在你拿枪的时候才使用它。