欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android?JobScheduler詳細介紹

 更新時間:2024年09月13日 11:33:55   作者:輕口味  
JobScheduler是Android?5.0引入的系統(tǒng)服務,它可以根據網絡狀態(tài)、充電狀態(tài)、電量和存儲狀況等來觸發(fā)相應的JobService執(zhí)行任務,它支持多條件組合、持久性任務,以及在API?21以上版本的Android系統(tǒng)中使用,對Android?JobScheduler相關知識感興趣的朋友跟隨小編一起看看吧

Android JobScheduler介紹

介紹

JobScheduler是在Android 5.0添加的,它可以檢測網絡狀態(tài)、設備是否充電中、低電量、低存儲等狀態(tài),當所有條件都滿足時就會觸發(fā)執(zhí)行對應的JobService來完成任務。同時具備了重試、定時執(zhí)行、持久化任務(設備重啟后可恢復任務)等功能??芍^是十分強大
JobScheduler的使用大致分為三步:

  • 創(chuàng)建JobService類
  • 創(chuàng)建一個JobInfo
  • 獲取JobScheduler系統(tǒng)服務執(zhí)行任務

1 創(chuàng)建JobService

JobScheduler的原理大致是是通過監(jiān)聽手機狀態(tài),當條件滿足時啟動Service執(zhí)行任務。
因此在使用JobScheduler之前,我們需要定義一個Service,當然并不是隨隨便便定義,而是需要派生自JobService。
只需要重寫onStopJob和onStartJob即可。

class DemoJobService: JobService() {
    override fun onStartJob(params: JobParameters?): Boolean {
        //do sth...
        //這個返回值是有講究的
        //true表示Service的工作在一個獨立線程中執(zhí)行,工作完成之后需要調用jobFinish方法通知JobScheduler工作完成
        //false表示Service的工作已經完成,JobScheduler收到通知之后會釋放資源
        return false
    }
    //該方法會在一些極端場景下觸發(fā)
    //比如當前的Job需要有Wifi連接的場景下才可執(zhí)行,但是在執(zhí)行期間
    //用戶關閉Wifi,那么就會觸發(fā)該方法
    override fun onStopJob(params: JobParameters?): Boolean {
        //do sth...
        //true表示需要進行重試
        //false表示不再進行重試,Job將會被丟棄
        return true
    }
}

同時,在manifest中注冊時,還需要設置一個權限(否則會報錯),如下

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
    //...
    <service android:name=".DemoJobService" 
             android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>

2 創(chuàng)建JobInfo

JobInfo是對任務的描述,比如說需要監(jiān)聽哪些狀態(tài)、重試策略、任務執(zhí)行時間、是否持久化等等。
JobInfo.Builder的構造函數(shù)需要傳入一個jobId,是Job的唯一標志,后續(xù)通過該jobId來取消Job。
通過Builder模式構造JobInfo。

val jobInfo = JobInfo.Builder(1, ComponentName(packageName, DemoJobService::class.java.name))
    .setBackoffCriteria(1000,JobInfo.BACKOFF_POLICY_LINEAR) //重試機制
    .setMinimumLatency(1000)//設置延遲時間
    .setOverrideDeadline(10000)//設置最后期限,如果達到該時間點,Job還沒被執(zhí)行,那么會強制執(zhí)行一次
//                .setPeriodic(2000)//每隔2s執(zhí)行一次,跟上面兩個會沖突
    .setPersisted(true)//持久化,就算手機關機,啟動之后也可以恢復Job,需要RECEIVE_BOOT_COMPLETED權限
    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)//設置Job依賴的網絡類型
    .setRequiresCharging(false)//是否要求設備處于充電狀態(tài)
    .setRequiresDeviceIdle(false)//是否要求設備處于空閑狀態(tài)
    .build()

JobInfo其他的設置方法:

