Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/179.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android服务在应用程序关闭后执行异步任务_Android_Android Asynctask_Android Service_Android Broadcast_Intentservice - Fatal编程技术网

Android服务在应用程序关闭后执行异步任务

Android服务在应用程序关闭后执行异步任务,android,android-asynctask,android-service,android-broadcast,intentservice,Android,Android Asynctask,Android Service,Android Broadcast,Intentservice,我目前正在为Android开发一个应用程序。其中一个要求是广泛记录应用程序的使用情况。更具体地说,应该记录用户何时关闭应用程序。此日志记录由服务器交互组成。关于这一具体要求,我偶然发现: 及 这两个问题都有公认的答案,答案取决于服务#onTaskRemoved(Intent) 然而,在我的情况下,该解决方案似乎不起作用,即在该方法中启动的AsyncTasks只是偶尔执行。更具体地说,onPreExecute始终执行但doInBackground不执行。我在安装了安卓6(棉花糖)的Nexus5上进

我目前正在为Android开发一个应用程序。其中一个要求是广泛记录应用程序的使用情况。更具体地说,应该记录用户何时关闭应用程序。此日志记录由服务器交互组成。关于这一具体要求,我偶然发现:

这两个问题都有公认的答案,答案取决于
服务#onTaskRemoved(Intent)

然而,在我的情况下,该解决方案似乎不起作用,即在该方法中启动的
AsyncTask
s只是偶尔执行。更具体地说,
onPreExecute
始终执行
doInBackground
不执行。我在安装了安卓6(棉花糖)的Nexus5上进行了测试

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" );
    }
  }
}
public类SomeService扩展服务{
@凌驾
公共IBinder onBind(意向维护){
返回null;
}
@凌驾
公共无效onTaskRemoved(意向性内容){
新的DoSomethingTask().executeOnExecutor(Asyntask.THREAD\u POOL\u EXECUTOR);
}
私有静态最终类DoSomethingTask扩展了AsyncTask{
@凌驾
受保护的void onPreExecute(){
Log.e(DoSomethingTask.class.getName(),“始终执行此操作”);
}
@凌驾
受保护的空位背景(空位…空位){
Log.e(DoSomethingTask.class.getName(),“这似乎只是有时执行…”);
//这里应该实际调用RESTAPI,通知服务器用户已关闭应用程序。
}
@凌驾
取消后受保护的作废(作废结果){
super.onCancelled(结果);
Log.e(DoSomethingTask.class.getName(),“从未调用”);
}
@凌驾
受保护的void onCancelled(){
super.onCancelled();
Log.e(DoSomethingTask.class.getName(),“从未调用”);
}
}
}
以下是除上述代码示例外我尝试的所有内容的概述:

  • 我尝试了各种
    onStartCommand
    选项(启动粘滞、启动不粘滞等),但都没有成功
  • 我还尝试在
    onTaskRemoved
    方法中重新启动服务,然后在onstart命令中执行
    AsyncTask
  • onTaskRemoved
    方法中启动
    IntentService
    (在其
    onHandleIntent
    方法中启动
    AsyncTask
    )也不能解决问题
  • BroadcastReceiver
    与本地广播(
    LocalBroadcastManager#sendBroadcast
    )结合使用也不起作用(我仔细检查了广播接收器是否有效注册为发送广播的接收器)
编辑

我还查看了
应用程序
类中的回调: -
onTerminate
:此方法仅在模拟环境中调用,因此无效 -
ontrimmory(int)
:此方法可用于检测应用程序何时进入后台,但对于应用程序何时退出,它没有明确的案例


我可以保留一个活动堆栈(将在
活动#onPause()
等中更新)。但这需要在每个
活动中做大量工作,而不是上述
服务
方法,该方法只涉及单个位置的干扰。

首先:在安卓系统中,您无法保证执行您的要求。时期系统可以随时gc您的类或终止您的进程。此外,Android的概念并没有真正的“关闭应用程序”的概念,就像网站没有一样。因此,在你继续阅读之前,我敦促你重新考虑你的要求

话虽如此。以下是一些提示: 我对
服务#onTaskRemoved(Intent)
的理解是,只有通过任务切换器杀死应用程序时才会执行,所以我不知道这是否对您有用。在您的实例中,我会在应用程序对象中保留一个活动引用计数器(+1表示每个onResume(),-1表示每个活动的onPause()。使用此选项,您可以检查用户是否具有活动UI。通常,如果您按下最后一个接近“关闭”应用程序范例的活动。然后从应用程序对象(这可能是最后一个获得gc的对象)开始执行任务,或者如果这不起作用,请尝试一个未绑定的服务您可以生成的最不耦合的组件


另一个非常糟糕的解决方案是重写对象(例如,您的活动)中的finalize()方法。使用它的理由非常少,因为它会触发一个额外的gc循环,并且您的代码将在主线程上运行,但是如果对象即将被gc’ed,它是一种执行代码的方法。因此android团队不鼓励使用它,只有当你头上有枪的时候才可以使用它。

你可以通过扩展应用程序类并重写onTerminate()onDestroy()onLowMemory()之类的东西来做到这一点。我也尝试过,但我忘了在帖子中提到它。我已经在底部完成了,请参见编辑部分。