亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android WorkManager使用以及源碼分析

 更新時間:2023年02月13日 10:36:52   作者:眾少成多積小致巨  
WorkManager 是適合用于持久性工作的推薦解決方案。如果工作始終要通過應(yīng)用重啟和系統(tǒng)重新啟動來調(diào)度,便是持久性的工作。本文主要介紹了Android WorkManager的使用,需要的可以參考一下

1、前言

WorkManager 是適合用于持久性工作的推薦解決方案。如果工作始終要通過應(yīng)用重啟和系統(tǒng)重新啟動來調(diào)度,便是持久性的工作。由于大多數(shù)后臺處理操作都是通過持久性工作完成的,因此 WorkManager 是適用于后臺處理操作的主要推薦 API。 WorkManager 可處理三種類型的持久性工作:

  • 立即執(zhí)行:必須立即開始且很快就完成的任務(wù),可以加急。
  • 長時間運行:運行時間可能較長(有可能超過 10 分鐘)的任務(wù)。
  • 可延期執(zhí)行:延期開始并且可以定期運行的預(yù)定任務(wù)。

2、使用

2.1、引用

implementation "androidx.work:work-runtime:2.7.1" //基礎(chǔ)使用
implementation "androidx.work:work-multiprocess:2.7.1" //跨進程時引用

2.2 使用

執(zhí)行一次性任務(wù)

Data data = new Data.Builder().putBoolean("is_test", false).build();
WorkManager.getInstance(this).enqueue(
        new OneTimeWorkRequest.Builder(Test.class) // 執(zhí)行任務(wù)一次性任務(wù)
                .setInputMerger(NewInputMerge.class) // 輸入數(shù)據(jù)合并策略,這里并沒有用,鏈式處理時,多個上流執(zhí)行結(jié)果合并,作為下流輸入數(shù)據(jù)
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 5, TimeUnit.MINUTES) // 重試策略
                .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) // 加急處理
                .addTag("test").addTag("huahua") // 標識
                .setInputData(data) // 輸入數(shù)據(jù)
                .setInitialDelay(5, TimeUnit.SECONDS) // 執(zhí)行延時時間
                .setConstraints(new Constraints.Builder().setRequiresBatteryNotLow(true).build()) // 約束,部分約束只對高版本有效
                .build()
);

執(zhí)行周期性任務(wù)

WorkManager.getInstance(this).enqueue(
        new PeriodicWorkRequest.Builder(Test.class, 2, TimeUnit.HOURS) // 執(zhí)行周期性任務(wù),周期2小時
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 5, TimeUnit.MINUTES)
                .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
                .addTag("test").addTag("huahua")
                .setInputData(data)
                .setInitialDelay(5, TimeUnit.SECONDS) // 首次執(zhí)行延時時間
                .setConstraints(new Constraints.Builder().setRequiresBatteryNotLow(true).build())
                .build()
);

擁有名字的任務(wù)

WorkManager.getInstance(this).enqueueUniqueWork("test", ExistingWorkPolicy.KEEP,
        new OneTimeWorkRequest.Builder(Test.class).build()); // 此種方法會對重復(fù)名字的任務(wù)進行處理

監(jiān)聽狀態(tài)

WorkManager.getInstance(this).getWorkInfosByTagLiveData("test").observe(this, 
        new Observer<List<WorkInfo>>() {
            @Override
            public void onChanged(List<WorkInfo> workInfos) {

            }
        });

定義Work代碼

public class Test extends Worker {
    public Test(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
        Data input = getInputData(); // 獲取輸入數(shù)據(jù)
        boolean isTest = input.getBoolean("is_test", true);
    }

    @NonNull
    @Override
    public Result doWork() {
        return Result.success();
    }
}

繼承使Worker類,實現(xiàn)doWork()方法,此方法是實現(xiàn)任務(wù)的主體;doWork()返回的 Result會通知 WorkManager 服務(wù)工作是否成功,以及工作失敗時是否應(yīng)重試工作。

  • Result.success():工作成功完成。
  • Result.failure():工作失敗。
  • Result.retry():工作失敗,應(yīng)根據(jù)其重試政策在其他時間嘗試。