.setMinimumLatency(5000)//5秒 最小延時、
.setOverrideDeadline(60000)//maximum最多執(zhí)行時間  
 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)//免費的網絡---wifi 藍牙 USB
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)//任意網絡---
  /**
   設置重試/退避策略,當一個任務調度失敗的時候執(zhí)行什么樣的測量采取重試。
    initialBackoffMillis:第一次嘗試重試的等待時間間隔ms
    *backoffPolicy:對應的退避策略。比如等待的間隔呈指數(shù)增長。
    */
  .setBackoffCriteria(long initialBackoffMillis, int backoffPolicy)
.setBackoffCriteria(JobInfo.MAX_BACKOFF_DELAY_MILLIS, JobInfo.BACKOFF_POLICY_LINEAR)
  //.setPeriodic (long intervalMillis)//設置執(zhí)行周期,每隔一段時間間隔任務最多可以執(zhí)行一次。
//.setPeriodic(long intervalMillis,long flexMillis)//在周期執(zhí)行的末端有一個flexMiliis長度的窗口期,任務就可以在這個窗口期執(zhí)行。
 //設置設備重啟后,這個任務是否還要保留。需要權限:  RECEIVE_BOOT_COMPLETED //ctrl+shift+y/u x
//.setPersisted(boolean isPersisted);
// .setRequiresCharging(boolean )//是否需要充電
// .setRequiresDeviceIdle(boolean)//是否需要等設備出于空閑狀態(tài)的時候
// .addTriggerContentUri(uri)//監(jiān)聽uri對應的數(shù)據發(fā)生改變,就會觸發(fā)任務的執(zhí)行。
// .setTriggerContentMaxDelay(long duration)//設置Content發(fā)生變化一直到任務被執(zhí)行中間的最大延遲時間
 //設置Content發(fā)生變化一直到任務被執(zhí)行中間的延遲。如果在這個延遲時間內content發(fā)生了改變,延遲時間會重寫計算。
  // .setTriggerContentUpdateDelay(long durationMilimms)

3 執(zhí)行任務

最后通過getSystemService獲取JobScheduler服務執(zhí)行任務就可以了

//執(zhí)行任務
val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
jobScheduler.schedule(jobInfo)
//取消任務
jobScheduler.cancel(1)

4 最后

JobScheduler上手還是比較簡單的,由于本文是基于api23的源碼,因此還有很多新功能沒有在源碼中展示出來,如setRequiresBatteryNotLow(設置Job對電量的要求)、setRequiresStorageNotLow(設置Job對存儲空間的要求)等.

特性&適用

  • 支持在一個任務上組合多個條件
  • 內置條件:設備待機、設備充電和連接網絡
  • 支持持續(xù)的job,這意味著設備重啟后,之前被中斷的job可以繼續(xù)執(zhí)行
  • 支持設置job的最后執(zhí)行期限
  • 根據你的配置,可以設置job在后臺運行還是在主線程中運行

適用

需要在Android設備滿足某種場合才需要去執(zhí)行處理數(shù)據:

  • 應用具有可以推遲的非面向用戶的工作(定期數(shù)據庫數(shù)據更新)
  • 應用具有當插入設備時希望優(yōu)先執(zhí)行的工作(充電時才希望執(zhí)行的工作備份數(shù)據)
  • 需要訪問網絡或 Wi-Fi 連接時需要進行的任務(如向服務器拉取內置數(shù)據)
  • 希望作為一個批次定期運行的許多任務(s)

特征

  • Job Scheduler只有在Api21或以上的系統(tǒng)支持。
  • Job Scheduler是將多個任務打包在一個場景下執(zhí)行。
  • 在系統(tǒng)重啟以后,任務會依然保留在Job Scheduler當中,因此不需要監(jiān)聽系統(tǒng)啟動狀態(tài)重復設定。
  • 如果在一定期限內還沒有滿足特定執(zhí)行所需情況,Job Scheduler會將這些任務加入隊列,并且隨后會進行執(zhí)行

使用Job Scheduler,應用需要做的事情就是判斷哪些任務是不緊急的,可以交給Job Scheduler來處理,Job Scheduler集中處理收到的任務,選擇合適的時間,合適的網絡,再一起進行執(zhí)行。把時效性不強的工作丟給它做。

源碼分析

JobScheduler是系統(tǒng)服務JobSchedulerService,JobScheduler是一個抽象類;以下是JobScheduler的源碼:

