1. 程式人生 > >應用前後臺切換,Application registerActivityLifecycleCallbacks(API 14)-Android

應用前後臺切換,Application registerActivityLifecycleCallbacks(API 14)-Android

registerActivityLifecycleCallbacks與ActivityLifecycleCallbacks?

-- 需求:

1.統計App的停留時間registerActivityLifecycleCallbacks();

2.統計App中某個Activity停留時間:onResume()->onPause()的時間差。。。

3.App應用由前臺到後臺再切前臺超過1小時,展示廣告

-- 在微信中,對於4.0以上的機型也是採用通過註冊ActivityLifecycleCallbacks介面,對於4.0以下的機型我們會嘗試反射ActivityThread中的mInstrumentation物件。

Android中Hook Instrumentation 的實現- https://blog.csdn.net/u012341052/article/details/71191409
Android外掛化開發之Hook StartActivity方法- https://blog.csdn.net/u011068702/article/details/53208825
public class Hooker {
    private static final String TAG = "Hooker";
    public static void hookInstrumentation() throws Exception {
        Class<?> activityThread = Class.forName("android.app.ActivityThread");
        Method sCurrentActivityThread = activityThread.getDeclaredMethod("currentActivityThread");
        sCurrentActivityThread.setAccessible(true);
        //獲取ActivityThread 物件
        Object activityThreadObject = sCurrentActivityThread.invoke(activityThread);

        //獲取 Instrumentation 物件
        Field mInstrumentation = activityThread.getDeclaredField("mInstrumentation");
        mInstrumentation.setAccessible(true);
        Instrumentation instrumentation = (Instrumentation) mInstrumentation.get(activityThreadObject);
        CustomInstrumentation customInstrumentation = new CustomInstrumentation(instrumentation);
        //將我們的 customInstrumentation 設定進去
        mInstrumentation.set(activityThreadObject, customInstrumentation);
    }

}

-- APP前後臺切換
 getRunningTasks和getRunningAppProcesses失效- https://blog.csdn.net/axi295309066/article/details/56123954
 Android 5.0以上的getRunningTasks失效,該方法可以獲得在前臺執行的系統程序。可以用getRunningAppProcesses方法暫時替代。android6.0以上的getRunningAppProcesses也失效,系統關閉了三方軟體對系統程序的訪問,出於安全考慮。
 -- 在5.0以下可以使用,即在4.0以下可以使用
/**
     * APP是否處於前臺喚醒狀態
     *
     * @return
     */
    public boolean isAppOnForeground() {
        ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
        String packageName = getApplicationContext().getPackageName();
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager
                .getRunningAppProcesses();
        if (appProcesses == null)
            return false;

        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            // The name of the process that this object is associated with.
            if (appProcess.processName.equals(packageName)
                    && appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return true;
            }
        }
        return false;
    }

在5.1.+後獲取執行中程序呢
Example code for "How-To SU" -

https://github.com/Chainfire/libsuperuser

-- registerActivityLifecycleCallbacks 在 API 14-Android 4.0才出現的。Android在API 14之後,在Application類中,提供了一個應用生命週期回撥的註冊方法,用來對應用的生命週期進行集中管理,這個介面叫registerActivityLifecycleCallbacks,可以通過它註冊自己的ActivityLifeCycleCallback,每一個Activity的生命週期都會回撥到這裡的對應方法。其實這個註冊方法的本質和我們實現BaseActivity是一樣的,只是將生命週期的管理移到了Activity本身的實現中。

> 需求3程式碼實現如下(>= APi 14):