配置初始化 不同的版本初始化不同,但是都是通過Provider來進行的,2.6之前是WorkManagerInitializer, 2.6之后是InitializationProvider;這里按照2.7.1的版本來說,老版本有需要留言回復(fù);有兩種處理方案

  • 移除默認Provider
  • 按照Provider流程來進行

按照提供初始化流程處理

1.首先注意一個字符串配置:這個很重要,不建議修改

<string name="androidx_startup" translatable="false">androidx.startup</string>

2.提供實現(xiàn)Initializer的類,這個類是被調(diào)用的關(guān)鍵

3.移除默認實現(xiàn)

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data
        android:name="androidx.work.WorkManagerInitializer"
        android:value="androidx.startup"
        tools:node="remove" /> // 這表示移除
</provider>

默認實現(xiàn)Initializer類WorkManagerInitializer,使用的默認configuration

public final class WorkManagerInitializer implements Initializer<WorkManager> {

    private static final String TAG = Logger.tagWithPrefix("WrkMgrInitializer");

    @NonNull
    @Override
    public WorkManager create(@NonNull Context context) {
        Logger.get().debug(TAG, "Initializing WorkManager with default configuration.");
        WorkManager.initialize(context, new Configuration.Builder().build()); // 這里提供Configuration
        return WorkManager.getInstance(context);
    }

    @NonNull
    @Override
    public List<Class<? extends androidx.startup.Initializer<?>>> dependencies() {
        return Collections.emptyList(); // 提供需要執(zhí)行的其它Initializer
    }
}

4.進行注冊自定義實現(xiàn); 在meta-data數(shù)據(jù)處理,key為你需要調(diào)用的初始化類,value必須為R.sting.androidx_startup這個字符串的值; 如下

<provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge" >
        <meta-data
            android:name="androidx.work.WorkManagerInitializer" // 這里為你的實現(xiàn)的Initializer
            android:value="androidx.startup" /> // 這里必須與R.sting.androidx_startup保持一致
    </provider>

2.3 重要概念

任務(wù)標識

  • id : 通過WorkRequest對象getStringId獲取,每次添加一次任務(wù),就會得到唯一的id
  • name :任務(wù)名字,暫時一次性任務(wù)才可以有; 一個任務(wù)最多一個名字,而一個名字可以對應(yīng)多個任務(wù); 同名字任務(wù)可以通過定義不同名字沖突來解決
  • tag: 一個任務(wù)可以擁有多個tag,一個tag可以對應(yīng)多個任務(wù)

任務(wù)類型

  • 一次性任務(wù): 僅僅執(zhí)行一次, 如果結(jié)果返回retry時,按照重試退避政策,進行重試,直至成功
  • 周期性任務(wù): 按照周期執(zhí)行,無論結(jié)果返回什么情況,每次周期內(nèi)僅僅執(zhí)行一次

任務(wù)鏈

