1: 開(kāi)啟一個(gè)像素的Activity
系統(tǒng)一般是不會(huì)殺死前臺(tái)進(jìn)程的。所以要使得進(jìn)程常駐,我們只需要在鎖屏的時(shí)候在本進(jìn)程開(kāi)啟一個(gè)Activity,
為了欺騙用戶(hù),讓這個(gè)Activity的大小是1像素,并且透明無(wú)切換動(dòng)畫(huà),
在開(kāi)屏幕的時(shí)候,把這個(gè)Activity關(guān)閉掉,所以這個(gè)就需要監(jiān)聽(tīng)系統(tǒng)鎖屏廣播.
//權(quán)限
<uses-permission android:name="android.permission.RECEIVE_USER_PRESENT"/>
//注冊(cè)
<service android:name=".ui.service.MainService"
android:process="1000"/>
<receiver android:name=".ui.broadcastReceiver.ScreenBroadcastListener$ScreenBroadcastReceiver">
<intent-filter android:priority="90000">
<action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
</receiver>
//1px Activity
public class SinglePixelActivity extends Activity {
public static final String TAG = SinglePixelActivity.class.getSimpleName();
public static void actionToSinglePixelActivity(Context context) {
Intent intent = new Intent(context, SinglePixelActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.activity_singlepixel);
Window window = getWindow();
//放在左上角
window.setGravity(Gravity.START | Gravity.TOP);
WindowManager.LayoutParams attributes = window.getAttributes();
//寬高設(shè)計(jì)為1個(gè)像素
attributes.width = 1;
attributes.height = 1;
//起始坐標(biāo)
attributes.x = 0;
attributes.y = 0;
window.setAttributes(attributes);
ScreenManager.getInstance(this).setActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
在屏幕關(guān)閉的時(shí)候把SinglePixelActivity啟動(dòng)起來(lái),
在開(kāi)屏的時(shí)候把SinglePixelActivity 關(guān)閉掉,
所以要監(jiān)聽(tīng)系統(tǒng)鎖屏廣播,以接口的形式通知MainActivity啟動(dòng)或者關(guān)閉SinglePixActivity。
public class ScreenBroadcastListener {
private Context mContext;
private ScreenBroadcastReceiver mScreenReceiver;
private ScreenStateListener mListener;
public ScreenBroadcastListener(Context context) {
mContext = context.getApplicationContext();
mScreenReceiver = new ScreenBroadcastReceiver();
}
interface ScreenStateListener {
void onScreenOn();
void onScreenOff();
}
/**
* screen狀態(tài)廣播接收者
*/
private class ScreenBroadcastReceiver extends BroadcastReceiver {
private String action = null;
@Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action)) { // 開(kāi)屏
mListener.onScreenOn();
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 鎖屏
mListener.onScreenOff();
}
}
}
public void registerListener(ScreenStateListener listener) {
mListener = listener;
registerListener();
}
private void registerListener() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(mScreenReceiver, filter);
}
}
//1px Activity管理類(lèi)
public class ScreenManager {
private Context mContext;
private WeakReference<Activity> mActivityWref;
public static ScreenManager gDefualt;
public static ScreenManager getInstance(Context context) {
if (gDefualt == null) {
gDefualt = new ScreenManager(context.getApplicationContext());
}
return gDefualt;
}
private ScreenManager(Context context) {
this.mContext = context;
}
public void setActivity(Activity pActivity) {
mActivityWref = new WeakReference<Activity>(pActivity);
}
public void startActivity() {
SinglePixelActivity.actionToSinglePixelActivity(mContext);
}
public void finishActivity() {
//結(jié)束掉SinglePixelActivity
if (mActivityWref != null) {
Activity activity = mActivityWref.get();
if (activity != null) {
activity.finish();
}
}
}
}
現(xiàn)在MainActivity改成如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ScreenManager screenManager = ScreenManager.getInstance(MainActivity.this);
ScreenBroadcastListener listener = new ScreenBroadcastListener(this);
listener.registerListener(new ScreenBroadcastListener.ScreenStateListener() {
@Override
public void onScreenOn() {
screenManager.finishActivity();
}
@Override
public void onScreenOff() {
screenManager.startActivity();
}
});
}
}
初步的思路是先判斷app進(jìn)程是否存在,如果存在的話(huà),
就利用startActivities啟動(dòng)MainActivity和DetailActivity。
為什么還要啟動(dòng)MainActivity而不直接只啟動(dòng)DetailActivity?
因?yàn)橛腥缦虑闆r,進(jìn)程中的所有Activity都已經(jīng)退出了,但進(jìn)程還沒(méi)有被系統(tǒng)回收,
這時(shí)判斷進(jìn)程是否存在返回true,然后只啟動(dòng)DetailActivity的話(huà),按Back鍵任務(wù)棧就直接到底,返回桌面了。
而我們要的效果是按Back鍵返回上一級(jí)Activity,也就是MainActivity。
如果app進(jìn)程已經(jīng)退出,不存在了,此時(shí)就用一個(gè)Intent啟動(dòng)應(yīng)用,
該Intent中包含一個(gè)Bundle, Bundle中存有啟動(dòng)DetailActivity所需的參數(shù),
這個(gè)Intent傳入SplashActivity后,再由SplashActivity傳給MainActivity,在MainActivity中加入判斷,
如果有該參數(shù),則表示應(yīng)用是從通知欄啟動(dòng)的,要進(jìn)行跳轉(zhuǎn)到DetailActivity的操作,否則就是常規(guī)啟動(dòng)。
(缺點(diǎn): 如果沒(méi)root 在部分機(jī)器上會(huì)造成廣播監(jiān)聽(tīng)不到)
2
系統(tǒng)自帶的,onStartCommand方法必須具有一個(gè)整形的返回值,
這個(gè)整形的返回值用來(lái)告訴系統(tǒng)在服務(wù)啟動(dòng)完畢后,
如果被Kill,系統(tǒng)將如何操作,這種方案雖然可以,
但是在某些情況or某些定制ROM上可能失效,
認(rèn)為可以多做一種保保守方案。
START_STICKY
如果系統(tǒng)在onStartCommand返回后被銷(xiāo)毀,系統(tǒng)將會(huì)重新創(chuàng)建服務(wù)并依次調(diào)用onCreate和onStartCommand(
注意:根據(jù)測(cè)試Android2.3.3以下版本只會(huì)調(diào)用onCreate根本不會(huì)調(diào)用onStartCommand,
Android4.0可以辦到),這種相當(dāng)于服務(wù)又重新啟動(dòng)恢復(fù)到之前的狀態(tài)了)。
3
JobSheduler
JobSheduler是作為進(jìn)程死后復(fù)活的一種手段,
native進(jìn)程方式最大缺點(diǎn)是費(fèi)電,
Native 進(jìn)程費(fèi)電的原因是感知主進(jìn)程是否存活有兩種實(shí)現(xiàn)方式,在 Native 進(jìn)程中通過(guò)死循環(huán)或定時(shí)器,輪訓(xùn)判斷主進(jìn)程是否存活,當(dāng)主進(jìn)程不存活時(shí)進(jìn)行拉活。
其次5.0以上系統(tǒng)不支持。
但是JobSheduler可以替代在Android5.0以上native進(jìn)程方式,這種方式即使用戶(hù)強(qiáng)制關(guān)閉,也能被拉起來(lái),親測(cè)可行。
4 進(jìn)程相互喚醒
顧名思義,就是指的不同進(jìn)程,
不同app之間互相喚醒,如你手機(jī)里裝了支付寶、淘寶、天貓、UC等阿里系的app,
那么你打開(kāi)任意一個(gè)阿里系的app后,有可能就順便把其他阿里系的app給喚醒了。
注:服務(wù)保活的前提是:要盡可能減少內(nèi)存和電量的消耗。
Android 7.0版本以上,目前沒(méi)有什么真正意義上的?;?。