Android?;罘桨?/h2>

1:low memory killer

系統(tǒng)出于性能和體驗(yàn)上的考慮,APP退到后臺后并不會真正的kill、掉進(jìn)程,而是將其緩存起來。
打開的應(yīng)用越多,緩存的應(yīng)用也就越多,在系統(tǒng)進(jìn)程不足的情況下,系統(tǒng)根據(jù)自己的一套進(jìn)程回收機(jī)制,來判斷kill掉哪些進(jìn)程,以騰出進(jìn)程給需要的app,這套進(jìn)程回收機(jī)制叫做low memory killer。

2:內(nèi)存不足

內(nèi)存閥值,每個手機(jī)都不一樣,當(dāng)可用內(nèi)存小于該值得時候,Android就會殺死對應(yīng)優(yōu)先級得進(jìn)程。

3:進(jìn)程的優(yōu)先級

進(jìn)程的優(yōu)先級通過oom_adj來判斷,oom_adj取值如下:

adj級別 說明
UNKNOWN_ADJ 16 預(yù)留的最低級別,一般對于緩存的進(jìn)程才有可能設(shè)置成這個級別
CACHED_APP_MAX_ADJ 15 緩存進(jìn)程,空進(jìn)程,在內(nèi)存不足的情況下就會優(yōu)先被kill
CACHED_APP_MIN_ADJ 9 緩存進(jìn)程,也就是空進(jìn)程
SERVICE_B_ADJ 8 不活躍的進(jìn)程
PREVIOUS_APP_ADJ 7 切換進(jìn)程
HOME_APP_ADJ 6 與Home交互的進(jìn)程
SERVICE_ADJ 5 有Service的進(jìn)程
HEAVY_WEIGHT_APP_ADJ 4 高權(quán)重進(jìn)程
BACKUP_APP_ADJ 3 正在備份的進(jìn)程
PERCEPTIBLE_APP_ADJ 2 可感知的進(jìn)程,比如那種播放音樂
VISIBLE_APP_ADJ 1 可見進(jìn)程
FOREGROUND_APP_ADJ 0 前臺進(jìn)程
PERSISTENT_SERVICE_ADJ -11 重要進(jìn)程
PERSISTENT_PROC_ADJ -12 核心進(jìn)程
SYSTEM_ADJ -16 系統(tǒng)進(jìn)程
NATIVE_ADJ -17 系統(tǒng)起的Native進(jìn)程

0-3是比較安全的oom_adj一般不會被系統(tǒng)殺死的,所以我們只要保證自己的app oom_adj在0-3之間就可以了。
可以通過adb命令:cat /proc /4181/oom_adj來查看自己app的oom_adj的值
4181是進(jìn)程號

保活

方案1:activity1像素?;?/h4>

原理:手機(jī)關(guān)閉屏幕的時候,偷偷創(chuàng)建一個activity,讓應(yīng)用成為前臺進(jìn)程,打開屏幕時關(guān)閉activity,這樣用戶就不會發(fā)現(xiàn)什么異常,我們知道前臺應(yīng)用的oom_adj為0是不會被殺死的,這樣就達(dá)到看保活的目的。

        //設(shè)置1像素
        Window window = getWindow();
        window.setGravity(Gravity.LEFT | Gravity.TOP);
        WindowManager.LayoutParams params = window.getAttributes();
        params.x = 0;
        params.y = 0;
        params.height = 1;
        params.width = 1;
        window.setAttributes(params);

缺點(diǎn):activity不夠干凈,只有在息屏的時候才生效,存在局限性比較大,而且谷歌原生的系統(tǒng)息屏的時候不會清理進(jìn)程,但是現(xiàn)在很多廠商會在息屏的時候清理內(nèi)存,所以本方案的可行性不高,可以作為了解。

方案2:前臺service保活

?;钤恚簡右粋€前臺服務(wù),從而拉高整個應(yīng)用的優(yōu)先級。
因?yàn)橐坏┩ㄖ挥脩舾傻裟敲丛摫;罘桨妇筒缓糜昧?,所以通知圖標(biāo)存在與否是該方案是否可行的關(guān)鍵。
但是該方案是谷歌官方承認(rèn)的?;罘桨?,所以可行性還是很高的。
需要適配
API<18通知圖標(biāo)不會顯示

//activity中
startservice(new Intent( packagecontext: this, Foregroundservice. class)):
//service中
startforeground(1, new Notification());

API>=18&&API<26可以啟動雙服務(wù),綁定同樣的D,然后stop
這個方法的原理是8.0系統(tǒng)之前會根據(jù)服務(wù)的id來判斷通知,那么第二個id設(shè)置跟第一個相同,然后自殺,系統(tǒng)就會誤認(rèn)為此通知已死就不會通知了,那么通知欄上面就不會顯示