使用 WorkManager 創(chuàng)建工作鏈并將其加入隊列。工作鏈用于指定多個依存任務(wù)并定義這些任務(wù)的運行順序。使用 WorkManager.beginWith(OneTimeWorkRequest 或 WorkManager.beginWith(List)返回WorkContinuation實例,然后通過其 then(OneTimeWorkRequest)或 then(List)添加任務(wù)鏈,最后使用WorkContinuation.enqueue()進行執(zhí)行。

任務(wù)鏈先添加的任務(wù)為后續(xù)任務(wù)的先決條件, 也就是前面任務(wù)成功了后面任務(wù)才會執(zhí)行

重試退避政策

針對worker執(zhí)行返回Result.retry()時處理策略, 使用方法setBackoffCriteria設(shè)置, 有兩個指標,策略和延時時間(允許的最小值,即 10 秒);情況有下面2種

  • 線性LINEAR: 每次失敗后重新開啟任務(wù)時間延時為 延時時間次數(shù)倍(延時時間 * n)
  • EXPONENTIAL: 每次失敗后重新開啟任務(wù)時間延時為 延時時間的指數(shù)倍(延時時間 * 2^n)

輸入合并器

針對一次性任務(wù),且在工作鏈中,父級工作請求的輸出將作為子級的輸入傳入的場景中使用。輸入中會存在相同關(guān)鍵字,這時,輸入就會存在沖突

WorkManager 提供兩種不同類型的 InputMerger:

  • OverwritingInputMerger:會嘗試將所有輸入中的所有鍵添加到輸出中。如果發(fā)生沖突,它會覆蓋先前設(shè)置的鍵。
  • ArrayCreatingInputMerger: 會嘗試合并輸入,并在必要時創(chuàng)建數(shù)組。

沖突解決政策

調(diào)度唯一工作時,發(fā)生沖突時要執(zhí)行的操作??梢酝ㄟ^在將工作加入隊列時傳遞一個枚舉來實現(xiàn)此目的。

對于一次性工作,您需要提供一個 ExistingWorkPolicy,有4 個選項。

  • REPLACE:用新工作替換現(xiàn)有工作。此選項將取消現(xiàn)有工作。
  • KEEP:保留現(xiàn)有工作,并忽略新工作。
  • APPEND:將新工作附加到現(xiàn)有工作的末尾。此政策將導(dǎo)致您的新工作到現(xiàn)有工作,在現(xiàn)有工作完成后運行。 現(xiàn)有工作將成為新工作的先決條件。如果現(xiàn)有工作變?yōu)?nbsp;CANCELLED 或 FAILED 狀態(tài),新工作也會變?yōu)?nbsp;CANCELLED 或 FAILED。如果您希望無論現(xiàn)有工作的狀態(tài)如何都運行新工作,請改用 APPEND_OR_REPLACE
  • APPEND_OR_REPLACE: 類似于 APPEND,不過它并不依賴于先決條件工作狀態(tài)。**即使現(xiàn)有工作變?yōu)?nbsp;CANCELLED 或 FAILED 狀態(tài),新工作仍會運行。

約束條件

任務(wù)執(zhí)行的先決條件,使用Contraints.Builder()進行構(gòu)建實例。有一下約束

  • NetworkType : 約束運行工作所需的網(wǎng)絡(luò)類型。
  • BatteryNotLow : 如果設(shè)置為 true,那么當設(shè)備處于“電量不足模式”時,工作不會運行。
  • RequiresCharging : 如果設(shè)置為 true,那么工作只能在設(shè)備充電時運行。
  • DeviceIdle:如果設(shè)置為 true,則要求用戶的設(shè)備必須處于空閑狀態(tài),才能運行工作。在運行批量操作時,此約束會非常有用;若是不用此約束,批量操作可能會降低用戶設(shè)備上正在積極運行的其他應(yīng)用的性能。
  • StorageNotLow: 如果設(shè)置為 true,那么當用戶設(shè)備上的存儲空間不足時,工作不會運行。

還有以下約束,對于>=24的版本有效:

  • setContentUriTriggers方法: 設(shè)置觸發(fā)任務(wù)的uri
  • setTriggerContentUpdateDelay方法:設(shè)置觸發(fā)執(zhí)行的延遲時間
  • setTriggerMaxContentDelay方法:設(shè)置處罰執(zhí)行的最大延時

3、原理

合理分為幾個部分來說

  • 1. 約束檢測: 約束檢測的邏輯以及實現(xiàn)
  • 2. 任務(wù)調(diào)度: 3種調(diào)度器, alarm、greedy、JobScheduler; 用于喚起任務(wù)執(zhí)行
  • 3. 任務(wù)執(zhí)行流程 :請求的包裝,任務(wù)如何加入調(diào)度器,以及調(diào)度完成后執(zhí)行任務(wù)詳情

這里有需要理解的一個技術(shù)點:SettableFuture,實現(xiàn)了ListenableFuture接口,并且增加了下面接口ListenableFuture。這個類在源碼中頻繁使用

ListenableFuture只有一個方法

void addListener(Runnable listener, Executor executor)

調(diào)用了這個方法,這個類才有使用意義;調(diào)用之后,表示SettableFuture若完成,則使用executor執(zhí)行l(wèi)istener

另外一個讓我覺得有意思的地方,或者說不同之前future的地方是, SettableFuture未實現(xiàn)Runnable接口,也就是其結(jié)果不是來源于自己,來源于調(diào)用下面3個方法

    public boolean set(@Nullable V value) // 正常設(shè)置結(jié)果

    public boolean setException(Throwable throwable) // 執(zhí)行結(jié)果異常

    public boolean setFuture(ListenableFuture<? extends V> future) // 設(shè)置執(zhí)行結(jié)果來源,也就是ListenableFuture的執(zhí)行結(jié)果

