Android Service 性能優(yōu)化

和你一起終身學(xué) 習(xí),這里是程序員Android
經(jīng)典好文推薦,通過閱讀本文,您將收獲以下知識點(diǎn):
一、Service 介紹
二、Service 優(yōu)先級
三、Service 回收過程
四、Service 保活方法
一、Service 介紹
service:是一個后臺服務(wù),專門用來處理常駐后臺的工作的組件。
服務(wù)的優(yōu)化 主要體驗(yàn)在兩個方面:一·服務(wù)的保活,二·服務(wù)后臺對于執(zhí)行任務(wù)的集中管理.
下面我們主要對服務(wù)的保活方面進(jìn)行講解,至于任務(wù)集中管理執(zhí)行,在電量優(yōu)化中已經(jīng)講過,這里就不再累贅。
開始先來說下我們實(shí)現(xiàn)的方式:
1.提高進(jìn)程優(yōu)先級
2.java層雙進(jìn)程守護(hù)
3.1個像素的Activity保活
4.JobScheduler輪詢
5.native層雙進(jìn)程守護(hù)
今天我們只寫前三種方式,第四種native層雙進(jìn)程守護(hù)將在NDK章節(jié)講解。
二、Service 優(yōu)先級
1. 前臺進(jìn)程
-
Activity已調(diào)用onResume()方法
-
Service服務(wù)已調(diào)用startForeground()
-
生命周期回調(diào)的Service (onCreate() 、onStart()或onDestroy())
-
正執(zhí)行其onReceive()方法的BroadcastReceiver
2. 可見進(jìn)程
-
不在前臺、但仍對用戶可見的Activity(比如調(diào)用其onPause()方法)
-
綁定到可見(或前臺)Activity 的Service
3. 服務(wù)進(jìn)程
-
startService()方法啟動的服務(wù),且不屬于上面兩類
4. 后臺進(jìn)程
-
對用戶不可見的 Activity 的進(jìn)程已調(diào)用 Activity 的onStop()方法
5. 空進(jìn)程
-
不含任何活動應(yīng)用組件的進(jìn)程
三、Service 回收過程
1.應(yīng)用內(nèi)存不足,回收進(jìn)程
提高進(jìn)程優(yōu)先級,減少進(jìn)程oom_adj值,如啟動進(jìn)程的setForeground()提高進(jìn)程優(yōu)先級
當(dāng)應(yīng)用程序退到后臺時,釋放占用的資源,因?yàn)楫?dāng)oom_adj相同時,優(yōu)先釋放內(nèi)存消耗大的進(jìn)程一直在后臺運(yùn)行的進(jìn)程一定要輕
2.系統(tǒng)第三方清理軟件,殺死進(jìn)程
使用aidl,實(shí)現(xiàn)雙進(jìn)程守護(hù)
白名單
3.各大rom廠商在應(yīng)用退出時,會清理殺死進(jìn)程
使用NDK,輪詢查看指定進(jìn)程是否被殺死,如果殺死fork進(jìn)程,啟動
使用JobScheduler,輪詢查看指定進(jìn)程是否被殺死,如果殺死,啟動
四、Service 保活方法
雙進(jìn)程守護(hù)(基于java層)
這里我們將用到aidl,有不了解的同學(xué)可以自己去了解下,我們先來上代碼:
1.編寫aidl接口
interface ProcessConnect {
}
接口里面什么都沒有,這個只是用來監(jiān)聽是否斷開連接,如果斷開,就代碼啟動服務(wù)。
2.工作服務(wù)
public class MessageService extends Service {
private String TAG = "MessageService";
private int ID=0X00022;
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
mContext = this;
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
Log.e(TAG, "MessageService====>print");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//assert uri
String path = "file:///android_asset/xiaoxin.wav";
Notification.Builder builder = new Notification.Builder(mContext);
Notification notification = builder
.setContentText("messageservice")
.setSmallIcon(R.drawable.ting)
.setSound(Uri.parse(path))
.build();
startForeground(ID,notification);
bindService(new Intent(MessageService.this,GuardService.class),mServiceConnection,BIND_WAIVE_PRIORITY);
return START_STICKY;
}
public ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "MessageService====>onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
startService(new Intent(MessageService.this,GuardService.class));
bindService(new Intent(MessageService.this,GuardService.class),mServiceConnection,BIND_WAIVE_PRIORITY);
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new ProcessConnect.Stub() {
};
}
}
3.守護(hù)服務(wù)
public class GuardService extends Service {
private Context mContext;
private int ID=0X00021;
@Override
public void onCreate() {
super.onCreate();
mContext = this;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//assert uri
String path = "file:///android_asset/xiaoxin.wav";
Notification.Builder builder = new Notification.Builder(mContext);
Notification notification = builder
.setContentText("GuardService")
.setSmallIcon(R.drawable.ting)
.setSound(Uri.parse(path))
.build();
startForeground(ID,notification);
bindService(new Intent(GuardService.this,MessageService.class),mServiceConnection,BIND_WAIVE_PRIORITY);
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new ProcessConnect.Stub(){
};
}
public ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("GuardService", "GuardService====>onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
startService(new Intent(GuardService.this,MessageService.class));
bindService(new Intent(GuardService.this,MessageService.class),mServiceConnection,BIND_WAIVE_PRIORITY);
}
};
}
從上面兩個服務(wù)可以看到,每當(dāng)一個服務(wù)結(jié)束,另一個服務(wù)就會啟動它,來實(shí)現(xiàn)進(jìn)程不被關(guān)閉。
4.MainActivity開啟服務(wù)
startService(new Intent(this,MessageService.class));
startService(new Intent(this,GuardService.class));
5.配置
<service android:name=".MessageService"></service>
//新的進(jìn)程中運(yùn)行
<service android:name=".GuardService" android:process=":guardservice"></service>
主要五步就搞定了,很簡單吧,但是不要高興的太早,因?yàn)檫@種雙進(jìn)程守護(hù)的方法,只能對4.0以下有效,對于4.0以上機(jī)型,只能部分有用,這個問題最后再說,我們先來看下使用JobScheduler,輪詢啟動被殺死的進(jìn)程。
1個像素的Activity保活
啟動一個1個像素的Activity,當(dāng)用戶解鎖以后將這個Activity結(jié)束掉(順便同時把自己的核心服務(wù)再開啟一次)。被用戶發(fā)現(xiàn)了就不好了。
重點(diǎn)就是對屏幕進(jìn)行監(jiān)聽,下面我們來分析代碼:
1個像素的Activity實(shí)現(xiàn):
Window window = getWindow();
window.setGravity(Gravity.LEFT|Gravity.TOP);
LayoutParams params = window.getAttributes();
params.height = 1;
params.width = 1;
params.x = 0;
params.y = 0;
window.setAttributes(params);
對屏幕進(jìn)行監(jiān)聽
private void registerListener() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
mContext.registerReceiver(mScreenReceiver, filter);
}
JobScheduler
在android開發(fā)中,會存在這么些場景 : 你需要在稍后的某個時間點(diǎn)或者當(dāng)滿足某個特定的條件時執(zhí)行一個任務(wù),例如當(dāng)設(shè)備接通電源適配器或者連接到WIFI。幸運(yùn)的是在API 21 ( Android 5.0,即Lollipop )中,google提供了一個新叫做JobScheduler API的組件來處理這樣的場景。
當(dāng)一系列預(yù)置的條件被滿足時,JobScheduler API為你的應(yīng)用執(zhí)行一個操作。與AlarmManager不同的是這個執(zhí)行時間是不確定的。除此之外,JobScheduler API允許同時執(zhí)行多個任務(wù)。這允許你的應(yīng)用執(zhí)行某些指定的任務(wù)時不需要考慮時機(jī)控制引起的電池消耗。
下面我們就使用JobScheduler來啟動我們被殺死的服務(wù):
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class JobWakeUpService extends JobService {
private JobScheduler service;
private int JobId=100;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
JobInfo info = new JobInfo.Builder(JobId,new ComponentName(this,JobWakeUpService.class))
.setPeriodic(2000)
.build();
service = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
service.schedule(info);
return START_STICKY;
}
@Override
public boolean onStartJob(JobParameters params) {
Log.e("JobWakeUpService", "JobWakeUpService====>print");
//開始定時任務(wù)
if(!isServiceWork(this,MessageService.class.getName())){
//
startService(new Intent(this,MessageService.class));
}
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
//停止
service.cancel(JobId);
// service.cancelAll();
return false;
}
private boolean isServiceWork(Context context,String serviceName){
ActivityManager am= (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInforunningServices = am.getRunningServices(100);
if(runningServices == null){
return false;
}
for (ActivityManager.RunningServiceInfo service : runningServices) {
String className = service.service.getClassName();
if(className.equals(serviceName)){
return true;
}
}
return false;
}
}
我們看到這邊就是使用JobScheduler服務(wù)來進(jìn)行循環(huán)調(diào)用我們的JobWakeUpService的onStartJob。
我們接下來看下配置:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
<service android:name=".JobWakeUpService"
android:enabled="true"
android:permission="android.permission.BIND_JOB_SERVICE"
></service>
調(diào)用:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startService(new Intent(this, JobWakeUpService.class));
}
這個就能實(shí)現(xiàn)輪詢查看指定進(jìn)程是否被殺死,如果殺死,啟動的功能。
可能你們想問這種方式是否可以解決5.0以上進(jìn)程不被殺死嗎?我只能遺憾的告訴你,不能,我在華為7.0上的測試,沒有能夠起來。
我們看了這么多的方式,也不能解決進(jìn)程不被殺死的情況,那有沒有更好的辦法呢?
native層雙進(jìn)程守護(hù)
關(guān)于NDK來實(shí)現(xiàn)雙進(jìn)程守護(hù)將在ndk文章中講解。
下載地址:NoDieService-Demo
原文鏈接:https://www.jianshu.com/p/1d176d1cedb5
友情推薦:
至此,本篇已結(jié)束。轉(zhuǎn)載網(wǎng)絡(luò)的文章,小編覺得很優(yōu)秀,歡迎點(diǎn)擊閱讀原文,支持原創(chuàng)作者,如有侵權(quán),懇請聯(lián)系小編刪除,歡迎您的建議與指正。同時期待您的關(guān)注,感謝您的閱讀,謝謝!
點(diǎn)個在看,方便您使用時快速查找!
