Android性能之服務優化

和你一起終身學習,這裏是程序員 Android

經典好文推薦,通過閱讀本文,您將收穫以下知識點:

一、Service 介紹
二、Service 優先級
三、Service 回收過程
四、Service 保活方法

一、Service 介紹

service:是一個後臺服務,專門用來處理常駐後臺的工作的組件。
服務的優化 主要體驗在兩個方面:一·服務的保活,二·服務後臺對於執行任務的集中管理.

下面我們主要對服務的保活方面進行講解,至於任務集中管理執行,在電量優化中已經講過,這裏就不再累贅。

開始先來說下我們實現的方式:

1.提高進程優先級
2.java層雙進程守護
3.1個像素的Activity保活
4.JobScheduler輪詢
5.native層雙進程守護

今天我們只寫前三種方式,第四種native層雙進程守護將在NDK章節講解。

二、Service 優先級

1. 前臺進程

  • Activity已調用onResume()方法
  • Service服務已調用startForeground()
  • 生命週期回調的Service (onCreate() 、onStart()或onDestroy())
  • 正執行其onReceive()方法的BroadcastReceiver

2. 可見進程

  • 不在前臺、但仍對用戶可見的Activity(比如調用其onPause()方法)
  • 綁定到可見(或前臺)Activity 的Service

3. 服務進程

  • startService()方法啓動的服務,且不屬於上面兩類

4. 後臺進程

  • 對用戶不可見的 Activity 的進程已調用 Activity 的onStop()方法

5. 空進程

  • 不含任何活動應用組件的進程

三、Service 回收過程

1.應用內存不足,回收進程

提高進程優先級,減少進程oom_adj值,如啓動進程的setForeground()提高進程優先級
當應用程序退到後臺時,釋放佔用的資源,因爲當oom_adj相同時,優先釋放內存消耗大的進程一直在後臺運行的進程一定要輕

2.系統第三方清理軟件,殺死進程

使用aidl,實現雙進程守護
白名單

3.各大rom廠商在應用退出時,會清理殺死進程

使用NDK,輪詢查看指定進程是否被殺死,如果殺死fork進程,啓動
使用JobScheduler,輪詢查看指定進程是否被殺死,如果殺死,啓動

四、Service 保活方法

雙進程守護(基於java層)

這裏我們將用到aidl,有不瞭解的同學可以自己去了解下,我們先來上代碼:

1.編寫aidl接口
    interface ProcessConnect {

    }

接口裏面什麼都沒有,這個只是用來監聽是否斷開連接,如果斷開,就代碼啓動服務。

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);
            }
        };

    }

從上面兩個服務可以看到,每當一個服務結束,另一個服務就會啓動它,來實現進程不被關閉。

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結束掉(順便同時把自己的核心服務再開啓一次)。被用戶發現了就不好了。
重點就是對屏幕進行監聽,下面我們來分析代碼:

1個像素的Activity實現:

    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);

對屏幕進行監聽

    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開發中,會存在這麼些場景 : 你需要在稍後的某個時間點或者當滿足某個特定的條件時執行一個任務,例如當設備接通電源適配器或者連接到WIFI。幸運的是在API 21 ( Android 5.0,即Lollipop )中,google提供了一個新叫做JobScheduler API的組件來處理這樣的場景。

當一系列預置的條件被滿足時,JobScheduler API爲你的應用執行一個操作。與AlarmManager不同的是這個執行時間是不確定的。除此之外,JobScheduler API允許同時執行多個任務。這允許你的應用執行某些指定的任務時不需要考慮時機控制引起的電池消耗。

下面我們就使用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服務來進行循環調用我們的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));
    }

這個就能實現輪詢查看指定進程是否被殺死,如果殺死,啓動的功能。

可能你們想問這種方式是否可以解決5.0以上進程不被殺死嗎?我只能遺憾的告訴你,不能,我在華爲7.0上的測試,沒有能夠起來。

我們看了這麼多的方式,也不能解決進程不被殺死的情況,那有沒有更好的辦法呢?

native層雙進程守護

關於NDK來實現雙進程守護將在ndk文章中講解。

下載地址:NoDieService-Demo

原文鏈接:https://www.jianshu.com/p/1d176d1cedb5

至此,本篇已結束。轉載網絡的文章,小編覺得很優秀,歡迎點擊閱讀原文,支持原創作者,如有侵權,懇請聯繫小編刪除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章