Android 自用 App保活——音樂播放保活適配8.0 (賊好用)

又是好久沒有積累東西了。慚愧,慚愧。。。手動哭泣。閒話說到這裏,下面我介紹一種新的 App 保活方式哈,目前用小米家族手機 涵蓋 Android 5.0 到 Android 8.1家族的測試。結論是,不主動幹掉,是死不了的。但是主動幹掉了,是活不了的。

之前介紹介紹了 雙進程保活,我還大言不慚的 適配 8.0 。但是,從 Android 6.0 之後這個方法及其不好用,說死就死,華爲,小米 分分鐘 弄死筆者的 App 。 而且 最噁心的事情,居然 ANR 。 筆者對現在那些閉着眼睛 抄博客 的大佬實在不敢恭維了。對了,之前的筆記地址爲:自己用到的Android 雙服務保活(適配8.0), Android 6.0 以上不建議使用 !!!好了,下面說說,服務播放音樂,保活的基本原理吧。

一、保活原理

1、準備一首無聲音樂(文末我會提供);

2、在認爲可以進行保活的位置 進行激活服務 播放(筆者在MainActivity 內啓動 服務);

3、在服務的 onCreate()方法內 初始化 MediaPlayer 對象;

4、將 onBind()方法返回值置空;

5、在 onStartCommand()方法內 開啓線程 進行音樂播放(筆者選擇播放 3s 之後進行了音樂暫停處理,放置部分 定製 os 出現鎖屏 線程音樂播放界面,及其噁心,比如 miui);

6、在 onDestroy( ) 方法內進行關閉 播放器對象,移除播放器對象,重啓本服務。

二、保活代碼

/**
 * Content:後臺播放音樂達到保活目的
 * Actor:韓小呆 ヾ(゚▽゚)ノ
 * Time:  2018/10/12 10:47
 * Update:
 * Time:
 */
public class SingASongService extends Service {
    private MediaPlayer mMediaPlayer;
    private Thread thread;

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

    @Override
    public void onCreate() {
        super.onCreate();
        MyThread myThread = new MyThread();
        thread = new Thread(myThread);
        mMediaPlayer = MediaPlayer.create(MainApplication.getInstance(), R.raw.no_kill);
        mMediaPlayer.setLooping(true);

        LogUtils.d("onCreate() 創建播放對象:" + mMediaPlayer.hashCode());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        thread.start();
        LogUtils.d("播放時 線程名稱:" + thread.getName());
        return START_STICKY;
    }

    //開始、暫停播放
    private void startPlaySong() {
        if (mMediaPlayer == null) {
            mMediaPlayer = MediaPlayer.create(MainApplication.getInstance(), R.raw.no_kill);
            LogUtils.d("音樂啓動播放,播放對象爲: " + mMediaPlayer.hashCode());
            mMediaPlayer.start();
        } else {
            mMediaPlayer.start();
            LogUtils.d("音樂啓動播放,播放對象爲: " + mMediaPlayer.hashCode());
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if (mMediaPlayer != null) {
            mMediaPlayer.pause();
            LogUtils.d("音樂啓動播放,播放對象爲: " + mMediaPlayer.hashCode());
            int progress = mMediaPlayer.getCurrentPosition();
            LogUtils.d("音樂暫停,播放進度:" + progress);
        }
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        mMediaPlayer.pause();
        LogUtils.d("恢復播放 時當前播放器對象:" + mMediaPlayer.hashCode());
        stopPlaySong();
        LogUtils.d("應用播放服務被殺死,正在重啓");
        LogUtils.d("目標播放工作線程是否存活:" + thread.isAlive());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(new Intent(getApplicationContext(), SingASongService.class));
        } else {
            startService(new Intent(getApplicationContext(), SingASongService.class));
        }
    }

    //停止播放銷燬對象
    private void stopPlaySong() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            LogUtils.d("音樂停止播放,播放對象爲:" + mMediaPlayer.hashCode());
            LogUtils.d("音樂播放器是否在循環:" + mMediaPlayer.isLooping());
            LogUtils.d("音樂播放器是否還在播放:" + mMediaPlayer.isPlaying());
            mMediaPlayer.release();
            LogUtils.d("播放對象銷燬,播放對象爲:" + mMediaPlayer.hashCode());
            mMediaPlayer = null;
        }
    }

    class MyThread implements Runnable {

        @Override
        public void run() {
            startPlaySong();
        }
    }
}

爲了方便判定 對象是否被消失,打印日誌有點多,也方便,各位朋友驗證。別 oom 啊。部分代碼可以進行優化,比如說創建線程的方式,我只是爲了方便驗證吧,畢竟比較菜。

三、直接使用代碼

public class SingASongService extends Service {
    
    private MediaPlayer mMediaPlayer;
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mMediaPlayer = MediaPlayer.create(MainApplication.getInstance(), R.raw.no_kill);
        mMediaPlayer.setLooping(true);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                startPlaySong();
            }
        }).start();
        return START_STICKY;
    }

    //開始、暫停播放
    private void startPlaySong() {
        if (mMediaPlayer == null) {
            mMediaPlayer = MediaPlayer.create(MainApplication.getInstance(), R.raw.no_kill);
            mMediaPlayer.start();
        } else {
            mMediaPlayer.start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if (mMediaPlayer != null) {
            mMediaPlayer.pause();
        }
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        mMediaPlayer.pause();
        stopPlaySong();
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(new Intent(getApplicationContext(), SingASongService.class));
        } else {
            startService(new Intent(getApplicationContext(), SingASongService.class));
        }
    }

    //停止播放銷燬對象
    private void stopPlaySong() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }
}

無聲音樂

最後提醒部分小白,service 是需要註冊的哦!ヾ(゚▽゚)ノ

最最後,給我讀者有什麼 特別的想法 可以隨時 留言 提問。 還有,各位,可以點下小心心,或者是 加個關注啥的‧,::‧( ̄▽ ̄)/‧:‧°* 

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