本文出自 “阿敏其人” 簡書博客,轉載或引用請注明出處。
"從前有座山,山里有座廟,廟里有個老和尚他袈裟七彩燈...... "
推過來的歌曲真有意思!
首先,感謝Alex_Cin的留言,才有下文的產(chǎn)生。
之前寫過一小文,Android 程序打開即啟動指定頁面,比如密碼檢查頁。,實現(xiàn)方式麻煩瑣碎,后來Alex_Cin留言說可以考慮采用Application.ActivityLifecycleCallbacks來實現(xiàn) 監(jiān)聽程序處于前臺還是后臺 ,閱讀學習后,大呼過癮。很早就想把這個寫成博客記錄分享給各位朋友,但是因為個人原因遲遲未完成,現(xiàn)在補上。
關于監(jiān)聽程序處于前臺還是后臺
- 弄一個BaseActivity,onResume等方法加1減1?這樣不好,bug還是有的。
- 獲得所有程序的列表,判斷當前程序是否至于前臺?不好,而且新SDK有所限制。
- 廣播+服務,牛刀殺雞。
所以,Application.ActivityLifecycleCallbacks登場,清脆利索,簡單大氣。
老規(guī)矩,先看圖:

結構圖

菜已上,酒已喝。說說菜怎么做的吧。
一、Application.ActivityLifecycleCallbacks
Application通過ActivityLifecycleCallbacks使用接口提供了一套回調(diào)方法,用于讓開發(fā)者對Activity的生命周期事件進行集中處理。 ActivityLifecycleCallbacks接口回調(diào)可以簡化監(jiān)測Activity的生命周期事件,在一個類中作統(tǒng)一處理。 ActivityLifecycleCallbacks使用要求API 14+ (Android 4.0+)。
既然是接口,那么來實現(xiàn)以下看看怎樣唄
隨便寫一個類,比如名為TestAppCb,實現(xiàn)Application.ActivityLifecycleCallbacks接口
public class TestAppCb implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
我們發(fā)現(xiàn)了很多跟Activity很聲明周期很相似的方法。作用不贅述,下面會附上一個名為ForegroundCallbacks的實現(xiàn)類,自行參考。
以往若需監(jiān)測Activity的生命周期事件代碼,你可能是這樣做的,重寫每一個Acivity的onResume(),然后作統(tǒng)計和處理,ActivityLifecycleCallbacks接口回調(diào)可以簡化這一繁瑣過程,在一個類中作統(tǒng)一處理。
二、具體使用
核心封裝類,根據(jù)下面的代碼的封裝,結合自定義的Application,就可以輕松地實現(xiàn)監(jiān)聽程序處于前臺還是后臺的需求。
public class ForegroundCallbacks implements Application.ActivityLifecycleCallbacks {
public static final long CHECK_DELAY = 500;
public static final String TAG = ForegroundCallbacks.class.getName();
public interface Listener {
public void onBecameForeground();
public void onBecameBackground();
}
private static ForegroundCallbacks instance;
private boolean foreground = false, paused = true;
private Handler handler = new Handler();
private List<Listener> listeners = new CopyOnWriteArrayList<Listener>();
private Runnable check;
public static ForegroundCallbacks init(Application application){
if (instance == null) {
instance = new ForegroundCallbacks();
application.registerActivityLifecycleCallbacks(instance);
}
return instance;
}
public static ForegroundCallbacks get(Application application){
if (instance == null) {
init(application);
}
return instance;
}
public static ForegroundCallbacks get(Context ctx){
if (instance == null) {
Context appCtx = ctx.getApplicationContext();
if (appCtx instanceof Application) {
init((Application)appCtx);
}
throw new IllegalStateException(
"Foreground is not initialised and " +
"cannot obtain the Application object");
}
return instance;
}
public static ForegroundCallbacks get(){
if (instance == null) {
throw new IllegalStateException(
"Foreground is not initialised - invoke " +
"at least once with parameterised init/get");
}
return instance;
}
public boolean isForeground(){
return foreground;
}
public boolean isBackground(){
return !foreground;
}
public void addListener(Listener listener){
listeners.add(listener);
}
public void removeListener(Listener listener){
listeners.remove(listener);
}
@Override
public void onActivityResumed(Activity activity) {
paused = false;
boolean wasBackground = !foreground;
foreground = true;
if (check != null)
handler.removeCallbacks(check);
if (wasBackground){
L.d ("went foreground");
for (Listener l : listeners) {
try {
l.onBecameForeground();
} catch (Exception exc) {
L.d ("Listener threw exception!:"+exc.toString());
}
}
} else {
L.d ("still foreground");
}
}
@Override
public void onActivityPaused(Activity activity) {
paused = true;
if (check != null)
handler.removeCallbacks(check);
handler.postDelayed(check = new Runnable(){
@Override
public void run() {
if (foreground && paused) {
foreground = false;
L.d ("went background");
for (Listener l : listeners) {
try {
l.onBecameBackground();
} catch (Exception exc) {
L.d ("Listener threw exception!:"+exc.toString());
}
}
} else {
L.d ("still foreground");
}
}
}, CHECK_DELAY);
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
@Override
public void onActivityStarted(Activity activity) {}
@Override
public void onActivityStopped(Activity activity) {}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
@Override
public void onActivityDestroyed(Activity activity) {}
}
.
.
MyApplication 結合Application.ActivityLifecycleCallbacks
監(jiān)聽如此輕松
public class MyApplication extends Application{
@Override
public void onCreate() {
super.onCreate();
ForegroundCallbacks.init(this);
ForegroundCallbacks.get().addListener(new ForegroundCallbacks.Listener() {
@Override
public void onBecameForeground() {
L.d("當前程序切換到前臺");
if(CacheUtils.getBoolean(getApplicationContext(), MyConst.GESTRUE_IS_LIVE)){
L.d("已經(jīng)開啟手勢鎖");
Intent intent = new Intent(getApplicationContext(), CheckGesPwdActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}else{
}
}
@Override
public void onBecameBackground() {
L.d("當前程序切換到后臺");
}
});
}
}
如上,即可,手勢庫可以直接引用做個小demo。
整個過程實現(xiàn)起來都是相當輕松的,亮點是ForegroundCallbacks,里面的代碼值得咀嚼和學習。
本文粗糙了點,哈哈哈哈,不過我為什么感覺我還是挺良心的,哈哈哈哈。
附上github鏈接GestureLockMaster
三、單個Activity單獨使用?
就在一個頁面監(jiān)聽,當然可以。
public class TestLifeAc extends AppCompatActivity implements ForegroundCallbacks.Listener {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_city_list);
// 注冊監(jiān)聽
ForegroundCallbacks.get(this).addListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 移除監(jiān)聽
ForegroundCallbacks.get(this).removeListener(this);
}
@Override
public void onBecameForeground(Activity activity) {
// 切換為前臺
}
@Override
public void onBecameBackground(Activity activity) {
//切換為后臺
}
}
四,參考學習
Is my Android app currently foreground or background?
本篇完。