應用前後臺切換,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" -
-- 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();
}
}