3.1 約束檢測

類圖如下

結(jié)合源碼分析,結(jié)論有:

  • WorkConstraintsTracker類:使用入口,構(gòu)造器傳入WorkConstraintsCallback為結(jié)果回調(diào),也可以直接調(diào)用方法areAllConstraintsMet來判斷是否滿足約束
  • ConstraintController類:一種約束控制器類,通過OnConstraintUpdatedCallback回調(diào)實時結(jié)果給WorkConstraintsTracker, 通過ConstraintListener與ConstraintTracker聯(lián)系
  • ConstraintTracker:實際約束值的檢測者,ConstraintListener回調(diào)實時傳遞值與ConstraintController;通過setState觸發(fā)回調(diào)

實際檢測技術(shù)點,也就是ConstraintTracker實現(xiàn)

3.1.1 StorageNotLowTracker類

存儲空間的是否低,根據(jù)系統(tǒng)廣播來處理

Intent.ACTION_DEVICE_STORAGE_OK // 存儲空間夠用
Intent.ACTION_DEVICE_STORAGE_LOW // 存儲空間很低

初步檢測狀態(tài):

@Override
public Boolean getInitialState() {
    Intent intent = mAppContext.registerReceiver(null, getIntentFilter());
    if (intent == null || intent.getAction() == null) {
        return true;
    } else {
        switch (intent.getAction()) {
            case Intent.ACTION_DEVICE_STORAGE_OK:
                return true;
            case Intent.ACTION_DEVICE_STORAGE_LOW:
                return false;
            default:
                return null;
        }
    }
}

實時更新通過接收廣播信息:

public void onBroadcastReceive(Context context, @NonNull Intent intent) {
    if (intent.getAction() == null) {
        return;
    }

    switch (intent.getAction()) {
        case Intent.ACTION_DEVICE_STORAGE_OK:
            setState(true);
            break;
        case Intent.ACTION_DEVICE_STORAGE_LOW:
            setState(false);
            break;
    }
}

3.1.2 BatteryChargingTracker類

充電狀態(tài),同樣通過廣播來進行處理;

接收廣播根據(jù)版本不同而不同如下:

    public IntentFilter getIntentFilter() {
        IntentFilter intentFilter = new IntentFilter();
        if (Build.VERSION.SDK_INT >= 23) {
            intentFilter.addAction(BatteryManager.ACTION_CHARGING);
            intentFilter.addAction(BatteryManager.ACTION_DISCHARGING);
        } else {
            intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
            intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
        }
        return intentFilter;
    }

初始狀態(tài):

    @Override
    public Boolean getInitialState() {
        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent intent = mAppContext.registerReceiver(null, intentFilter);
        if (intent == null) {
            Logger.get().error(TAG, "getInitialState - null intent received");
            return null;
        }
        return isBatteryChangedIntentCharging(intent);
    }
    
    private boolean isBatteryChangedIntentCharging(Intent intent) {
        boolean charging;
        if (Build.VERSION.SDK_INT >= 23) {
            int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
            charging = (status == BatteryManager.BATTERY_STATUS_CHARGING
                    || status == BatteryManager.BATTERY_STATUS_FULL);
        } else {
            int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
            charging = (chargePlug != 0);
        }
        return charging;
    }

實時狀態(tài):

@Override
public void onBroadcastReceive(Context context, @NonNull Intent intent) {
    String action = intent.getAction();
    if (action == null) {
        return;
    }
    Logger.get().debug(TAG, String.format("Received %s", action));
    switch (action) {
        case BatteryManager.ACTION_CHARGING:
            setState(true);
            break;
        case BatteryManager.ACTION_DISCHARGING:
            setState(false);
            break;
        case Intent.ACTION_POWER_CONNECTED:
            setState(true);
            break;
        case Intent.ACTION_POWER_DISCONNECTED:
            setState(false);
            break;
    }
}

3.1.3 BatteryNotLowTracker類

