又是好久沒有積累東西了。慚愧,慚愧。。。手動哭泣。閒話說到這裏,下面我介紹一種新的 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 是需要註冊的哦!ヾ(゚▽゚)ノ
最最後,給我讀者有什麼 特別的想法 可以隨時 留言 提問。 還有,各位,可以點下小心心,或者是 加個關注啥的‧,::‧( ̄▽ ̄)/‧:‧°*