說到App的前后臺監(jiān)控呕诉,有什么使用場景呢吃度?例如:
IM模塊,收到消息時椿每,需要判斷當(dāng)前App是否在前臺,如果在前臺則震動一下提醒用戶亦渗,如果在后臺則發(fā)送一條通知提醒用戶。
收到Push推送汁尺,需要判斷App是否存活法精,如果存活則直接跳轉(zhuǎn)到目標(biāo)界面,如果不存活則先啟動App,再跳轉(zhuǎn)到目標(biāo)頁面亿虽。
有沒有簡便的Api
-
iOS上的AppDelegate
applicationDidEnterBackground方法回調(diào)提醒App處于后臺。
applicationWillEnterForeground方法回調(diào)提醒App處于前臺粘秆。
-
Android的Application
- 很遺憾,沒有攻走!
既然沒有此再,有沒有別的法子?
解決方案
其實獲取方法输拇,有好幾種:
通過ActivityManager.getRunningTasks()獲取當(dāng)前運行的task列表,需要遍歷逛裤,而且需要申請android.permission.GET_TASKS權(quán)限,而且5.0后被廢棄带族,5.0以上版本失效蟀给。
5.0后,ActivityManager提供了getRunningAppProcesses()方法獲取正在運行的應(yīng)用程序跋理,同樣需要遍歷,但不需要申請權(quán)限祠饺,但據(jù)說8.0后失效了汁政。
Application注冊ActivityLifecycleCallbacks,獲取App上的所有Activity生命周期改變的回調(diào)记劈,對onActivityStarted和onActivityStopped做計數(shù)即可,如果計數(shù)為0代表為后臺目木,大于0則為前臺懊渡,需要Api14以上军拟,就是4.0以上可使用。一般現(xiàn)在兼容都在4.4肾档,所以基本沒有兼容性問題,并且不需要申請權(quán)限怒见。
方案選擇
基于申請權(quán)限和不需要遍歷的性能消耗姑宽,我選擇了方案3。
新建一個單例類AppMonitor炮车,在Application中初始化,并注冊ActivityLifecycleCallbacks回調(diào)纪隙,我們再對生命周期回調(diào)進(jìn)行計數(shù)难审,并且提供我們自定義的回調(diào)即可亿絮。
提供initialize方法初始化AppMonitor告喊。
-
提供Callback接口
- 提供onAppForeground回調(diào)派昧,表示App切換到前臺。
- 提供onAppBackground回調(diào)秆吵,表示App切換到后臺五慈。
- 提供onAppUIDestroyed回調(diào),表示App所有界面都銷毀了泻拦,可以認(rèn)為就是App被“殺死”了。
public class AppMonitor {
/**
* 注冊了的監(jiān)聽器
*/
private List<Callback> mCallbacks;
/**
* 是否初始化了
*/
private boolean isInited;
/**
* 活躍Activity的數(shù)量
*/
private int mActiveActivityCount = 0;
/**
* 存活的Activity數(shù)量
*/
private int mAliveActivityCount = 0;
public static AppMonitor get() {
return SingleHolder.INSTANCE;
}
private static final class SingleHolder {
private static final AppMonitor INSTANCE = new AppMonitor();
}
public void initialize(Context context) {
if (isInited) {
return;
}
mCallbacks = new CopyOnWriteArrayList<>();
registerLifecycle(context);
isInited = true;
}
/**
* 注冊生命周期
*/
private void registerLifecycle(Context context) {
Application application = (Application) context.getApplicationContext();
application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mAliveActivityCount++;
}
@Override
public void onActivityStarted(Activity activity) {
mActiveActivityCount++;
notifyChange();
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
mActiveActivityCount--;
notifyChange();
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
mAliveActivityCount--;
notifyAppAliveChange();
}
});
}
/**
* 判斷App是否活著
*/
public boolean isAppAlive() {
return mAliveActivityCount > 0;
}
/**
* 判斷App是否在前臺
*/
public boolean isAppForeground() {
return mActiveActivityCount > 0;
}
/**
* 判斷App是否在后臺
*/
public boolean isAppBackground() {
return mActiveActivityCount <= 0;
}
/**
* 通知監(jiān)聽者
*/
private void notifyChange() {
if (mActiveActivityCount > 0) {
for (Callback callback : mCallbacks) {
callback.onAppForeground();
}
} else {
for (Callback callback : mCallbacks) {
callback.onAppBackground();
}
}
}
/**
* 通知監(jiān)聽者界面銷毀
*/
private void notifyAppAliveChange() {
if (mAliveActivityCount == 0) {
for (Callback callback : mCallbacks) {
callback.onAppUIDestroyed();
}
}
}
public interface Callback {
/**
* 當(dāng)App切換到前臺時回調(diào)
*/
void onAppForeground();
/**
* App切換到后臺時回調(diào)
*/
void onAppBackground();
/**
* App所有界面都銷毀了
*/
void onAppUIDestroyed();
}
public static class CallbackAdapter implements Callback {
@Override
public void onAppForeground() {
}
@Override
public void onAppBackground() {
}
@Override
public void onAppUIDestroyed() {
}
}
/**
* 注冊回調(diào)
*/
public void register(Callback callback) {
if (mCallbacks.contains(callback)) {
return;
}
mCallbacks.add(callback);
}
/**
* 注銷回調(diào)
*/
public void unRegister(Callback callback) {
if (!mCallbacks.contains(callback)) {
return;
}
mCallbacks.remove(callback);
}
}
使用
- 初始化
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//前后臺監(jiān)聽初始化
AppMonitor.get().initialize(this);
}
}
- 注冊監(jiān)聽和注銷監(jiān)聽
AppMonitor.Callback callback = new AppMonitor.Callback() {
@Override
public void onAppForeground() {
//App切換到前臺
}
@Override
public void onAppBackground() {
//App切換到后臺
}
@Override
public void onAppUIDestroyed() {
//App被殺死了
}
};
//注冊回調(diào)
AppMonitor.get().register(callback);
//注銷回調(diào)
AppMonitor.get().unRegister(callback);
- 判斷App是否在前臺
boolean isAppForeground = AppMonitor.get().isAppForeground();
- 判斷App是否在后臺
boolean isAppBackground = AppMonitor.get().isAppBackground();
- 判斷App是否存活(所有頁面都銷毀了)
boolean isAlive = AppMonitor.get().isAppAlive();
總結(jié)
雖然Android中沒有簡潔明了的Api,獲取前后臺狀態(tài)和回調(diào)闹瞧,但是好在我們可以自己動手豐衣足食展辞,滿足需求。