Android将后台应用唤起到前台的方法- https://blog.csdn.net/ShareUs/article/details/72902947
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本身的实现中。
Android API- https://developer.android.com/reference/android/app/Application.ActivityLifecycleCallbacks.html
> 需求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();
}
}