電量是否低,同樣通過廣播實時獲取狀態(tài)

    Intent.ACTION_BATTERY_OKAY //電量正常
    Intent.ACTION_BATTERY_LOW //電量低

初始狀態(tài):

    @Override
    public Boolean getInitialState() {
        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent intent = mAppContext.registerReceiver(null, intentFilter);
        if (intent == null) {
            Logger.get().error(TAG, "getInitialState - null intent received");
            return null;
        }

        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
        float batteryPercentage = level / (float) scale;

        return (status == BatteryManager.BATTERY_STATUS_UNKNOWN
                || batteryPercentage > BATTERY_LOW_THRESHOLD); // 這里是小于15%算是低
    }

實時更新:

    @Override
    public void onBroadcastReceive(Context context, @NonNull Intent intent) {
        if (intent.getAction() == null) {
            return;
        }
        Logger.get().debug(TAG, String.format("Received %s", intent.getAction()));
        switch (intent.getAction()) {
            case Intent.ACTION_BATTERY_OKAY:
                setState(true);
                break;
            case Intent.ACTION_BATTERY_LOW:
                setState(false);
                break;
        }
    }

3.1.4 NetworkStateTracker類

網(wǎng)絡(luò)狀態(tài),這個根據(jù)版本不同使用也不同

  • 大于等于24時, ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback networkCallback) 來進行監(jiān)聽網(wǎng)絡(luò)狀態(tài)變化
  • 小于24時,通過廣播ConnectivityManager.CONNECTIVITY_ACTION來進行處理

初始狀態(tài):

NetworkState getActiveNetworkState() {
    NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
    boolean isConnected = info != null && info.isConnected();
    boolean isValidated = isActiveNetworkValidated();
    boolean isMetered = ConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager);
    boolean isNotRoaming = info != null && !info.isRoaming();
    return new NetworkState(isConnected, isValidated, isMetered, isNotRoaming);
}          

實時狀態(tài): 在回調(diào)NetworkCallback或者接收到廣播onReceive時,調(diào)用getActiveNetworkState得到

3.2 任務(wù)調(diào)度器

實現(xiàn)Scheduler接口,調(diào)度器有3個:

  • SystemJobScheduler: 使用JobSceuler來完成任務(wù)喚起;小于23版本時使用
  • SystemAlarmScheduler: 使用Alarm來完成任務(wù)喚起;大于等于23版本使用
  • GreedyScheduler:在進程內(nèi)直接調(diào)用,不同android版本均會建立 其實還有一個androidx.work.impl.background.gcm.GcmScheduler,這個實現(xiàn)需要借助google的GCM推送服務(wù)來實現(xiàn),這里用了反射(國內(nèi)不支持),并且優(yōu)先于SystemAlarmScheduler

調(diào)度器的創(chuàng)建在WorkManagerImpl類

   public List<Scheduler> createSchedulers(
            @NonNull Context context,
            @NonNull Configuration configuration,
            @NonNull TaskExecutor taskExecutor) {

        return Arrays.asList(
                Schedulers.createBestAvailableBackgroundScheduler(context, this), // 可以被系統(tǒng)喚起調(diào)用手段
                new GreedyScheduler(context, configuration, taskExecutor, this)); // 進程內(nèi)調(diào)用手段
    }

調(diào)度器被調(diào)用的邏輯在Schedulers