public abstract class JobScheduler {
public static final int RESULT_FAILURE = 0;
public static final int RESULT_SUCCESS = 1;
//這個是提交一個工作任務JobInfo
public abstract int schedule(JobInfo job);
public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag);
 //這個是取消一個工作任務
public abstract void cancel(int jobId);
//這個是取消所有的工作任務
public abstract void cancelAll();
  //得到所有將來要執(zhí)行的工作任務
public abstract @NonNull List<JobInfo> getAllPendingJobs();
//根據Jobid獲得將來要執(zhí)行的工作任務
public abstract @Nullable JobInfo getPendingJob(int jobId);
}

JobScheduler的實現(xiàn)類是JobSchedulerImpl:

public class JobSchedulerImpl extends JobScheduler {
IJobScheduler mBinder;
/* package */ JobSchedulerImpl(IJobScheduler binder) {
    mBinder = binder;
}
@Override
public int schedule(JobInfo job) {
    try {
        //這個mBinder是JobSchedulerService中的IJobScheduler.Stub,
        return mBinder.schedule(job);
    } catch (RemoteException e) {
        return JobScheduler.RESULT_FAILURE;
    }
}
@Override
public void cancel(int jobId) {
    try {
        mBinder.cancel(jobId);
    } catch (RemoteException e) {}
}
@Override
public void cancelAll() {
    try {
        mBinder.cancelAll();
    } catch (RemoteException e) {}
}
@Override
public List<JobInfo> getAllPendingJobs() {
    try {
        return mBinder.getAllPendingJobs();
    } catch (RemoteException e) {
        return null;
    }
}
}

在代碼中 調用mJobScheduler.schedule(job);其實是調了JobScheduler的實現(xiàn)類JobSchedulerImpl中的schedule方法;然后再調了mBinder.schedule(job);這個mBinder就是JobSchedulerService,調用了JobSchedulerService類里面IJobScheduler.Stub內部類的schedule方法; JobSchedulerService是在哪里啟動的呢?先看一下的源碼,從源碼分析JobSchedulerService是一個系統(tǒng)服務;

public class JobSchedulerService extends com.android.server.SystemService
    implements StateChangedListener, JobCompletedListener {
static final boolean DEBUG = false;
/** The number of concurrent jobs we run at one time. */
private static final int MAX_JOB_CONTEXTS_COUNT
        = ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
static final String TAG = "JobSchedulerService";
/** Master list of jobs. */
final JobStore mJobs;
static final int MSG_JOB_EXPIRED = 0;
static final int MSG_CHECK_JOB = 1;
//....省略了n多代碼
}

是系統(tǒng)服務那應該就是在 SystemServer啟動的,先看一下SystemServer的源碼;

public final class SystemServer {
private static final String TAG = "SystemServer";
//手機開機啟動后會走這個main方法,然后調用run方法
public static void main(String[] args) {
    new SystemServer().run();
  }

手機開機啟動會走SystemServer中的主函數(shù)main方法,main方法調用了run方法,下面是run方法中的代碼:

private void run() {
     //....省略了n多代碼
    // Start services.
    //這里啟動一些系統(tǒng)服務
    try {
        startBootstrapServices();
        startCoreServices();
      //會走這個
        startOtherServices();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    }
 //....省略了n多代碼
}

從run方法可以看出,這里啟動了一系列的系統(tǒng)服務,里面調用了startOtherServices()方法,那接下看一下startOtherServices方法,向下看:

private void startOtherServices() {
      //....省略了n多代碼
         mSystemServiceManager.startService(TwilightService.class);
        //這里就是啟動JobSchedulerService
      mSystemServiceManager.startService(JobSchedulerService.class);
        if (!disableNonCoreServices) {
            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
                mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
            }
            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
                mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
            }
            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) {
                mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
            }
        }
 //....省略了n多代碼
}

在startOtherServices方法方法中調用了mSystemServiceManager.startService(JobSchedulerService.class);這里就啟動了JobSchedulerService服務;接下來我們分析JobSchedulerService的源碼; 先看一下JobSchedulerService的構造方法:

