Files
mkdocs/docs/android面试/性能优化/电量优化.md
2026-01-15 11:53:37 +08:00

15 KiB
Raw Permalink Blame History

电量优化

目录


电量消耗分析

电量消耗主要来源

  1. CPU:频繁计算、长时间运行
  2. 网络:频繁请求、大数据传输
  3. 定位GPS、网络定位
  4. 屏幕:高亮度、长时间亮屏
  5. 传感器:加速度计、陀螺仪等
  6. WakeLock:阻止系统休眠

电量消耗分析工具

1. Battery Historian

# 收集电池数据
adb shell dumpsys batterystats --reset
# 使用应用一段时间
adb shell dumpsys batterystats > batterystats.txt

# 生成报告
python historian.py batterystats.txt > battery.html

2. Battery Profiler

  • Android Studio -> View -> Tool Windows -> Profiler
  • 实时查看电量消耗
  • 分析电量消耗趋势
  • 查看唤醒锁使用情况

3. adb 命令

# 查看电量信息
adb shell dumpsys battery

# 查看电量统计
adb shell dumpsys batterystats

# 查看唤醒锁
adb shell dumpsys power

WakeLock使用

WakeLock 简介

WakeLock 用于阻止系统进入休眠状态,保持 CPU 运行或屏幕亮起。

WakeLock 类型

// PARTIAL_WAKE_LOCK保持 CPU 运行,屏幕可以关闭
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
    PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock"
);

// SCREEN_DIM_WAKE_LOCK保持屏幕变暗CPU 运行(已废弃)
// SCREEN_BRIGHT_WAKE_LOCK保持屏幕高亮CPU 运行(已废弃)
// FULL_WAKE_LOCK保持屏幕高亮键盘背光CPU 运行(已废弃)

// ACQUIRE_CAUSES_WAKEUP获取时立即唤醒屏幕
// ON_AFTER_RELEASE释放后保持屏幕亮起一段时间

WakeLock 使用示例

public class WakeLockManager {
    private PowerManager powerManager;
    private PowerManager.WakeLock wakeLock;
    
    public WakeLockManager(Context context) {
        powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK,
            "MyApp::WakeLock"
        );
    }
    
    public void acquire() {
        if (!wakeLock.isHeld()) {
            wakeLock.acquire();
        }
    }
    
    public void release() {
        if (wakeLock.isHeld()) {
            wakeLock.release();
        }
    }
    
    public void acquire(long timeout) {
        if (!wakeLock.isHeld()) {
            wakeLock.acquire(timeout); // 超时自动释放
        }
    }
}

// 使用
WakeLockManager manager = new WakeLockManager(context);
manager.acquire();
// 执行需要保持 CPU 运行的任务
manager.release();

WakeLock 注意事项

// ❌ 错误示例:忘记释放 WakeLock
public void doWork() {
    wakeLock.acquire();
    // 如果这里抛出异常WakeLock 不会被释放
    doSomething();
    wakeLock.release();
}

// ✅ 正确做法:使用 try-finally
public void doWork() {
    wakeLock.acquire();
    try {
        doSomething();
    } finally {
        wakeLock.release();
    }
}

// ✅ 使用超时自动释放
wakeLock.acquire(10 * 60 * 1000L); // 10分钟后自动释放

WakeLock 最佳实践

  1. 及时释放:使用完毕后立即释放
  2. 使用超时:设置超时时间,避免忘记释放
  3. 最小化使用:只在必要时使用,尽量减少使用时间
  4. 使用替代方案:优先使用 JobScheduler、WorkManager

JobScheduler

JobScheduler 简介

JobScheduler 是 Android 5.0+ 提供的任务调度框架,可以在合适的时机执行任务,节省电量。

JobScheduler 优势

  1. 智能调度:系统选择最佳时机执行
  2. 批量执行:合并多个任务一起执行
  3. 条件触发:满足条件时才执行
  4. 电量友好:减少电量消耗

JobScheduler 使用示例

public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        // 执行任务(在后台线程)
        new Thread(() -> {
            // 执行任务
            doWork();
            
            // 任务完成
            jobFinished(params, false);
        }).start();
        
        return true; // 返回 true 表示任务在后台执行
    }
    
    @Override
    public boolean onStopJob(JobParameters params) {
        // 任务被取消
        return false; // 返回 false 表示任务不需要重新调度
    }
    
    private void doWork() {
        // 执行具体任务
    }
}
public class JobSchedulerHelper {
    private JobScheduler jobScheduler;
    
    public JobSchedulerHelper(Context context) {
        jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    }
    
