【Android 电量优化】电量优化 ( JobScheduler | JobService | AsyncTask )

本文涉及的产品
云解析DNS-重点域名监控,免费拨测 20万次(价值200元)
简介: 【Android 电量优化】电量优化 ( JobScheduler | JobService | AsyncTask )

文章目录

一、JobScheduler 使用流程

二、AsyncTask 简介

三、JobScheduler 开发流程

四、JobScheduler 代码示例

1、JobScheduleManager 代码示例

2、JobService 与 AsyncTask 代码示例

3、AndroidManifest.xml 配置

4、执行结果

五、源码及资源下载





一、JobScheduler 使用流程


JobScheduler 使用流程 :



① 获取 JobScheduler 服务 : 从 Context 对象中 , 调用 getSystemService 方法跨进程获取 ;


mJobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);


② 创建 JobInfo 任务信息 :


//创建一个任务
JobInfo jobInfo = new
        JobInfo.Builder(0,  // 任务 id 为 0
        new ComponentName(mContext, BpJobService.class))
        .setRequiresCharging(true)  // 要求在充电时执行
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 非蜂窝网络执行
        .setExtras(extras).build();


③ 提交任务 :


mJobScheduler.schedule(jobInfo);


④ 执行任务 : 在 JobService 的 onStartJob 方法中 , 会由系统在合适的时间 , 执行相关任务 ;


public class BpJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        // 启动 AsyncTask 异步任务处理工作
        new JobAsyncTask().execute(params);
        return false;
    }
    // ... 省略部分代码
}







二、AsyncTask 简介


在 JobScheduler 提交任务后 , 系统会在 JobService 中执行相应的任务 , 执行的时机由系统选择 ;


系统回调 JobService 服务中的 onStartJob 方法时 , 由用户自行执行相应的任务 , 一般是使用 AsyncTask 来执行相应任务 ;



1 . AsyncTask<JobParameters, Void, Void> 三个泛型解析


泛型 1 11 : 异步任务开始时 , execute 方法传入的参数类型

泛型 2 22 : 异步任务执行时 , 进度值类型

泛型 3 33 : 异步任务结束时 , 结果类型


2 . AsyncTask 4 44 个方法解析 :


onPreExecute : doInBackground 之前执行的方法, 一般在该方法中执行初始化操作 ( 主线程, 可以更新 UI )

doInBackground : 主要的耗时操作是在该方法中执行的 ( 非主线程, 不能更新 UI )

onProgressUpdate : 在 doInBackground 中调用了 publishProgress 方法, 就会回调该方法 , 一般情况下是在该方法中执行更新 UI 的操作 ( 主线程, 可以更新 UI )

onPostExecute : doInBackground 执行完毕后 , 调用 return 方法后 , 该方法会被调用 ( 主线程, 可以更新 UI )

执行顺序 : onPreExecute -> doInBackground -> onProgressUpdate -> onPostExecute






三、JobScheduler 开发流程


1 . 任务管理类 : 开发 JobScheduleManager 管理类 , 该类负责与 Service 服务中的需求对接 , 接收 Service 服务中的添加任务的需求 , 将任务操作转为参数 , 并提交到系统 JobScheduler 中 ;


2 . 任务执行服务 : 开发 JobService 服务 , 该服务是执行具体的任务的类 , 在该类中 , 接收到系统调度的任务参数 , 在 onStartJob 方法中解析这些参数 , 并创建 AsyncTask 执行对应的任务 ;


3 . 添加任务 : 在一个第三方 Service 服务中 , 调用 JobScheduleManager 类添加任务 , 系统会自动回调分配执行任务 , 在 JobService 中的 onStartJob 方法中执行任务 ;






四、JobScheduler 代码示例




1、JobScheduleManager 代码示例


该类主要用于管理 JobScheduler , 初始化 JobScheduler , 处理添加任务的选项等操作 , 如任务执行时机 , 执行需求 等 ;