public JobSchedulerService(Context context) {
    super(context);
    // Create the controllers.
    mControllers = new ArrayList<StateController>();
    //以下控制類都是繼承了StateController類
    //網絡聯(lián)接控制類
    mControllers.add(ConnectivityController.get(this));
  //時間控制類
    mControllers.add(TimeController.get(this));
  //延時控制類
    mControllers.add(IdleController.get(this));
    //電量控制類
    mControllers.add(BatteryController.get(this));
    mControllers.add(AppIdleController.get(this));
    mHandler = new JobHandler(context.getMainLooper());
  //new了IJobScheduler.Stub,這個其實就是前面JobSchedulerImpl類中mBinder,這里用到了進程間通信binder機制,不明白的可能先學習一下進程間通信機制;
    mJobSchedulerStub = new JobSchedulerStub();
    mJobs = JobStore.initAndGet(this);
}

創(chuàng)建了5個不同的StateController,分別添加到mControllers。

類型說明
ConnectivityController注冊監(jiān)聽網絡連接狀態(tài)的廣播
TimeController注冊監(jiān)聽job時間到期的廣播
IdleController注冊監(jiān)聽屏幕亮/滅,dream進入/退出,狀態(tài)改變的廣播
BatteryController注冊監(jiān)聽電池是否充電,電量狀態(tài)的廣播
AppIdleController監(jiān)聽app是否空閑

前面提到調用mBinder.schedule(job);其實是調用了JobSchedulerService類里面IJobScheduler.Stub內部類的schedule方法;接下看一下這個方法:

