Android性能 之 服務優(yōu)化

和你一起終身學習,這里是程序員Android
經典好文推薦,通過閱讀本文,您將收獲以下知識點:
一、Service 介紹
二、Service 優(yōu)先級
三、Service 回收過程
四、Service 保活方法
一、Service 介紹
service:是一個后臺服務,專門用來處理常駐后臺的工作的組件。
服務的優(yōu)化 主要體驗在兩個方面:一·服務的保活,二·服務后臺對于執(zhí)行任務的集中管理.
下面我們主要對服務的保活方面進行講解,至于任務集中管理執(zhí)行,在電量優(yōu)化中已經講過,這里就不再累贅。
開始先來說下我們實現(xiàn)的方式:
1.提高進程優(yōu)先級
2.java層雙進程守護
3.1個像素的Activity保活
4.JobScheduler輪詢
5.native層雙進程守護
今天我們只寫前三種方式,第四種native層雙進程守護將在NDK章節(jié)講解。
二、Service 優(yōu)先級
1. 前臺進程
Activity已調用onResume()方法
Service服務已調用startForeground()
生命周期回調的Service (onCreate() 、onStart()或onDestroy())
正執(zhí)行其onReceive()方法的BroadcastReceiver
2. 可見進程
不在前臺、但仍對用戶可見的Activity(比如調用其onPause()方法)
綁定到可見(或前臺)Activity 的Service
3. 服務進程
startService()方法啟動的服務,且不屬于上面兩類
4. 后臺進程
對用戶不可見的 Activity 的進程已調用 Activity 的onStop()方法
5. 空進程
不含任何活動應用組件的進程
三、Service 回收過程
1.應用內存不足,回收進程
提高進程優(yōu)先級,減少進程oom_adj值,如啟動進程的setForeground()提高進程優(yōu)先級
當應用程序退到后臺時,釋放占用的資源,因為當oom_adj相同時,優(yōu)先釋放內存消耗大的進程一直在后臺運行的進程一定要輕
2.系統(tǒng)第三方清理軟件,殺死進程
使用aidl,實現(xiàn)雙進程守護
白名單
3.各大rom廠商在應用退出時,會清理殺死進程
使用NDK,輪詢查看指定進程是否被殺死,如果殺死fork進程,啟動
使用JobScheduler,輪詢查看指定進程是否被殺死,如果殺死,啟動
四、Service 保活方法
雙進程守護(基于java層)
這里我們將用到aidl,有不了解的同學可以自己去了解下,我們先來上代碼:
1.編寫aidl接口
interface ProcessConnect {
}
接口里面什么都沒有,這個只是用來監(jiān)聽是否斷開連接,如果斷開,就代碼啟動服務。
2.工作服務
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.守護服務
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);
}
};
}
從上面兩個服務可以看到,每當一個服務結束,另一個服務就會啟動它,來實現(xiàn)進程不被關閉。
4.MainActivity開啟服務
startService(new Intent(this,MessageService.class));
startService(new Intent(this,GuardService.class));
5.配置
<service android:name=".MessageService"></service>
//新的進程中運行
<service android:name=".GuardService" android:process=":guardservice"></service>
主要五步就搞定了,很簡單吧,但是不要高興的太早,因為這種雙進程守護的方法,只能對4.0以下有效,對于4.0以上機型,只能部分有用,這個問題最后再說,我們先來看下使用JobScheduler,輪詢啟動被殺死的進程。
1個像素的Activity保活
啟動一個1個像素的Activity,當用戶解鎖以后將這個Activity結束掉(順便同時把自己的核心服務再開啟一次)。被用戶發(fā)現(xiàn)了就不好了。
重點就是對屏幕進行監(jiān)聽,下面我們來分析代碼:
1個像素的Activity實現(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);
對屏幕進行監(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ā)中,會存在這么些場景 : 你需要在稍后的某個時間點或者當滿足某個特定的條件時執(zhí)行一個任務,例如當設備接通電源適配器或者連接到WIFI。幸運的是在API 21 ( Android 5.0,即Lollipop )中,google提供了一個新叫做JobScheduler API的組件來處理這樣的場景。
當一系列預置的條件被滿足時,JobScheduler API為你的應用執(zhí)行一個操作。與AlarmManager不同的是這個執(zhí)行時間是不確定的。除此之外,JobScheduler API允許同時執(zhí)行多個任務。這允許你的應用執(zhí)行某些指定的任務時不需要考慮時機控制引起的電池消耗。
下面我們就使用JobScheduler來啟動我們被殺死的服務:
@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");
//開始定時任務
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服務來進行循環(huán)調用我們的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>
調用:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startService(new Intent(this, JobWakeUpService.class));
}
這個就能實現(xiàn)輪詢查看指定進程是否被殺死,如果殺死,啟動的功能。
可能你們想問這種方式是否可以解決5.0以上進程不被殺死嗎?我只能遺憾的告訴你,不能,我在華為7.0上的測試,沒有能夠起來。
我們看了這么多的方式,也不能解決進程不被殺死的情況,那有沒有更好的辦法呢?
native層雙進程守護
關于NDK來實現(xiàn)雙進程守護將在ndk文章中講解。
下載地址:NoDieService-Demo
原文鏈接:https://www.jianshu.com/p/1d176d1cedb5
友情推薦:
至此,本篇已結束。轉載網絡的文章,小編覺得很優(yōu)秀,歡迎點擊閱讀原文,支持原創(chuàng)作者,如有侵權,懇請聯(lián)系小編刪除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!
點個在看,方便您使用時快速查找!