package kim.hsl.bp;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.os.Build;
import android.os.PersistableBundle;
import android.util.Log;
import java.util.List;
public class JobScheduleManager {
    public static final String TAG = "JobScheduleManager";
    /**
     * 将不紧急的任务调度到更合适的时机进行处理
     * 如充电时 , 如 WIFI 连接时
     * 1. 避免频繁由于执行单次任务 , 唤醒硬件模块 , 造成电量浪费
     * 2. 避免在不合适的时机执行耗电任务 , 如使用蜂窝网络在不合适的时候更新软件
     */
    private JobScheduler mJobScheduler;
    /**
     * 上下文对象
     */
    private Context mContext;
    /*
        单例模式
     */
    private static JobScheduleManager mInstance;
    private JobScheduleManager(){}
    public static JobScheduleManager getInstance(){
        if(mInstance == null){
            mInstance = new JobScheduleManager();
        }
        return mInstance;
    }
    public void init(Context context){
        this.mContext = context;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mJobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        }
    }
    public void addJob(String currentJobData){
        if(mJobScheduler == null){
            return;
        }
        Log.i(TAG, "添加任务 : " + currentJobData);
        // 查找 id 为 0 的 任务
        JobInfo pendingJob = null;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            pendingJob = mJobScheduler.getPendingJob(0);
        }else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            List<JobInfo> allPendingJobs = mJobScheduler.getAllPendingJobs();
            for(JobInfo info : allPendingJobs){
                if(info.getId() == 0){
                    pendingJob = info;
                    break;
                }
            }
        }
        // 获取任务执行数据
        String historyJobData = "";
        if(pendingJob != null){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                PersistableBundle extras = pendingJob.getExtras();
                historyJobData = extras.getString("JOB_DATA");
                mJobScheduler.cancel(0);
            }
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            PersistableBundle extras = new PersistableBundle();
            extras.putString("JOB_DATA", currentJobData + "$" + historyJobData);
            //创建一个任务
            JobInfo jobInfo = new
                    JobInfo.Builder(0,  // 任务 id 为 0
                    new ComponentName(mContext, BpJobService.class))
                    .setRequiresCharging(true)  // 要求在充电时执行
                    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 非蜂窝网络执行
                    .setExtras(extras).build();
            // 将任务提交到队列中
            mJobScheduler.schedule(jobInfo);
        }
    }
}


2、JobService 与 AsyncTask 代码示例


JobService 与 AsyncTask 代码示例 :



注意 JobService 的两个方法 onStartJob , onStopJob 的调用时机 , 与返回值含义 ;


注意 AsyncTask 定义时三个泛型的含义 , onPreExecute , doInBackground , onProgressUpdate , onPostExecute 四个方法的调用时机 ;


package kim.hsl.bp;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.os.AsyncTask;
import android.os.Build;
import android.os.PersistableBundle;
import android.util.Log;
import androidx.annotation.RequiresApi;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class BpJobService extends JobService {
    public static final String TAG = "Battery_Performance.BpJobService";
    /**
     *
     * @param params
     * @return
     *      true 任务正要被执行, 需要开始执行任务
     *      false 任务执行完毕
     */
    @Override
    public boolean onStartJob(JobParameters params) {
        // 启动 AsyncTask 异步任务处理工作
        new JobAsyncTask().execute(params);
        return false;
    }
    /**
     *
     * @param params
     * @return
     */
    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }
    /**
     * AsyncTask<JobParameters, Void, Void> 三个泛型解析
     * -- 1. 异步任务开始时 , execute 方法传入的参数类型
     * -- 2. 异步任务执行时 , 进度值类型
     * -- 3. 异步任务结束时 , 结果类型
     */
    class JobAsyncTask extends AsyncTask<JobParameters, Void, Void> {
        /**
         * doInBackground 之前执行的方法, 一般在该方法中执行初始化操作
         * ( 主线程, 可以更新 UI )
         */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        /**
         * 主要的耗时操作是在该方法中执行的
         * ( 非主线程, 不能更新 UI )
         * @param jobParameters
         * @return
         */
        @Override
        protected Void doInBackground(JobParameters... jobParameters) {
            JobParameters parameters = jobParameters[0];
            PersistableBundle extras = parameters.getExtras();
            String jobData = extras.getString("JOB_DATA");
            Log.i(TAG, "JobAsyncTask 执行 : " + jobData);
            return null;
        }
        /**
         * 在 doInBackground 中调用了 publishProgress 方法, 就会回调该方法
         * 一般情况下是在该方法中执行更新 UI 的操作
         * ( 主线程, 可以更新 UI )
         * @param values
         */
        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }
        /**
         * doInBackground 执行完毕后 , 调用 return 方法后 , 该方法会被调用
         * ( 主线程, 可以更新 UI )
         * @param aVoid
         */
        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
        }
    }
}




3、AndroidManifest.xml 配置


主要是配置 AlarmManagerService 服务 和 BpJobService 服务 ;