final class JobSchedulerStub extends IJobScheduler.Stub {
   //....省略了n多代碼
    @Override
    public int schedule(JobInfo job) throws RemoteException {
        if (DEBUG) {
            Slog.d(TAG, "Scheduling job: " + job.toString());
        }
        //這里做了一個檢驗,非關鍵代碼
        final int pid = Binder.getCallingPid();
        final int uid = Binder.getCallingUid();
     //....省略了n多代碼
        long ident = Binder.clearCallingIdentity();
        try {
        //這個是關鍵代碼,調用JobSchedulerService中的schedule
            return JobSchedulerService.this.schedule(job, uid);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }
}

從上面代碼看出,是調用了調用JobSchedulerService中的schedule方法,好了,看一下JobSchedulerService中的schedule方法;

public int schedule(JobInfo job, int uId) {
    JobStatus jobStatus = new JobStatus(job, uId);
    cancelJob(uId, job.getId());
    startTrackingJob(jobStatus);
  //通過handler發(fā)消息
    mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
    return JobScheduler.RESULT_SUCCESS;
}

從上面代碼可以看出是通過Handler發(fā)消息,MSG_CHECK_JOB是目標源,看一下JobHandler 中的方法

private class JobHandler extends Handler {
    public JobHandler(Looper looper) {
        super(looper);
    }
    @Override
    public void handleMessage(Message message) {
        synchronized (mJobs) {
            if (!mReadyToRock) {
                return;
            }
        }
        switch (message.what) {
            case MSG_JOB_EXPIRED:
                synchronized (mJobs) {
                    JobStatus runNow = (JobStatus) message.obj;
                    if (runNow != null && !mPendingJobs.contains(runNow)
                            && mJobs.containsJob(runNow)) {
                        mPendingJobs.add(runNow);
                    }
                    queueReadyJobsForExecutionLockedH();
                }
                break;
            case MSG_CHECK_JOB:
                synchronized (mJobs) {
                    maybeQueueReadyJobsForExecutionLockedH();
                }
                break;
        }
        maybeRunPendingJobsH();
        removeMessages(MSG_CHECK_JOB);
    }

通過Handler發(fā)消息,然后調用 maybeQueueReadyJobsForExecutionLockedH()方法,

private void queueReadyJobsForExecutionLockedH() {
        ArraySet<JobStatus> jobs = mJobs.getJobs();
        if (DEBUG) {
            Slog.d(TAG, "queuing all ready jobs for execution:");
        }
      //遍歷要處理的目標任務,把目標任務加到集合PendingJobs中
        for (int i=0; i<jobs.size(); i++) {
            JobStatus job = jobs.valueAt(i);
            if (isReadyToBeExecutedLocked(job)) {
                if (DEBUG) {
                    Slog.d(TAG, "    queued " + job.toShortString());
                }
                //把目標任務加到待處理目標任務集合中
                mPendingJobs.add(job);
            } else if (isReadyToBeCancelledLocked(job)) {
                stopJobOnServiceContextLocked(job);
            }
        }
        if (DEBUG) {
            final int queuedJobs = mPendingJobs.size();
            if (queuedJobs == 0) {
                Slog.d(TAG, "No jobs pending.");
            } else {
                Slog.d(TAG, queuedJobs + " jobs queued.");
            }
        }
    }

這個方法主要是遍歷將來要處理的工作任務然后一個個加到待處理工作任務集合中去;這個方法執(zhí)行完后就會執(zhí)行JobHandler中的maybeRunPendingJobsH()方法;

private void maybeRunPendingJobsH() {
        synchronized (mJobs) {
            if (mDeviceIdleMode) {
                // If device is idle, we will not schedule jobs to run.
                return;
            }
            Iterator<JobStatus> it = mPendingJobs.iterator();
            if (DEBUG) {
                Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
            }
            //通過遍歷待處理任務集合,一個個處理待處理任務
            while (it.hasNext()) {
                JobStatus nextPending = it.next();
                JobServiceContext availableContext = null;
                for (int i=0; i<mActiveServices.size(); i++) {
                    JobServiceContext jsc = mActiveServices.get(i);
                    final JobStatus running = jsc.getRunningJob();
                    if (running != null && running.matches(nextPending.getUid(),
                            nextPending.getJobId())) {
                        // Already running this job for this uId, skip.
                        availableContext = null;
                        break;
                    }
                    if (jsc.isAvailable()) {
                        availableContext = jsc;
                    }
                }
                if (availableContext != null) {
                    if (DEBUG) {
                        Slog.d(TAG, "About to run job "
                                + nextPending.getJob().getService().toString());
                    }
    //這個方法就是處理待處理任務的方法
                    if (!availableContext.executeRunnableJob(nextPending)) {
                        if (DEBUG) {
                            Slog.d(TAG, "Error executing " + nextPending);
                        }
                        mJobs.remove(nextPending);
                    }
                    it.remove();
                }
            }
        }
    }
}

從上面源碼分析可以得出,這個方法通過遍歷待處理任務集合,處理任務,這里調用了availableContext.executeRunnableJob(nextPending)方法,這個就是處理待處理任務的方法,接下來我們一起看看這個方法的源碼,分析下:

public class JobServiceContext extends IJobCallback.Stub   implements ServiceConnection {
 @Override
public void onServiceConnected(ComponentName name, IBinder service) {
    if (!name.equals(mRunningJob.getServiceComponent())) {
        mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
        return;
    }
    this.service = IJobService.Stub.asInterface(service);
    final PowerManager pm =
            (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag());
//這里也用WakeLock鎖,防止手機休眠
    mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid()));
    mWakeLock.setReferenceCounted(false);
    mWakeLock.acquire();
    mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
}
}

JobServiceContext是ServiceConnection,這個是進程間通訊ServiceConnection,通過調用availableContext.executeRunnableJob(nextPending)方法,會觸發(fā)調用onServiceConnected,看到這里應該明白了,onServiceConnected方法中的service就是jobservice,里面還用了WakeLock鎖,防止手機休眠,然后通過Handler發(fā)消息 調用了handleServiceBoundH()方法,

/** Start the job on the service. */
    private void handleServiceBoundH() {
        if (DEBUG) {
            Slog.d(TAG, "MSG_SERVICE_BOUND for " + mRunningJob.toShortString());
        }
        if (mVerb != VERB_BINDING) {
            Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
                    + VERB_STRINGS[mVerb]);
            closeAndCleanupJobH(false /* reschedule */);
            return;
        }
        if (mCancelled.get()) {
            if (DEBUG) {
                Slog.d(TAG, "Job cancelled while waiting for bind to complete. "
                        + mRunningJob);
            }
            closeAndCleanupJobH(true /* reschedule */);
            return;
        }
        try {
            mVerb = VERB_STARTING;
            scheduleOpTimeOut();
      //我們就是要找這個方法, 看到這里明白了吧,這個就是調用了jobService中的startjob
            service.startJob(mParams);
        } catch (RemoteException e) {
            Slog.e(TAG, "Error sending onStart message to '" +
                    mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
        }
    }

