手持ActivityLifecycleCallbacks,監(jiān)聽前后臺狀態(tài)如此舒服

本文出自 “阿敏其人” 簡書博客,轉載或引用請注明出處。

"從前有座山,山里有座廟,廟里有個老和尚他袈裟七彩燈...... "
推過來的歌曲真有意思!

首先,感謝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ī)矩,先看圖:

ges.gif

結構圖

Paste_Image.png

菜已上,酒已喝。說說菜怎么做的吧。

一、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?

本篇完。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,745評論 25 709
  • 最近剛從舊公司離職,為面試在做準備,因為平時開發(fā)CV大法用得比較多,很多基礎知識掌握得不是很牢靠以及很多工具框架只...
    黎清海閱讀 2,322評論 1 19
  • 1.什么是Activity?問的不太多,說點有深度的 四大組件之一,一般的,一個用戶交互界面對應一個activit...
    JoonyLee閱讀 5,855評論 2 51
  • 那張一本正經(jīng)的臉 平平展展地從我身旁經(jīng)過 她不希望我評價她 她怕我說出好話 又怕我說出不好的話 我學牛馬打了個響鼻...
    左左右右艾小年閱讀 463評論 0 0
  • 今天是第九周了,天也突然冷了,我給學生們上課,檢查作業(yè),發(fā)現(xiàn)很多孩子都不能完完,整整地做完作業(yè),這需要老師的一些技...
    lygly9閱讀 267評論 0 0

友情鏈接更多精彩內(nèi)容