注意为 BpJobService 服务声明 android.permission.BIND_JOB_SERVICE 权限 ;


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kim.hsl.bp">
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".BatteryReceiver" >
            <intent-filter>
                <!-- 充电线插上 -->
                <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
                <!-- 充电线拔出 -->
                <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
            </intent-filter>
        </receiver>
        <receiver android:name=".WifiReceiver" >
            <intent-filter>
                <!-- 网络状态改变 -->
                <action android:name="android.intent.action.CONNECTIVITY_CHANGE" />
            </intent-filter>
        </receiver>
        <!-- WeakLock 保持 CPU 唤醒的 Service 服务 -->
        <service
            android:name=".WeakLockService"
            android:process=":weaklock" />
        <!-- AlarmManager 保持 CPU 唤醒的 Service 服务 -->
        <service
            android:name=".AlarmManagerService"
            android:process=":alrmmanager" />
        <!-- JobScheduler 服务 -->
        <service
            android:name=".BpJobService"
            android:process=":jobservice"
            android:permission="android.permission.BIND_JOB_SERVICE"/>
    </application>
</manifest>



4、执行结果


执行结果 :


2020-07-07 15:00:58.189 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.AlarmManagerService: AlarmManagerService onCreate
2020-07-07 15:01:19.056 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.AlarmManagerService: receiver ACTION
2020-07-07 15:01:19.057 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.JobScheduleManager: 添加任务 : ACTION(1594105279057)
2020-07-07 15:01:19.239 11158-11214/kim.hsl.bp:jobservice I/Battery_Performance.BpJobService: JobAsyncTask 执行 : ACTION(1594105279057)$
2020-07-07 15:02:38.985 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.AlarmManagerService: receiver ACTION
2020-07-07 15:02:38.986 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.JobScheduleManager: 添加任务 : ACTION(1594105358986)
2020-07-07 15:02:38.997 11158-11214/kim.hsl.bp:jobservice I/Battery_Performance.BpJobService: JobAsyncTask 执行 : ACTION(1594105358986)$
2020-07-07 15:03:19.058 11091-11091/kim.hsl.bp:alrmmanager I/Battery_Performance.AlarmManagerService: receiver ACTION




五、源码及资源下载


源码及资源下载地址 :


① GitHub 工程地址 : Battery_Performance


② 使用 AlarmManager 保持 CPU 唤醒 Service 代码地址 : AlarmManagerService.java


③ JobScheduleManager.java 代码地址 : JobScheduleManager.java


④ BpJobService.java 代码地址 : BpJobService.java


⑤ AndroidManifest.xml 配置文件地址 : AndroidManifest.xml


目录
相关文章
|
2月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
226 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
3月前
|
存储 消息中间件 人工智能
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
242 10
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
|
9月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
2096 77
|
7月前
|
缓存 编解码 Android开发
Android内存优化之图片优化
本文主要探讨Android开发中的图片优化问题,包括图片优化的重要性、OOM错误的成因及解决方法、Android支持的图片格式及其特点。同时介绍了图片储存优化的三种方式:尺寸优化、质量压缩和内存重用,并详细讲解了相关的实现方法与属性。此外,还分析了图片加载优化策略,如异步加载、缓存机制、懒加载等,并结合多级缓存流程提升性能。最后对比了几大主流图片加载框架(Universal ImageLoader、Picasso、Glide、Fresco)的特点与适用场景,重点推荐Fresco在处理大图、动图时的优异表现。这些内容为开发者提供了全面的图片优化解决方案。
278 1
|
存储 缓存 编解码
Android经典面试题之图片Bitmap怎么做优化
本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。
210 20
Android经典面试题之图片Bitmap怎么做优化
|
Java Android开发 UED
安卓应用开发中的内存管理优化技巧
在安卓开发的广阔天地里,内存管理是一块让开发者既爱又恨的领域。它如同一位严苛的考官,时刻考验着开发者的智慧与耐心。然而,只要我们掌握了正确的优化技巧,就能够驯服这位考官,让我们的应用在性能和用户体验上更上一层楼。本文将带你走进内存管理的迷宫,用通俗易懂的语言解读那些看似复杂的优化策略,让你的开发之路更加顺畅。
338 33
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
399 31
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
211 4
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。
|
Java Android开发 开发者
安卓应用开发中的线程管理优化技巧
【9月更文挑战第10天】在安卓开发的海洋里,线程管理犹如航行的风帆,掌握好它,能让应用乘风破浪,反之则可能遭遇性能的暗礁。本文将通过浅显易懂的语言和生动的比喻,带你探索如何优雅地处理安卓中的线程问题,从基础的线程创建到高级的线程池运用,让你的应用运行更加流畅。