Android實現(xiàn)后臺返回前臺再次顯示廣告
市面上主流的APP都是在啟動頁做廣告展示的,即通常都是叫SplashActivity的是APP的launcher頁面,在manifest文件中配置, 2017年以來, 你會發(fā)現(xiàn)越來越多的APP在進入后臺時隔一定時間后再次回到前臺會再次顯示廣告界面, 3s自動播放, 或者手動點擊跳過
比如網(wǎng)易云音樂, 淘寶, 京東商城啦, 似乎現(xiàn)在都是很主流的做法了,剛好最近項目中也有這樣的需求, 我們也實現(xiàn)了一遍,所以寫出來分享下,相互學(xué)習(xí)借鑒
要實現(xiàn)后臺返回前臺顯示廣告的邏輯, 主要的點在于監(jiān)聽APP進入后臺的時間點, 和APP從后臺返回到前臺的時間點
我們是在Application子類中完成的, 定義三個常量記錄當(dāng)前APP狀態(tài)
// 正常狀態(tài)
public static final int STATE_NORMAL = 0;
// 從后臺回到前臺
public static final int STATE_BACK_TO_FRONT = 1;
// 從前臺進入后臺
public static final int STATE_FRONT_TO_BACK = 2;
在Application中需要監(jiān)聽Activity的生命周期變化, registerActivityLifecycleCallbacks是application類已經(jīng)提供好的一個方法, 它可以非常方便的監(jiān)聽整個項目中的所有activity的生命周期
// Application類中的內(nèi)部類接口
public interface ActivityLifecycleCallbacks {
void onActivityCreated(Activity activity, Bundle savedInstanceState);
void onActivityStarted(Activity activity);
void onActivityResumed(Activity activity);
void onActivityPaused(Activity activity);
void onActivityStopped(Activity activity);
void onActivitySaveInstanceState(Activity activity, Bundle outState);
void onActivityDestroyed(Activity activity);
}
可以很清晰的看到Activity的生命周期函數(shù)都會回調(diào)到ActivityLifecycleCallbacks接口來, 我們讓Application實現(xiàn)此接口, 并在相應(yīng)的回調(diào)方法中的完成具體的后臺狀態(tài)的監(jiān)聽
定義幾個需要用的變量記錄相關(guān)狀態(tài)和時間
// APP狀態(tài)
private static int sAppState = STATE_NORMAL;
// 標(biāo)記程序是否已進入后臺(依據(jù)onStop回調(diào))
private boolean flag;
// 標(biāo)記程序是否已進入后臺(依據(jù)onTrimMemory回調(diào))
private boolean background;
// 從前臺進入后臺的時間
private static long frontToBackTime;
// 從后臺返回前臺的時間
private static long backToFrontTime;
在onResume回調(diào)中監(jiān)聽回到前臺的判斷, 只要activity一旦獲取焦點這個方法都會觸發(fā),并且會觸發(fā)多次
@Override
public void onActivityResumed(@NonNull Activity activity) {
if (background || flag) {
background = false;
flag = false;
sAppState = STATE_BACK_TO_FRONT;
backToFrontTime = System.currentTimeMillis();
Log.e(TAG, "onResume: STATE_BACK_TO_FRONT");
if (canShowAd()) {
ShowADActivity.show(activity);
}
} else {
sAppState = STATE_NORMAL;
}
}
在onStop回調(diào)中監(jiān)聽程序進入后臺的判斷
@Override
public void onActivityStopped(@NonNull Activity activity) {
//判斷當(dāng)前activity是否處于前臺
if (!SystemUtils.isCurAppTop(activity)) {
// 從前臺進入后臺
sAppState = STATE_FRONT_TO_BACK;
frontToBackTime = System.currentTimeMillis();
flag = true;
Log.e(TAG, "onStop: " + "STATE_FRONT_TO_BACK");
} else {
// 否則是正常狀態(tài)
sAppState = STATE_NORMAL;
}
}
在onTrimMemory中監(jiān)聽?wèi)?yīng)用程序的切換,這也是一種監(jiān)聽方式.因為有時候onStop的回調(diào)不一定會完全執(zhí)行(尤其是切換最近使用APP列表時),所以這個方法也是必須的
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
// TRIM_MEMORY_UI_HIDDEN是UI不可見的回調(diào), 通常程序進入后臺后都會觸發(fā)此回調(diào),大部分手機多是回調(diào)這個參數(shù)
// TRIM_MEMORY_BACKGROUND也是程序進入后臺的回調(diào), 不同廠商不太一樣, 魅族手機就是回調(diào)這個參數(shù)
if (level == Application.TRIM_MEMORY_UI_HIDDEN || level == TRIM_MEMORY_BACKGROUND) {
background = true;
} else if (level == Application.TRIM_MEMORY_COMPLETE) {
background = !SystemUtils.isCurAppTop(this);
}
if (background) {
frontToBackTime = System.currentTimeMillis();
sAppState = STATE_FRONT_TO_BACK;
logcat.e(TAG, "onTrimMemory: TRIM_MEMORY_UI_HIDDEN || TRIM_MEMORY_BACKGROUND");
} else {
sAppState = STATE_NORMAL;
}
}
最后, 就可以得到當(dāng)前APP的準(zhǔn)確狀態(tài)(sAppState)了, 是否可以再次顯示廣告
/**
* 進入后臺間隔10分鐘以后可以再次顯示廣告
*
* @return 是否能顯示廣告
*/
public static boolean canShowAd() {
return sAppState == STATE_BACK_TO_FRONT &&
(backToFrontTime - frontToBackTime) > 10 * 60 * 1000;
}
測試過程中,發(fā)現(xiàn)大部分品牌的手機都是OK的, 但是也有意外的,OPPO R9在切換應(yīng)用時,一個回調(diào)都沒觸發(fā),一定是Color OS改動太大, 目前尚無法處理.OV手機適配起來就是費勁啊
最后補充一個判斷程序是否前臺的API
/**
* 判斷當(dāng)前程序是否前臺進程
*
* @param context
* @return
*/
public static boolean isCurAppTop(Context context) {
if (context == null) {
return false;
}
String curPackageName = context.getPackageName();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> list = am.getRunningTasks(1);
if (list != null && list.size() > 0) {
RunningTaskInfo info = list.get(0);
String topPackageName = info.topActivity.getPackageName();
String basePackageName = info.baseActivity.getPackageName();
if (topPackageName.equals(curPackageName) && basePackageName.equals(curPackageName)) {
return true;
}
}
return false;
}
各位大佬們?nèi)绻懈玫膶崿F(xiàn),歡迎提供思路!