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

And*_*ord 18 android background-process android-lifecycle android-asynctask

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

在iOS下这很容易:

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

如何在Android上执行此操作?

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

那么,如何检测应用程序(不只是一个Activity)是关闭还是发送到后台?

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

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

Anj*_*ali 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;
    }

}
Run Code Online (Sandbox Code Playgroud)

我的代码的更多解释是:

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

服务以粘性方式启动,即使由于任何原因您的服务在后台被销毁,它也会自动重新启动.

有关详细信息,请访问: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();
Run Code Online (Sandbox Code Playgroud)

快乐的编码!!!!

  • 完毕!感谢您花费一些时间让初学者更容易理解答案! (2认同)

Ser*_*kov 9

接受的答案不正确。

不幸的是,作者认为将新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;
}
Run Code Online (Sandbox Code Playgroud)

onStartCommand()回调总是在主线程上调用,新Handler()线程附加到当前线程(即“主”)。所以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;
}
Run Code Online (Sandbox Code Playgroud)

在复制粘贴任何东西之前先想想自己......