【问题标题】:How to execute background task when Android app is closed / set to background?Android应用程序关闭/设置为后台时如何执行后台任务?
【发布时间】:2016-09-15 09:26:53
【问题描述】:

我的 Android 4+ 应用已连接到自定义网络服务,该服务用于每隔几分钟同步一次数据。为了确保在线数据始终是最新的,我想在应用关闭/发送到后台时触发同步。

在 iOS 下这很容易:

  • 在 AppDelegate 中收听applicationDidEnterBackground:
  • 使用beginBackgroundTaskWithName: 启动长时间运行的后台任务,避免在任务仍在运行时被挂起

如何在 Android 上执行此操作?

第一个问题是,没有任何东西相当于applicationDidEnterBackground:。到目前为止,我发现的所有解决方案都建议使用主要活动 onPause() 方法。然而,这会在主Activity 暂停时调用,在应用程序中启动另一个Activity 时也是如此。 ActivityLifecycleCallbacks 接口中的 onActivityPaused() 方法也是如此。

那么,如何检测app(不仅仅是Activity)是关闭还是发送到后台?

第二个问题是,我没有找到任何关于如何运行后台任务的信息。所有解决方案都指向简单地启动AsyncTask,但这真的是正确的解决方案吗?

AsyncTask 将启动一个新任务,但是当应用程序关闭/非活动时,此任务也会运行吗?我该怎么做才能防止应用程序和任务在几秒钟后暂停?如何确保在应用完全挂起之前任务可以完成?

【问题讨论】:

  • 您可以为此使用服务
  • 你考虑过服务吗?
  • 感谢您对服务的提示。我会检查一下。为什么投反对票?如果问题有问题,请告诉我,以便我改进。没有任何评论的否决票不是很有帮助。

标签: android android-asynctask background-process android-lifecycle


【解决方案1】:

以下代码将帮助您在应用关闭或在后台发布内容:

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;
    }

}

我的代码的更多解释是:

即使您的应用程序在后台,服务也会在后台运行,但请记住,它始终在主线程上运行,因此我创建了一个单独的线程来执行您的后台操作。

服务以粘性启动,即使由于任何原因您的服务在后台被破坏,它也会自动重新启动。

更多细节可以在这里找到: https://developer.android.com/guide/components/services.html

要检查您的应用是否在前台/后台,以下代码会有所帮助:

  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();

编码愉快!!!!

【讨论】:

  • 投了反对票,因为只是显示一个没有解释的代码,并期望原始发布者自动理解它,并不总是如此。如果您改进答案,将删除我的反对意见。
  • 完成!感谢您花点时间让初学者更容易理解答案!
  • 你已经使用handler做后台工作了,多久之后handler会被重复的网络调用调用?
  • 非常感谢。 Service 似乎确实是问题 Nr 的完美解决方案。 2.第一个问题呢:如何正确检测到应用被暂停/关闭而不仅仅是一个Activity?
【解决方案2】:

接受的答案不正确。

不幸的是,作者认为向Handler() 发布一个新的Runnable 任务会创建一个单独的线程——“我创建了一个单独的线程来执行你的后台操作”

@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;
}

onStartCommand() 回调总是在主线程上调用,新的Handler() 附加到当前线程(即“main”)。所以Runnable任务被发布在主线程队列的末尾。

要解决此问题并在一个真正独立的线程中执行Runnable,您可以使用AsyncTask 作为最简单的解决方案:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            // ...
        }
    });
    return android.app.Service.START_STICKY;
}

在复制粘贴任何内容之前先想想自己...

【讨论】:

  • 我认为 new Handler() 创建了一个新线程或一些默认线程,但我向您保证,在 new Handler() 中运行的代码不在主线程上运行。因为每当我在新的 Handler runnable 中工作时,我总是会遇到异常。
【解决方案3】:

您可以将服务用于您想要实现的目标。如果您没有调用 stopService(..) 或 stopSelf() 方法,服务将即使活动组件已被销毁也会在后台继续运行

在服务中,您可以进行异步网络调用,最好使用改造,然后您可以使用从您的网络服务获取的最新数据更新您的本地存储,例如 Sqlite DB。

Here是官方链接,你可以使用无限服务来实现你想要的。

【讨论】:

  • 非常感谢。 Service 似乎确实是问题 Nr 的完美解决方案。 2.第一个问题呢:如何正确检测到应用被暂停/关闭而不仅仅是一个Activity?
  • 为此,您可以覆盖活动生命周期方法,如 onPause() 和 onDestroy()。如果您的 Activity 是返回堆栈中的最后一项并且您按下了 android 默认返回按钮,则调用 onDestroy() 并退出您的应用程序。
【解决方案4】:

后台操作可以​​使用WorkManager

【讨论】:

    猜你喜欢
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    相关资源
    最近更新 更多