public static void schedule(Configuration configuration,WorkDatabase workDatabase,List<Scheduler> schedulers) {
        if (schedulers == null || schedulers.size() == 0) {
            return;
        }
        WorkSpecDao workSpecDao = workDatabase.workSpecDao();
        List<WorkSpec> eligibleWorkSpecsForLimitedSlots;
        List<WorkSpec> allEligibleWorkSpecs;
        workDatabase.beginTransaction();
        try {
            eligibleWorkSpecsForLimitedSlots = workSpecDao.getEligibleWorkForScheduling(configuration.getMaxSchedulerLimit()); 
            allEligibleWorkSpecs = workSpecDao.getAllEligibleWorkSpecsForScheduling(MAX_GREEDY_SCHEDULER_LIMIT);

            if (eligibleWorkSpecsForLimitedSlots != null && eligibleWorkSpecsForLimitedSlots.size() > 0) {
                long now = System.currentTimeMillis();
                for (WorkSpec workSpec : eligibleWorkSpecsForLimitedSlots) {
                    workSpecDao.markWorkSpecScheduled(workSpec.id, now); // 進行插槽狀態(tài)處理,非默認才會被GreedyScheduler進行調(diào)度
                }
            }
            workDatabase.setTransactionSuccessful();
        } finally {
            workDatabase.endTransaction();
        }

        if (eligibleWorkSpecsForLimitedSlots != null && eligibleWorkSpecsForLimitedSlots.size() > 0) {
            WorkSpec[] eligibleWorkSpecsArray =
                    new WorkSpec[eligibleWorkSpecsForLimitedSlots.size()];
            eligibleWorkSpecsArray =
                    eligibleWorkSpecsForLimitedSlots.toArray(eligibleWorkSpecsArray);
            for (Scheduler scheduler : schedulers) {
                if (scheduler.hasLimitedSchedulingSlots()) {
                    scheduler.schedule(eligibleWorkSpecsArray);
                }
            }
        }

        if (allEligibleWorkSpecs != null && allEligibleWorkSpecs.size() > 0) {
            WorkSpec[] enqueuedWorkSpecsArray = new WorkSpec[allEligibleWorkSpecs.size()];
            enqueuedWorkSpecsArray = allEligibleWorkSpecs.toArray(enqueuedWorkSpecsArray);
            for (Scheduler scheduler : schedulers) {
                if (!scheduler.hasLimitedSchedulingSlots()) {
                    scheduler.schedule(enqueuedWorkSpecsArray);
                }
            }
        }
    }

GreedyScheduler調(diào)度器處理任務(wù)正在排隊,任務(wù)最大限制是200條;其它調(diào)度器執(zhí)行在排隊且未被調(diào)度器處理的,且和現(xiàn)在調(diào)度器已經(jīng)處理的總和不超過配置中的最大限制,默認是版本23是10,其它版本20

3.2.1 GreedyScheduler調(diào)度器

類圖:

通過流程分析有以下結(jié)論:

  • 延時通過DelayedWorkTracker來處理,其實是通過Handler機制處理,在主Handler中進行
  • 約束通過WorkConstraintsTracker來進行檢測,通過自身實現(xiàn)回調(diào)WorkConstraintsCallback來處理
  • 滿足執(zhí)行條件的任務(wù),通過WorkManagerImpl進行執(zhí)行
  • 實現(xiàn)ExecutionListener接口,來檢測已經(jīng)完成的任務(wù),避免重復(fù)執(zhí)行
  • 必須在配置的進程中處理,默認為應(yīng)用主進程

3.2.2 SystemJobScheduler調(diào)度器

類圖:

  • SystemJobInfoConverter進行數(shù)據(jù)轉(zhuǎn)換JobScheduler需要的入?yún)?,以及其它?shù)據(jù)互相轉(zhuǎn)換
  • SystemJobService負責(zé)調(diào)用WorkManagerImpl類方法去執(zhí)行任務(wù);以及任務(wù)執(zhí)行完成的處理
  • 約束由JobScheduler自己內(nèi)部進行;而這里只需要調(diào)用方法即可

這個調(diào)度器比較簡單,其實現(xiàn)主要通過了JobScheduler的實現(xiàn),JobScheduler的實現(xiàn)原理這里不做介紹

3.2.3 SystemAlarmScheduler調(diào)度器