public int count = 0;
private long standardCompareTime = 10000;//比較時間是否會超過30分鐘 30 * 60 * 1000 TODO
//Log.e("1", "run:--------->當前類名: "+ getClass().getSimpleName());
private void monitorAppFrontBackstage() {//監聽App前後臺狀態
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {//API 14:Android 4.0
            @Override
            public void onActivityStopped(Activity activity) {
                LogUtil.e("desaco", activity + "onActivityStopped");
                count--;
                if (count == 0) {
                    LogUtil.e("desaco", ">>>>>>>>>>>>>>>>>>>切到後臺  lifecycle");
                    PreferencesManager.getInstance().put("time_is_show_ads", System.currentTimeMillis());
                }
            }

            @Override
            public void onActivityStarted(Activity activity) {
                LogUtil.e("desaco", activity + "onActivityStarted");
                long oldTime = PreferencesManager.getInstance().get("time_is_show_ads", 0l);
                long newTime = System.currentTimeMillis();
                long interval = newTime - oldTime;
                LogUtil.e("desaco", "切到前臺 oldTime="+oldTime+",,,newTime="+newTime+",,interval="+interval);
                if (count == 0) {
                    LogUtil.e("desaco", ">>>>>>>>>>>>>>>>>>>切到前臺  lifecycle");
                    if (oldTime > 0 && interval > standardCompareTime) {
//                        LogUtil.e("desaco", "activity name=" + activity.getClass().getSimpleName());
                        LogUtil.e("desaco", "需要展示廣告!!!");
                        Intent intent = new Intent(activity, LoadingActivity.class);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        intent.putExtra(ConstantAttr.SHOW_ADS_PAGE, true);
                        startActivity(intent);
                    }
                    PreferencesManager.getInstance().put("time_is_show_ads", 0l);
                }
                count++;
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
//                LogUtil.e("desaco", activity + "onActivitySaveInstanceState");
            }

            @Override
            public void onActivityResumed(Activity activity) {
                LogUtil.e("desaco", activity + "onActivityResumed");
            }

            @Override
            public void onActivityPaused(Activity activity) {
                LogUtil.e("desaco", activity + "onActivityPaused");
            }

            @Override
            public void onActivityDestroyed(Activity activity) {
                LogUtil.e("desaco", activity + "onActivityDestroyed");
            }

            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                LogUtil.e("desaco", activity + "onActivityCreated");
            }
        });

    }

> 需求3,API14之前可以考慮這個(< APi 14):在App的Activity基類中開始和結束計時

/**
 * Created by desaco on 2018/1/16.
 * 應用處於非啟用狀態超過30min後,再進入啟用狀態,展示LoadingActivity頁(主要是用來展示廣告),
 */
public class StatAppInactiveTimeUtils {
    private StatAppInactiveTimeUtils() {
    }
    private static StatAppInactiveTimeUtils singleton = null;
    public static StatAppInactiveTimeUtils getInstance() {
        if (singleton == null) {
            synchronized (StatAppInactiveTimeUtils.class) {
                if (singleton == null) {
                    singleton = new StatAppInactiveTimeUtils();
                }
            }
        }
        return singleton;
    }

    /**
     * onStop()生命週期中開始計時,onReStart()計時結束
     */
    private static long startTime;//開始計時時間;

    //開啟計時 關閉計時 重新計時(計時器)
    public void startStatTime() {
        startTime = System.currentTimeMillis();
    }

    //關閉計時,並清空
    public void endAndClearStatTime() {
        startTime = 0;
    }

    //獲取開始計時時間
    public long getStartTime() {
        return startTime;
    }

    //--------------------------------
    /**
     * 計算一個頁面從onResume()到onPause()花了多少時間,即頁面停留了多長時間
     * 當頁面停留時間大於30min,則不跳廣告
     */
    private static long onResumeStartTime;//記錄執行onResume()方法時的當前時間
    private static long onPauseEndTime;//記錄執行onPause()方法時的當前時間
//    private static long onStopCurrentTime;

    public void statOnResumeStartTime() {
        onResumeStartTime = System.currentTimeMillis();
    }

    public void statOnPauseEndTime() {
        onPauseEndTime = System.currentTimeMillis();
    }

    public long getOnResumeStartTime() {
        return onResumeStartTime;
    }

    public long getOnPauseEndTime() {
        return onPauseEndTime;
    }

//    public long getOnStopCurrentTime() {
//        onStopCurrentTime = System.currentTimeMillis();
//        return onStopCurrentTime;
//    }

    public void resetAfterKeyPress() {//按HOME、電源鍵後重新計時
        StatAppInactiveTimeUtils.getInstance().statOnResumeStartTime();
        StatAppInactiveTimeUtils.getInstance().statOnPauseEndTime();
    }
}