    public void scheduleJob() {
        JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(context, MyJobService.class))
            .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) // 需要网络
            .setRequiresCharging(false) // 不需要充电
            .setRequiresDeviceIdle(false) // 不需要设备空闲
            .setPeriodic(15 * 60 * 1000) // 每15分钟执行一次
            .setPersisted(true) // 持久化,重启后仍然有效
            .build();
        
        jobScheduler.schedule(jobInfo);
    }
    
    public void cancelJob(int jobId) {
        jobScheduler.cancel(jobId);
    }
    
    public void cancelAllJobs() {
        jobScheduler.cancelAll();
    }
}

JobScheduler 条件

JobInfo jobInfo = new JobInfo.Builder(1, componentName)
    // 网络条件
    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE) // 不需要网络
    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) // 任何网络
    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 非计费网络WiFi
    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NOT_ROAMING) // 非漫游网络
    
    // 充电条件
    .setRequiresCharging(true) // 需要充电
    
    // 设备空闲条件
    .setRequiresDeviceIdle(true) // 需要设备空闲
    
    // 存储条件
    .setRequiresStorageNotLow(true) // 存储空间充足
    
    // 电池条件
    .setRequiresBatteryNotLow(true) // 电池电量充足
    
    // 执行时间
    .setMinimumLatency(1000) // 最小延迟1秒
    .setOverrideDeadline(5000) // 最晚5秒后执行
    .setPeriodic(15 * 60 * 1000) // 每15分钟执行一次
    
    .build();

WorkManager

WorkManager 简介

WorkManager 是 Android Jetpack 提供的任务调度框架,兼容 Android 4.0+,是 JobScheduler、Firebase JobDispatcher、AlarmManager 的统一封装。

WorkManager 优势

  1. 向后兼容:兼容所有 Android 版本
  2. 智能调度:自动选择最佳调度方式
  3. 链式任务:支持任务链和任务组
  4. 约束条件:支持多种约束条件
  5. 持久化:任务持久化,应用重启后仍然有效

WorkManager 使用示例

1. 定义 Worker

public class MyWorker extends Worker {
    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }
    
    @NonNull
    @Override
    public Result doWork() {
        // 执行任务
        try {
            doSomething();
            return Result.success();
        } catch (Exception e) {
            return Result.retry(); // 重试
            // 或
            // return Result.failure(); // 失败
        }
    }
    
    private void doSomething() {
        // 执行具体任务
    }
}

2. 创建 WorkRequest

// 一次性任务
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
    .setConstraints(constraints)
    .setInitialDelay(10, TimeUnit.SECONDS)
    .addTag("my_tag")
    .build();

// 周期性任务
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(
    MyWorker.class,
    15, TimeUnit.MINUTES
).build();

3. 设置约束条件

Constraints constraints = new Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED) // 需要网络连接
    .setRequiresCharging(true) // 需要充电
    .setRequiresDeviceIdle(true) // 需要设备空闲
    .setRequiresBatteryNotLow(true) // 电池电量充足
    .setRequiresStorageNotLow(true) // 存储空间充足
    .build();

4. 提交任务

WorkManager workManager = WorkManager.getInstance(context);

// 提交一次性任务
workManager.enqueue(workRequest);

// 提交周期性任务
workManager.enqueue(periodicWorkRequest);

// 取消任务
workManager.cancelWorkById(workRequest.getId());
workManager.cancelAllWorkByTag("my_tag");
workManager.cancelAllWork();

5. 观察任务状态

workManager.getWorkInfoByIdLiveData(workRequest.getId())
    .observe(lifecycleOwner, workInfo -> {
        if (workInfo != null) {
            WorkInfo.State state = workInfo.getState();
            if (state == WorkInfo.State.SUCCEEDED) {
                // 任务成功
            } else if (state == WorkInfo.State.FAILED) {
                // 任务失败
            }
        }
    });

6. 链式任务

// 顺序执行
WorkManager workManager = WorkManager.getInstance(context);
workManager
    .beginWith(workRequest1)
    .then(workRequest2)
    .then(workRequest3)
    .enqueue();

// 并行执行
workManager
    .beginWith(workRequest1, workRequest2)
    .then(workRequest3)
    .enqueue();

后台任务优化

1. 减少后台任务频率

// ❌ 错误示例:频繁执行后台任务
Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        syncData(); // 每分钟同步一次
    }
}, 0, 60 * 1000);

// ✅ 正确做法:使用 WorkManager 智能调度
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
    SyncWorker.class,
    15, TimeUnit.MINUTES
).build();
WorkManager.getInstance(context).enqueue(workRequest);

2. 批量处理任务

// ❌ 错误示例:逐个处理
for (Item item : items) {
    processItem(item); // 每个任务都唤醒设备
}

