Android可保活的、不依附于应用进程存活的后台任务框架:WorkManager

Android可保活的、不依附于应用进程存活的后台任务框架:WorkManager

WorkManager旨在实现不依附与App进程的后台线程化任务。举例来说,假设App在本地有一个大小约2GB的文件需要上传到远程服务器。App希望在手机空闲且设备资源充足的情况下将这2GB大小的文件上传。
同时,该上传任务不受App进程存活与否影响(比如当前App进程被kill掉,仍能执行该任务)。这种类型的后台任务明显区别于过往的依附于App进程的Thread线程池一类的耗时任务。WorkManager实现的,是独立的、不依附于App进程的真正的后台耗时任务。
在过往,常规实现的Android后台任务(service,线程等),很容易受到寄宿的App进程情况影响,影响主要来自于无法保证寄宿的App进程一定存活。

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;

import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    static final String TIME = "time";
    static final String DATA = "data";
    static final String ID = "id";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        test();
    }

    private void test() {
        String TAG = "tag";

        OneTimeWorkRequest a = getRequest(TAG, 1000, "A", TestWorker.class);
        OneTimeWorkRequest b = getRequest(TAG, 2000, "B", TestWorker.class);
        OneTimeWorkRequest c = getRequest(TAG, 3000, "C", TestWorker.class);
        OneTimeWorkRequest d = getRequest(TAG, 4000, "D", TestWorker.class);

        WorkManager.getInstance(this)
                .enqueue(Arrays.asList(a, b, c, d));

        LiveData<List<WorkInfo>> liveData = WorkManager.getInstance(this).getWorkInfosByTagLiveData(TAG);
        liveData.observe(this, new Observer<List<WorkInfo>>() {
            @Override
            public void onChanged(List<WorkInfo> workInfos) {
                System.out.println("长度:" + workInfos.size());

                for (WorkInfo info : workInfos) {
                    if (info.getState() == WorkInfo.State.SUCCEEDED) {
                        Data data = info.getOutputData();

                        String s = data.getString(DATA);
                        Long time = data.getLong(TIME, -1);
                        String id = data.getString(ID);

                        System.out.println("onChanged:" + id + " " + s + " " + time);
                    }
                }
            }
        });

        System.out.println("UI Main线程Id:" + Thread.currentThread().getId());

        //取消任务。
        //UUID workId = workRequest.getId();
        //WorkManager.getInstance().cancelByWorkId(workId);
    }

    private OneTimeWorkRequest getRequest(String tag, int time, String id, Class cls) {
        //传递的参数数据。
        Data data = new Data.Builder()
                .putInt(TIME, time)
                .putString(ID, id)
                .putString(DATA, "phil " + id)
                .build();

        Constraints constraints = new Constraints.Builder()//触发规则。
                .setRequiresStorageNotLow(false)
                .setRequiresBatteryNotLow(false)
                .setRequiresCharging(false)
                .setRequiredNetworkType(NetworkType.NOT_REQUIRED)//对络连接不做要求。
                .build();

        OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(cls)
                .setInputData(data)
                .setConstraints(constraints)
                .addTag(tag)
                .build();

        return request;
    }
}

 

package zhangphil.demo;

import android.content.Context;
import android.os.SystemClock;

import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class TestWorker extends Worker {

    private String id;
    private int time;

    public TestWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);

        Data data = workerParams.getInputData();
        time = data.getInt(MainActivity.TIME, -1);
        id = data.getString(MainActivity.ID);
        String content = data.getString(MainActivity.DATA);

        System.out.println("Worker:传入数据->id:" + id + " time:" + time + " data:" + content);
    }

    /**
     * doWork()函数体已经线程化。
     *
     * @return
     */
    @NonNull
    @Override
    public Result doWork() {
        //模拟耗时操作。
        SystemClock.sleep(time);

        System.out.println("doWork:" + id + "-线程Id:" + Thread.currentThread().getId() + " 完成");

        //传输数据给外部监听者。
        Data data = new Data.Builder()
                .putString(MainActivity.ID, id)
                .putString(MainActivity.DATA, "数据回传")
                .putLong(MainActivity.TIME, System.currentTimeMillis())
                .build();

        return Result.success(data);
    }

    @Override
    public void onStopped() {
        super.onStopped();
    }
}

 

输出:

15477-15477/? I/System.out: UI Main线程Id:2
15477-15498/? I/System.out: Worker:传入数据->id:A time:1000 data:phil A
15477-15496/? I/System.out: Worker:传入数据->id:B time:2000 data:phil B
15477-15498/? I/System.out: Worker:传入数据->id:C time:3000 data:phil C
15477-15493/? I/System.out: Worker:传入数据->id:D time:4000 data:phil D
15477-15477/? I/System.out: 长度:4
15477-15477/? I/System.out: 长度:4
15477-15502/zhangphil.app I/System.out: doWork:A-线程Id:609 完成
15477-15477/zhangphil.app I/System.out: 长度:4
15477-15477/zhangphil.app I/System.out: onChanged:A 数据回传 1561542140123
15477-15503/zhangphil.app I/System.out: doWork:B-线程Id:610 完成
15477-15477/zhangphil.app I/System.out: 长度:4
15477-15477/zhangphil.app I/System.out: onChanged:B 数据回传 1561542141126
15477-15477/zhangphil.app I/System.out: onChanged:A 数据回传 1561542140123
15477-15505/zhangphil.app I/System.out: doWork:C-线程Id:611 完成
15477-15477/zhangphil.app I/System.out: 长度:4
15477-15477/zhangphil.app I/System.out: onChanged:C 数据回传 1561542142127
15477-15477/zhangphil.app I/System.out: onChanged:B 数据回传 1561542141126
15477-15477/zhangphil.app I/System.out: onChanged:A 数据回传 1561542140123
15477-15502/zhangphil.app I/System.out: doWork:D-线程Id:609 完成
15477-15477/zhangphil.app I/System.out: 长度:4
15477-15477/zhangphil.app I/System.out: onChanged:C 数据回传 1561542142127
15477-15477/zhangphil.app I/System.out: onChanged:B 数据回传 1561542141126
15477-15477/zhangphil.app I/System.out: onChanged:A 数据回传 1561542140123
15477-15477/zhangphil.app I/System.out: onChanged:D 数据回传 1561542144125

 

注意:本例基于WorkManager版本 2.1.0-beta02

implementation "androidx.work:work-runtime:2.1.0-beta02"

经验证发现,如果把a,b,c,d四个任务以任务链的形式组合任务,即使用WorkManager的beginWith-then设计任务链,至少存在一个问题:
在WorkManager构建阶段,通过setInputData传递给Worker的数据只有第一个任务可以成功,后面的传递失败。
具体原因不明,可能是Android官方还没有形成稳定的正式版。

 

附:

《Android体系架构:WorkManager》https://zhangphil.blog.csdn.net/article/details/89399972

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangphil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值