從上面源碼可以看出,最終是調用了jobService中的startjob方法, 這樣就明白了,是如何觸發(fā)調用jobService中的startjob方法的;

前面在JobSchedulerService中提到了控件類StateController類,這個是一個抽象類,有很多實現(xiàn)類,這個我只分析一個ConnectivityController實現(xiàn)類,其他都差不多,接下來分析一下ConnectivityController源碼:

public class ConnectivityController extends StateController implements
    ConnectivityManager.OnNetworkActiveListener {
private static final String TAG = "JobScheduler.Conn";
//工作任務狀態(tài)集合
private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
  //這個是手機網絡連接改變廣播,網絡發(fā)生改變,會觸發(fā)這個廣播
private final BroadcastReceiver mConnectivityChangedReceiver =
        new ConnectivityChangedReceiver();
/** Singleton. */
private static ConnectivityController mSingleton;
private static Object sCreationLock = new Object();
/** Track whether the latest active network is metered. */
private boolean mNetworkUnmetered;
/** Track whether the latest active network is connected. */
private boolean mNetworkConnected;
public static ConnectivityController get(JobSchedulerService jms) {
    synchronized (sCreationLock) {
        if (mSingleton == null) {
            mSingleton = new ConnectivityController(jms, jms.getContext());
        }
        return mSingleton;
    }
}
private ConnectivityController(StateChangedListener stateChangedListener, Context context) {
    super(stateChangedListener, context);
    // Register connectivity changed BR.
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    mContext.registerReceiverAsUser(
            mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
    ConnectivityService cs =
            (ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
    if (cs != null) {
        if (cs.getActiveNetworkInfo() != null) {
            mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
        }
        mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
    }
}
@Override
public void maybeStartTrackingJob(JobStatus jobStatus) {
    if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
        synchronized (mTrackedJobs) {
            jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
            jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
            mTrackedJobs.add(jobStatus);
        }
    }
}
@Override
public void maybeStopTrackingJob(JobStatus jobStatus) {
    if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
        synchronized (mTrackedJobs) {
            mTrackedJobs.remove(jobStatus);
        }
    }
}
/**
 * @param userId Id of the user for whom we are updating the connectivity state.
 */
private void updateTrackedJobs(int userId) {
    synchronized (mTrackedJobs) {
        boolean changed = false;
        for (JobStatus js : mTrackedJobs) {
            if (js.getUserId() != userId) {
                continue;
            }
            boolean prevIsConnected =
                    js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
            boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
            if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
                changed = true;
            }
        }
        if (changed) {
            mStateChangedListener.onControllerStateChanged();
        }
    }
}
/**
 * We know the network has just come up. We want to run any jobs that are ready.
 */
