1. 程式人生 > >Android 自用 App保活——音樂播放保活適配8.0 (賊好用)

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 是需要註冊的哦!ヾ(✿゚▽゚)ノ

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