1. 程式人生 > >Android程序守護,讓APP在系統記憶體中常駐(二)

Android程序守護,讓APP在系統記憶體中常駐(二)

      昨天晚上寫了用系統服務等方法來實現應用保活。今天寫一下用提高app的程序等級來實現應用保活。想看直接呼叫系統方法保活應用的可以點選Android程序守護,讓APP在系統記憶體中常駐(一)進行跳轉。

      一:第一種實現思路,建立廣播接收者來監聽系統關屏亮屏操作。當手機關屏時,顯示一個透明的一畫素的activity,此時使用者時看不見的;當手機亮屏時,把這個activity給finish掉。好了,有了思路就開始實現吧。

           1.首先新建一個廣播接收者:來判斷當前的螢幕狀態來進行一些操作。

public class AppBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())){
            AppReciver.getInstance().startApp(context);
        }else {
            AppReciver.getInstance().finishApp();
        }

    }
}

          2.建立一個1畫素的activity。

  @SuppressLint("RtlHardcoded")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_null);
        //設定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);
        //用來給單例傳過去activity,能讓它finish掉。
        AppReciver.getInstance().setActivity(this);
    }

        3.為這個活動建立一個空的透明的主題。

<style name="KeepLive" parent="AppTheme">
        <item name="windowBackground">@null</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>

        4.為這個活動修改AndroidManifest中的內容,把它單獨放入一個棧中。讓他使用剛剛為他建立的主題。

 <activity android:name=".NullActivity"
            android:launchMode="singleInstance"
            android:theme="@style/KeepLive"/>

        5.建立一個單例,用來完成開始和結束活動任務的邏輯操作。

class AppReciver {

    private static final AppReciver ourInstance = new AppReciver();
    private WeakReference<NullActivity> weakReference;

    private AppReciver() {
    }

    static AppReciver getInstance() {
        return ourInstance;
    }

    public void startApp(Context context) {
        context.startActivity(new Intent(context, NullActivity.class));
    }

    public void registerReceiver(Context context) {
        AppBroadcastReceiver appBroadcastReceiver = new AppBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.intent.action.SCREEN_OFF");
        intentFilter.addAction("android.intent.action.SCREEN_ON");
        intentFilter.addAction("android.intent.action.USER_PRESENT");
        context.registerReceiver(appBroadcastReceiver, intentFilter);

    }

    public void finishApp() {
        if (weakReference != null && weakReference.get() != null) {
            weakReference.get().finish();
        }
    }

    public void setActivity(NullActivity activity) {
        weakReference = new WeakReference(activity);
    }
}

          6.注意上面的單例中使用了WeakReference來儲存activity。這裡為了避免記憶體洩漏使用了弱引用。最後在活動中呼叫一下就完成了。

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //1.系統拉活service程序
        //startService(new Intent(this,StickService.class));

        //2.通過jobScheduler拉活
        //startJob();

        //3.通過bindService,通過ServiceConnection來拉活
        //bindService();

        //4.通過activity來提升app的程序等級
        AppReciver.getInstance().registerReceiver(this);
    }

       二:service提升app的程序等級

           1.首先新建一個服務。

public class ForegroundService extends Service {
    private static final int SERVICE_ID = 1;

    public ForegroundService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

         2.如果是安卓4.0以下可以直接構建一個空的通知。安卓8.0以上,通知需要設定channel ,還需要設定通知的重要級別 ,安卓9.0以上,通知會直接顯示出來。所以要進行版本的判斷,來實現通知的設定方式。4.0以下的可以直接通過下面一行程式碼呼叫。

if (Build.VERSION.SDK_INT < 18) {
            //安卓4.0以下可以直接構建一個空的通知。
            //設定成前臺服務,並且去除通知欄訊息
            startForeground(SERVICE_ID,new Notification());
        }

         3.安卓8.0以下的就需要先設定成前臺服務,然後再去通過新的服務去除通知欄的訊息。好了,廢話不說,直接上程式碼。

else if (Build.VERSION.SDK_INT < 26) {
            //設定成前臺服務
            startForeground(SERVICE_ID,new Notification());
            //並且去除通知欄訊息
            startService(new Intent(this,InnerService.class));
        }

          4.InnerService直接寫一個內部服務就行。在裡面進行去除通知欄的訊息。

 private class InnerService extends Service{
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startForeground(SERVICE_ID,new Notification());
            stopForeground(true);
            stopSelf();
            return super.onStartCommand(intent, flags, startId);
        }
    }

            5.下面是這個服務的完整程式碼。

public class ForegroundService extends Service {
    private static final int SERVICE_ID = 1;

    public ForegroundService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (Build.VERSION.SDK_INT < 18) {
            //安卓4.0以下可以直接構建一個空的通知。
            //設定成前臺服務,並且去除通知欄訊息
            startForeground(SERVICE_ID,new Notification());
        } else if (Build.VERSION.SDK_INT < 26) {
            //設定成前臺服務
            startForeground(SERVICE_ID,new Notification());
            //並且去除通知欄訊息
            startService(new Intent(this,InnerService.class));
        } else {
            //安卓8.0以上,通知需要設定channel
            //還需要設定通知的重要級別
            //安卓9.0以上,通知會直接顯示出來。
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (manager!=null){
                NotificationChannel channel = new NotificationChannel("channel","xxx",NotificationManager.IMPORTANCE_NONE);
                manager.createNotificationChannel(channel);
                Notification notification = new NotificationCompat.Builder(this,"channel").build();
                startForeground(SERVICE_ID,notification);
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private class InnerService extends Service{
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startForeground(SERVICE_ID,new Notification());
            stopForeground(true);
            stopSelf();
            return super.onStartCommand(intent, flags, startId);
        }
    }
}

           6.在活動中啟動一下就大功告成了。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //1.系統拉活service程序
        //startService(new Intent(this,StickService.class));

        //2.通過jobScheduler拉活
        //startJob();

        //3.通過bindService,通過ServiceConnection來拉活
        //bindService();

        //4.通過activity來提升app的程序等級
        //AppReciver.getInstance().registerReceiver(this);

        //5.通過Service來提升app的程序等級
        startService(new Intent(this,ForegroundService.class));
    }

   好了,就說到這吧,有什麼補充的或者哪裡說的不對的歡迎在下面評論,一期交流,相互學習。