這個調(diào)度器實現(xiàn)就比較復(fù)雜了;類圖:

  • SystemAlarmService服務(wù),任務(wù)各種情況通過啟動此服務(wù)來處理
  • SystemAlarmDispatcher, 任務(wù)各種情況分發(fā)處理節(jié)點,并回傳無任務(wù)處理情況,銷毀服務(wù)
  • CommandHander具體處理各種intent事件,以及內(nèi)部任務(wù)調(diào)度完成后收尾(實現(xiàn)了ExecutionListener接口,其意義卻不是任務(wù)已經(jīng)執(zhí)行完成后的處理)
  • ConstraintsCommandHandler:處理了約束情況,使用WorkConstraintsTracker檢測當時狀態(tài);事件是由*Proxy類廣播啟動service進而通知的, ConstraintProxyUpdateReceiver控制各種約束廣播是否可用
  • Alarms,使用AlramManager機制處理任務(wù)延時,并啟動服務(wù)
  • RescheduleReceiver:開機或者時間事件廣播,重啟動WorkManager處理剩余任務(wù)的;這里只有靜態(tài)注冊,非所有版本有效
  • DelayMetCommandHandler:進行約束實時更新判斷,并在滿足執(zhí)行時通過WorkManagerImpl執(zhí)行任務(wù);在類圖中沒有表明其實現(xiàn)了WorkTimer.TimeLimitExceededListener(這個是對任務(wù)從調(diào)度狀態(tài)到運行狀態(tài)的一個控制,10分鐘未完成狀態(tài)變化重新處理)
  • 使用了PowerManager.WakeLock保證調(diào)度過程中cpu運行

3.3、任務(wù)流程

任務(wù)流程涉及調(diào)度的具體過程,在以下流程圖中就會直接從Schedulers方法直接異步執(zhí)行啟動任務(wù);調(diào)度過程省略;

3.3.1 enqueue流程

WorkManager調(diào)用時,均是先包裝成WorkContinuationImpl然后調(diào)用其方法enqueue執(zhí)行;

WorkContinuationImpl: 包含了一個鏈表,指向了所有依賴的WorkContinuation對象;也記錄了任務(wù)本身的一些信息和流程狀態(tài)

流程圖

  • WorkerWrapper:handleResult方法后續(xù)是對不同結(jié)果以及任務(wù)類別,對任務(wù)數(shù)據(jù)進行相應(yīng)處理;其中進行了輸入數(shù)據(jù)的合并;在執(zhí)行中多個關(guān)鍵點對取消進行校驗處理
  • WorkForegroundRunnable:啟動前臺服務(wù),這個需要在實現(xiàn)Work中提供通知信息(方法getForegroundInfoAsync);如果有加急處理,也是啟動前臺服務(wù)
  • ListenableWorker中,通過setProgressAsync可以設(shè)置進度數(shù)據(jù);成功時,doWork返回的結(jié)果中含有成功數(shù)據(jù)
  • EnqueueRunnable:enqueueWorkWithPrerequisites方法中對重復(fù)任務(wù)依據(jù)策略進行了處理
  • CancelWorkRunable:iterativelyCancelWorkAndDependents刪除了依賴其的任務(wù)
  • 中間大量使用SettableFuture來讓各個Runnable執(zhí)行等待其執(zhí)行的先決條件

3.3.2 cancel流程

取消時,可以通過任務(wù)的id、name、tag或者取消所有;不管是哪種調(diào)用,都是通過標識獲取滿足條件的任務(wù)id集合,并進行取消;其流程也只是在id集合查詢時不同而已

流程圖

  • WorkWrapper進行打斷時,其流程也就是任務(wù)執(zhí)行時打斷處理,在執(zhí)行過程中多處對打斷進行了檢測處理
  • 取消時,對調(diào)度、執(zhí)行中的任務(wù)分別進行取消;同時同步狀態(tài)到數(shù)據(jù)庫

4、總結(jié)

上面只是大概介紹了常規(guī)使用,以及相關(guān)類圖、流程,代碼細節(jié)并沒有展示。代碼中的一些技術(shù)點需要至少會用

  • AlarmMananger
  • JobScheduler
  • 電量低、內(nèi)存不足、充電狀態(tài)、網(wǎng)絡(luò)狀態(tài)檢測以及實時更新
  • SettableFuture
  • ......

從代碼架構(gòu)上,也有需要去多思考的地方

  • 各個部分的分離抽象
  • 廣播、服務(wù)組件的打開關(guān)閉、以及服務(wù)的銷毀、任務(wù)執(zhí)行完畢后的回調(diào)收尾等性能的考量
  • 數(shù)據(jù)庫表的設(shè)計
  • 不論哪個版本,均有兩個調(diào)度器去執(zhí)行任務(wù),他們有可能去處理同一個任務(wù),這帶來的復(fù)雜度處理邏輯以及優(yōu)勢
  • ......

以上就是Android WorkManager使用以及源碼分析的詳細內(nèi)容,更多關(guān)于Android WorkManager的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論