//activity中
startservice(new Intent( packagecontext: this, Foregroundservice. class)):
//service中
startforeground(1, new Notification());
public static class Innerservice extends Service {
@Nullable
@Override
public Ibinder onbind(Intent intent){
return null;
}
@Override
public void oncreate() {
super.oncreate 
startforeground(1, new Notification())
stopself();
}

API>=26后暫時沒有方式能夠隱藏
8.0之后不可以創(chuàng)建同樣的id的通知,所以此隱藏通知的方法就不好用了,當(dāng)然了,通知顯示與否不是該方案成功的評判標(biāo)準(zhǔn),所以說還是可以用的。

拉活

1:廣播拉活

1.1:系統(tǒng)廣播拉活

在發(fā)生特定系統(tǒng)事件時,系統(tǒng)會發(fā)出廣播,通過在 Androidmanifest中靜
態(tài)注冊對應(yīng)的廣播監(jiān)聽器,即可在發(fā)生響應(yīng)事件時拉活
但是從 android7.0開始,對廣播進(jìn)行了限制,而且在8.0更加嚴(yán)格該方法就不適用了。

1.2:全家桶拉活

有多個app在用戶設(shè)備上安裝,只要開啟其中一個就可以將其他的app也拉
活。比如手機(jī)里裝了手Q、QQ空間、興趣部落等等,那么打開任意一個app后,其
他的app也都會被喚醒

2:賬戶(account)同步拉活

系統(tǒng)每隔一段時間會進(jìn)行賬戶同步,當(dāng)系統(tǒng)去賬戶同步的時候(不一定多長時間,跟系統(tǒng)有關(guān)),我們就去拉活app,這個方案是非常穩(wěn)定的,當(dāng)然了國內(nèi)的系統(tǒng)都是定制的,所以還是需要一定的適配的。
優(yōu)點(diǎn):系統(tǒng)喚醒,比較穩(wěn)定
缺點(diǎn):時間不能把控

2.1注冊一個service,添加一個系統(tǒng)可識別的action

<service android: name- account. Authenticationservice
<intent-filter>
<action android: name-androld. accounts. Accountauthenticator
</intent-filter
<meta-data
android: name="android, accounts, Accountauthenticato
android: resource="@xml/account authenticator /
</service>

2.2service中通過binder把AccountAuthenticator 對象告訴系統(tǒng)

private AccountAuthenticator accountAuthenticator;
@override
public IBinder on Bind(Intent intent) {
return account Authenticator.getIBinder() ;
@override
public void onCreate() {
super.onCreate() ;
accountAuthenticator=new AccountAuthenticator(context:this) ;

2.3:同步賬戶:

public class Syncservice extends service{
private SyncAdapter mSyncAdapter;
private static final String TAG="SyncService";
@override
public IBinder onBind(Intent intent) {
return mSyncAdapter.getSyncAdapterBinder() ;
@override
public void onCreate() {
super.onCreate() ;
mSyncAdapter=new SyncAdapter(getApplicationContext() , true) ;
public static class SyncAdapter extends AbstractThreadedSyncAdapter{
public SyncAdapter(Context context, boolean auto Initialize) {
super(context, autoInitialize) ;
@override
public void onPerformSync(Accounta ccount, Bundle extras, String authority, ContentProvider clientprovider, SyncResult syncResult{
Log.e(TAG, “同步賬戶") ;
//與互聯(lián)網(wǎng)或者本地?cái)?shù)據(jù)庫同步賬戶
}

2.4:添加權(quán)限

<uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS"
android:maxsdkversion="22"/>
<uses-permission
android:name="android.permission, GET_ACCOUNTS"
android:maxsdkversion="22"/>
<uses-permissionandroid:name="android.permission.MRITE_SYNC_SETTINGS"/>

3:JobScheduler拉活

JobScheduler允許在特定狀態(tài)與特定時間間隔周期執(zhí)行任務(wù)??梢岳?br> 用它的這個特點(diǎn)完成保活的功能,效果即開啟一個定時器,與普通定時器不
同的是其調(diào)度由系統(tǒng)完成。
同樣在某些ROM可能并不能達(dá)到需要的效果

@Requires Api(api=Build.VERSION.CODES.LOLLIPOP
public class MyJob service extends Jobservice{
public static void startJob(Context context) {
JobScheduler jobscheduler=(Jobscheduler) context.getSystemservice(Context.JOB_SCHEDULER_SERVICE) ;
JobInfo.Builder builder=new JobInfo.Builder(8, new ComponentName(context.get PackageName() ,
HyJob service.class.getName() ) ) .setPersisted(true) ;
//小于7.0
builder.setPeriodic(1000) ;//6.0以后最小是5s
//大于7.0
builder. set MinimumLatency(1000) ;//6.0以后最小是5s
job scheduler.schedule(builder.build() ) ;
}
@override
public boolean onStartJob(JobParameters params) {
//大于7.0
startJob(this);
return false;
}
@override
public boolean onStopJob(Jobparameters params) {
return false;
}
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容