Android實現后臺返回前臺再次顯示廣告

Android實現后臺返回前臺再次顯示廣告

市面上主流的APP都是在啟動頁做廣告展示的,即通常都是叫SplashActivity的是APP的launcher頁面,在manifest文件中配置, 2017年以來, 你會發現越來越多的APP在進入后臺時隔一定時間后再次回到前臺會再次顯示廣告界面, 3s自動播放, 或者手動點擊跳過

1461514126877_.pic.jpg

比如網易云音樂, 淘寶, 京東商城啦, 似乎現在都是很主流的做法了,剛好最近項目中也有這樣的需求, 我們也實現了一遍,所以寫出來分享下,相互學習借鑒

要實現后臺返回前臺顯示廣告的邏輯, 主要的點在于監聽APP進入后臺的時間點, 和APP從后臺返回到前臺的時間點

我們是在Application子類中完成的, 定義三個常量記錄當前APP狀態

 // 正常狀態
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中需要監聽Activity的生命周期變化, registerActivityLifecycleCallbacks是application類已經提供好的一個方法, 它可以非常方便的監聽整個項目中的所有activity的生命周期

// Application類中的內部類接口
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的生命周期函數都會回調到ActivityLifecycleCallbacks接口來, 我們讓Application實現此接口, 并在相應的回調方法中的完成具體的后臺狀態的監聽

定義幾個需要用的變量記錄相關狀態和時間

// APP狀態
private static int sAppState = STATE_NORMAL;
// 標記程序是否已進入后臺(依據onStop回調)
private boolean flag;
// 標記程序是否已進入后臺(依據onTrimMemory回調)
private boolean background;
// 從前臺進入后臺的時間
private static long frontToBackTime;
// 從后臺返回前臺的時間
private static long backToFrontTime;

在onResume回調中監聽回到前臺的判斷, 只要activity一旦獲取焦點這個方法都會觸發,并且會觸發多次

@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回調中監聽程序進入后臺的判斷

@Override
public void onActivityStopped(@NonNull Activity activity) {
        //判斷當前activity是否處于前臺
        if (!SystemUtils.isCurAppTop(activity)) {
            // 從前臺進入后臺
            sAppState = STATE_FRONT_TO_BACK;
            frontToBackTime = System.currentTimeMillis();
            flag = true;
            Log.e(TAG, "onStop: " + "STATE_FRONT_TO_BACK");
        } else {
            // 否則是正常狀態
            sAppState = STATE_NORMAL;
        }
 }

在onTrimMemory中監聽應用程序的切換,這也是一種監聽方式.因為有時候onStop的回調不一定會完全執行(尤其是切換最近使用APP列表時),所以這個方法也是必須的

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    // TRIM_MEMORY_UI_HIDDEN是UI不可見的回調, 通常程序進入后臺后都會觸發此回調,大部分手機多是回調這個參數
    // TRIM_MEMORY_BACKGROUND也是程序進入后臺的回調, 不同廠商不太一樣, 魅族手機就是回調這個參數
    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;
    }

}

最后, 就可以得到當前APP的準確狀態(sAppState)了, 是否可以再次顯示廣告

/**
 * 進入后臺間隔10分鐘以后可以再次顯示廣告
 *
 * @return 是否能顯示廣告
 */
public static boolean canShowAd() {
    return sAppState == STATE_BACK_TO_FRONT &&
            (backToFrontTime - frontToBackTime) > 10 * 60 * 1000;
}

測試過程中,發現大部分品牌的手機都是OK的, 但是也有意外的,OPPO R9在切換應用時,一個回調都沒觸發,一定是Color OS改動太大, 目前尚無法處理.OV手機適配起來就是費勁啊

最后補充一個判斷程序是否前臺的API

/**
 * 判斷當前程序是否前臺進程
 *
 * @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;
}

各位大佬們如果有更好的實現,歡迎提供思路!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容