// ✅ 正确做法:批量处理
List<Item> batch = new ArrayList<>();
for (Item item : items) {
    batch.add(item);
    if (batch.size() >= 10) {
        processBatch(batch); // 批量处理
        batch.clear();
    }
}

3. 使用前台服务

// 对于需要长时间运行的任务,使用前台服务
public class MyForegroundService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        
        Notification notification = createNotification();
        startForeground(1, notification);
    }
    
    private Notification createNotification() {
        return new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("正在运行")
            .setContentText("任务进行中")
            .setSmallIcon(R.drawable.ic_notification)
            .build();
    }
}

4. 避免长时间运行

// ❌ 错误示例:长时间运行
public void doWork() {
    while (true) {
        processData();
        Thread.sleep(1000);
    }
}

// ✅ 正确做法:使用 WorkManager 或 JobScheduler
// 让系统决定何时执行任务

5. 优化网络请求

// ❌ 错误示例:频繁请求
Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        api.getData().enqueue(callback); // 每分钟请求一次
    }
}, 0, 60 * 1000);

// ✅ 正确做法:使用推送或智能调度
// 使用 FCM 推送通知,或使用 WorkManager 在合适时机请求

电量优化工具

1. Battery Historian

# 收集数据
adb shell dumpsys batterystats --reset
# 使用应用
adb shell dumpsys batterystats > batterystats.txt

# 生成报告
python historian.py batterystats.txt > battery.html

2. Battery Profiler

  • Android Studio -> View -> Tool Windows -> Profiler
  • 实时查看电量消耗
  • 分析唤醒锁使用
  • 查看 CPU 使用情况

3. adb 命令

# 查看电量信息
adb shell dumpsys battery

# 查看唤醒锁
adb shell dumpsys power

# 查看电量统计
adb shell dumpsys batterystats

4. Doze 模式测试

# 进入 Doze 模式
adb shell dumpsys deviceidle force-idle

# 退出 Doze 模式
adb shell dumpsys deviceidle unforce

# 查看 Doze 状态
adb shell dumpsys deviceidle

面试常见问题

Q1: 如何优化应用电量消耗?

答案:

  1. 减少后台任务:使用 JobScheduler、WorkManager 智能调度
  2. 优化网络请求:减少请求频率、批量处理
  3. 合理使用 WakeLock:及时释放、使用超时
  4. 优化定位:使用缓存、降低定位频率
  5. 优化屏幕:降低亮度、及时关闭屏幕
  6. 优化 CPU:减少计算、使用异步处理

Q2: WakeLock 的作用和使用注意事项?

答案:

  • 作用:阻止系统进入休眠状态
  • 类型PARTIAL_WAKE_LOCK保持 CPU、SCREEN_BRIGHT_WAKE_LOCK保持屏幕
  • 注意事项
    1. 及时释放,避免忘记释放
    2. 使用超时,设置自动释放时间
    3. 最小化使用,只在必要时使用
    4. 优先使用 JobScheduler、WorkManager

Q3: JobScheduler 和 WorkManager 的区别?

答案:

  • JobScheduler

    • Android 5.0+ 支持
    • 系统级 API
    • 功能相对简单
  • WorkManager

    • Android 4.0+ 支持(向后兼容)
    • Jetpack 组件
    • 功能更强大,支持链式任务、任务组
    • 自动选择最佳调度方式

Q4: 如何分析应用电量消耗?

答案:

  1. Battery Historian:生成详细的电量消耗报告
  2. Battery Profiler:实时查看电量消耗
  3. adb 命令:查看电量统计、唤醒锁使用
  4. 系统设置:查看应用电量使用情况

Q5: Doze 模式对应用的影响?

答案:

  • Doze 模式Android 6.0+ 的省电模式
  • 影响
    1. 限制网络访问
    2. 延迟后台任务
    3. 限制唤醒锁
  • 应对
    1. 使用 WorkManager 或 JobScheduler
    2. 使用前台服务(重要任务)
    3. 使用 FCM 高优先级消息

Q6: 后台任务优化的最佳实践?

答案:

  1. 使用 WorkManager 或 JobScheduler 智能调度
  2. 减少任务执行频率
  3. 批量处理任务
  4. 使用约束条件(网络、充电等)
  5. 避免长时间运行的任务
  6. 使用前台服务(重要任务)

总结

电量优化是 Android 性能优化的重要部分,主要从以下几个方面入手:

  1. 减少后台任务:使用智能调度框架
  2. 优化网络请求:减少频率、批量处理
  3. 合理使用 WakeLock:及时释放、最小化使用
  4. 使用约束条件:只在满足条件时执行任务
  5. 监控电量消耗:使用工具分析电量使用情况

通过合理的电量优化,可以延长设备电池续航时间,提升用户体验。


最后更新2024年