public synchronized void onNetworkActive() {
    synchronized (mTrackedJobs) {
        for (JobStatus js : mTrackedJobs) {
            if (js.isReady()) {
                if (DEBUG) {
                    Slog.d(TAG, "Running " + js + " due to network activity.");
                }
                mStateChangedListener.onRunJobNow(js);
            }
        }
    }
}
class ConnectivityChangedReceiver extends BroadcastReceiver {
    /**
     * We'll receive connectivity changes for each user here, which we process independently.
     * We are only interested in the active network here. We're only interested in the active
     * network, b/c the end result of this will be for apps to try to hit the network.
     * @param context The Context in which the receiver is running.
     * @param intent The Intent being received.
     */
    // TODO: Test whether this will be called twice for each user.
    @Override
    public void onReceive(Context context, Intent intent) {
        if (DEBUG) {
            Slog.d(TAG, "Received connectivity event: " + intent.getAction() + " u"
                    + context.getUserId());
        }
        final String action = intent.getAction();
        if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
            final int networkType =
                    intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
                            ConnectivityManager.TYPE_NONE);
            // Connectivity manager for THIS context - important!
            final ConnectivityManager connManager = (ConnectivityManager)
                    context.getSystemService(Context.CONNECTIVITY_SERVICE);
            final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
            final int userid = context.getUserId();
            // This broadcast gets sent a lot, only update if the active network has changed.
            if (activeNetwork == null) {
            //網絡未聯(lián)接
                mNetworkUnmetered = false;
                mNetworkConnected = false;
                updateTrackedJobs(userid);
            } else if (activeNetwork.getType() == networkType) {
                mNetworkUnmetered = false;
                mNetworkConnected = !intent.getBooleanExtra(
                        ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
                if (mNetworkConnected) {  // No point making the call if we know there's no conn.
                    mNetworkUnmetered = !connManager.isActiveNetworkMetered();
                }
            //更新工作任務
                updateTrackedJobs(userid);
            }
        } else {
            if (DEBUG) {
                Slog.d(TAG, "Unrecognised action in intent: " + action);
            }
        }
    }
};
@Override
public void dumpControllerState(PrintWriter pw) {
    pw.println("Conn.");
    pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
    for (JobStatus js: mTrackedJobs) {
        pw.println(String.valueOf(js.hashCode()).substring(0, 3) + ".."
                + ": C=" + js.hasConnectivityConstraint()
                + ", UM=" + js.hasUnmeteredConstraint());
    }
}
 }

上面是網絡聯(lián)接控制類ConnectivityController,當網絡發(fā)生改變時,會觸發(fā)網絡連接改變廣播,然后調用updateTrackedJobs(userid)方法,在updateTrackedJobs方法中,會判斷網絡是否有改變,有改變的會調 mStateChangedListener.onControllerStateChanged()方法;這樣又調用了JobSchedulerService類中onControllerStateChanged方法:

@Override
public void onControllerStateChanged() {
    mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}

在onControllerStateChanged方法中通過handler發(fā)消息,然后調用了maybeQueueReadyJobsForExecutionLockedH();

private void maybeQueueReadyJobsForExecutionLockedH() {
        int chargingCount = 0;
        int idleCount =  0;
        int backoffCount = 0;
        int connectivityCount = 0;
        List<JobStatus> runnableJobs = new ArrayList<JobStatus>();
        ArraySet<JobStatus> jobs = mJobs.getJobs();
        for (int i=0; i<jobs.size(); i++) {
            JobStatus job = jobs.valueAt(i);
            if (isReadyToBeExecutedLocked(job)) {
                if (job.getNumFailures() > 0) {
                    backoffCount++;
                }
                if (job.hasIdleConstraint()) {
                    idleCount++;
                }
                if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
                    connectivityCount++;
                }
                if (job.hasChargingConstraint()) {
                    chargingCount++;
                }
                runnableJobs.add(job);
            } else if (isReadyToBeCancelledLocked(job)) {
                stopJobOnServiceContextLocked(job);
            }
        }
        if (backoffCount > 0 ||
                idleCount >= MIN_IDLE_COUNT ||
                connectivityCount >= MIN_CONNECTIVITY_COUNT ||
                chargingCount >= MIN_CHARGING_COUNT ||
                runnableJobs.size() >= MIN_READY_JOBS_COUNT) {
            if (DEBUG) {
                Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
            }
            for (int i=0; i<runnableJobs.size(); i++) {
          //把待處理的工作任務加到集合中去
                mPendingJobs.add(runnableJobs.get(i));
            }
        } else {
            if (DEBUG) {
                Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
            }
        }
        if (DEBUG) {
            Slog.d(TAG, "idle=" + idleCount + " connectivity=" +
            connectivityCount + " charging=" + chargingCount + " tot=" +
                    runnableJobs.size());
        }
    }

通過上面方法,把待處理的工作任務加到集合中,然后再調 maybeRunPendingJobsH();這個前面已提到過,就不再說了,一樣的;

理解JobScheduler機制

到此這篇關于Android JobScheduler介紹的文章就介紹到這了,更多相關Android JobScheduler介紹內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論