如何在Android应用关闭/设置为后台时执行后台任务?

时间:2016-09-15 09:26:54

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

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

在iOS下这很容易:

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

如何在Android上执行此操作?

第一个问题是,没有任何内容等同于applicationDidEnterBackground:。到目前为止,我发现的所有解决方案都建议使用主要的onPause()方法。但是,这会在主Activity暂停时调用,在应用程序中启动另一个Activity的情况也是如此。对于来自onActivityPaused()接口的ActivityLifecycleCallbacks方法,情况属实。

那么,如何检测应用(不仅仅是Activity)已关闭或发送到后台?

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

AsyncTask将启动一项新任务,但当应用关闭/停用时,此任务是否也会运行?我需要做什么,以防止应用程序和任务在几秒钟后被暂停?在应用程序完全暂停之前,如何确保任务可以完成?

4 个答案:

答案 0 :(得分:17)

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

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

快乐编码!!!!

答案 1 :(得分:3)

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

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

Here是官方链接,您可以使用无限制服务来实现您想要达到的目标。

答案 2 :(得分:2)

接受的答案不正确。

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

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

在复制粘贴任何内容之前都要三思而后行...

答案 3 :(得分:-1)

对于后台操作,您可以使用WorkManager