前言:
如題,個人需求是:我須要在App在後臺運行(未退出),調出最近運行記錄,殺死App服務時,程序可以向服務器發送一條指令,以此達到我想要的目的。java
Android方面剛剛纔開始玩,我一開始想的是可不能夠在Activity中監聽到,好比onDestroy()方法,可是打Log看了以後是沒有的。度娘是萬能的,百度一波後,我在逼乎上找到了另外一個思路,那就是建立一個Server,不少人的博客中也都指出了,App在後臺被殺死時,Service的onTaskRemoved()方法是能夠監聽到的。android
Service的onTaskRemoved()監聽App在後臺被殺死:
首先,一個Service類是必要的,其中onTaskRemoved()中的Http請求就是我須要跟服務器的交互服務器
1 package com.example.demo02; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.content.res.Configuration; 6 import android.os.IBinder; 7 import android.support.annotation.Nullable; 8 import android.util.Log; 9 10 import com.example.http.UserHttpClientUtil; 11 12 public class SimpleService extends Service { 13 private static final String TAG = "SimpleService"; 14 15 /** 16 * 綁定服務時纔會調用 17 * 必需要實現的方法 18 * @param intent 19 * @return 20 */ 21 @Nullable 22 @Override 23 public IBinder onBind(Intent intent) { 24 Log.d(TAG, "onBind: "); 25 return null; 26 } 27 28 /** 29 * 首次建立服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或 onBind() 以前)。 30 * 若是服務已在運行,則不會調用此方法。該方法只被調用一次 31 */ 32 @Override 33 public void onCreate() { 34 super.onCreate(); 35 } 36 37 /** 38 * 每次經過startService()方法啓動Service時都會被回調。 39 * @param intent 40 * @param flags 41 * @param startId 42 * @return 43 */ 44 @Override 45 public int onStartCommand(Intent intent, int flags, int startId) { 46 return START_STICKY; 47 } 48 49 /** 50 * 服務銷燬時的回調 51 */ 52 @Override 53 public void onDestroy() { 54 super.onDestroy(); 55 } 56 57 @Override 58 public void onStart(Intent intent, int startId) { 59 super.onStart(intent, startId); 60 } 61 62 @Override 63 public void onConfigurationChanged(Configuration newConfig) { 64 super.onConfigurationChanged(newConfig); 65 } 66 67 @Override 68 public void onLowMemory() { 69 super.onLowMemory(); 70 } 71 72 @Override 73 public void onTrimMemory(int level) { 74 super.onTrimMemory(level); 75 } 76 77 @Override 78 public boolean onUnbind(Intent intent) { 79 return super.onUnbind(intent); 80 } 81 82 @Override 83 public void onRebind(Intent intent) { 84 super.onRebind(intent); 85 Log.d(TAG, "onRebind: "); 86 } 87 88 @Override 89 public void onTaskRemoved(Intent rootIntent) { 90 super.onTaskRemoved(rootIntent); 91 new Thread(new Runnable() { 92 @Override 93 public void run() { 94 UserHttpClientUtil.exitCurrentAccount(LoginActivity.userInfoMapContextCache.get("userNo")); 95 } 96 }).start(); 97 } 98 99 }
而後,在Activity中啓動它app
1 intent = new Intent(this, SimpleService.class); 2 getApplicationContext().startService(intent);
AndroidManifest.xml中ide
1 <service 2 android:name=".SimpleService" 3 android:enabled="true" 4 android:exported="true"> 5 <intent-filter> 6 <action android:name="com.example.demo02.AndroidApplication.intentService" /> 7 </intent-filter> 8 </service>
可是,我在測試的發現這種監聽好像並不穩定,有時是能夠監聽到的,有時又監聽不到,這確定是不行的。(老式的Android是長按Home間調出最近運行記錄,可是新式的Android並非這樣了,我不知道是否是這方面的緣由)後來我又嘗試重寫Application,在Application中啓動Service測試
1 package com.example.demo02; 2 3 import android.app.Application; 4 import android.content.res.Configuration; 5 import android.util.Log; 6 7 import com.example.common.DefaultExceptionHandler; 8 import com.example.common.MyLifecycleHandler; 9 import com.example.http.UserHttpClientUtil; 10 11 import static com.example.demo02.LoginActivity.userInfoMapContextCache; 12 13 public class AndroidApplication extends Application { 14 private static AndroidApplication instance; 15 private static final String TAG = "AndroidApplication"; 16 @Override 17 public void onCreate() { 18 super.onCreate(); 19 instance = this; 20 Intent intentService = new Intent(this, SimpleService.class); 21 getApplicationContext().startService(intentService); 22 } 23 24 public static AndroidApplication getInstance(){ 25 return instance; 26 } 27 }
可是結果仍然是同樣的this
執念:我始終認爲這一種方法是可行的,多是我哪一方面寫的有問題,若是有大神看出,望指正,不勝感激。spa
這種方法暫時是走不通了,可是問題老是要解決的。通過一番思考,想出了一個上不得檯面的方法:我其實須要的是在App在後臺被殺死的狀況下(非程序崩潰),改變一下用戶的狀態,那麼我可不能夠在程序中監聽App處於前臺仍是後臺,當處於前臺時,每進入一個頁面,我都更新一下狀態爲在線(這是爲了不管從哪一個頁面進入後臺,App再次進入前臺時,狀態都可以更新,這個能夠在ActivityLifecycleCallbacks的onActivityResumed()方法中實現),當App位於後臺運行時,我就更新狀態爲離線(我使用了Application中的onTrimMemory()方法來實現)。設計
一條小路:
首先,須要判斷一個App處於前臺仍是後臺code
1 package com.example.common; 2 3 import android.app.Activity; 4 import android.app.Application; 5 import android.content.Context; 6 import android.content.Intent; 7 import android.os.Bundle; 8 import android.os.Handler; 9 import android.os.Message; 10 import android.widget.Toast; 11 12 import com.example.demo02.LoginActivity; 13 import com.example.http.UserHttpClientUtil; 14 15 import java.util.HashMap; 16 import java.util.Map; 17 18 import static com.example.demo02.LoginActivity.userInfoMapContextCache; 19 20 /** 21 * 判斷一個App處於前臺仍是後臺 22 */ 23 public class MyLifecycleHandler implements Application.ActivityLifecycleCallbacks{ 24 25 private static int resumed; 26 private static int paused; 27 private static int started; 28 private static int stopped; 29 30 @Override 31 public void onActivityCreated(Activity activity, Bundle bundle) { 32 33 } 34 35 @Override 36 public void onActivityStarted(Activity activity) { 37 ++started; 38 } 39 40 private Map<String, String> UpdateCurrentAccountMap = new HashMap<>(); 41 private Context context; 42 @Override 43 public void onActivityResumed(Activity activity) { 44 ++resumed; 45 context = activity.getApplicationContext(); 46 new Thread(new Runnable() { 47 @Override 48 public void run() { 49 if (userInfoMapContextCache.get("userNo") != null && userInfoMapContextCache.get("userNo") != "") { 50 UpdateCurrentAccountMap = UserHttpClientUtil.UpdateCurrentAccount(userInfoMapContextCache.get("userNo")); 51 loginHandler.sendEmptyMessage(0); 52 } 53 } 54 }).start(); 55 } 56 57 private Handler loginHandler = new Handler(){ 58 @Override 59 public void handleMessage(Message msg) { 60 if (!UpdateCurrentAccountMap.get("lastLoginTime").equals(userInfoMapContextCache.get("lastLoginTime"))) { 61 userInfoMapContextCache.clear(); 62 Intent intent = new Intent(context, LoginActivity.class); 63 intent.putExtra("isAccountReset", "true"); 64 context.startActivity(intent); 65 Toast.makeText(context, "當前帳號已經在其餘地方登錄,請從新登錄!", Toast.LENGTH_SHORT).show(); 66 } 67 } 68 }; 69 70 @Override 71 public void onActivityPaused(Activity activity) { 72 ++paused; 73 } 74 75 @Override 76 public void onActivityStopped(Activity activity) { 77 ++stopped; 78 } 79 80 @Override 81 public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { 82 83 } 84 85 @Override 86 public void onActivityDestroyed(Activity activity) { 87 88 } 89 90 public static boolean isApplicationVisible() { 91 return started > stopped; 92 } 93 94 public static boolean isApplicationInForeground() { 95 // 當全部 Activity 的狀態中處於 resumed 的大於 paused 狀態的,便可認爲有Activity處於前臺狀態中 96 return resumed > paused; 97 } 98 }
而後,重寫Application
1 package com.example.demo02; 2 3 import android.app.Application; 4 import android.content.res.Configuration; 5 import android.util.Log; 6 7 import com.example.common.DefaultExceptionHandler; 8 import com.example.common.MyLifecycleHandler; 9 import com.example.http.UserHttpClientUtil; 10 11 import static com.example.demo02.LoginActivity.userInfoMapContextCache; 12 13 public class AndroidApplication extends Application { 14 private static AndroidApplication instance; 15 private static final String TAG = "AndroidApplication"; 16 @Override 17 public void onCreate() { 18 super.onCreate(); 19 instance = this; 20 registerActivityLifecycleCallbacks(new MyLifecycleHandler()); 21 } 22 23 public static AndroidApplication getInstance(){ 24 return instance; 25 } 26 27 @Override 28 public void onTrimMemory(int level) { 29 super.onTrimMemory(level); 30 if (!MyLifecycleHandler.isApplicationInForeground()) { 31 new Thread(new Runnable() { 32 @Override 33 public void run() { 34 if (userInfoMapContextCache.get("userNo") != null && userInfoMapContextCache.get("userNo") != "") { 35 UserHttpClientUtil.exitCurrentAccount(userInfoMapContextCache.get("userNo")); 36 } 37 } 38 }).start(); 39 } 40 } 41 42 @Override 43 public void onLowMemory() { 44 super.onLowMemory(); 45 Log.d(TAG, "onLowMemory: "); 46 } 47 48 @Override 49 public void onTerminate() { 50 super.onTerminate(); 51 Log.d(TAG, "onTerminate: "); 52 } 53 54 @Override 55 public void onConfigurationChanged(Configuration newConfig) { 56 super.onConfigurationChanged(newConfig); 57 Log.d(TAG, "onConfigurationChanged: "); 58 } 59 }
不要忘記將你重寫的Application在AndroidManifest中說明
<application android:name=".AndroidApplication"
可是這種方法有一個壞處,就是在調用系統相機或者相冊時,App也是出於後臺的,這跟當初的設計理念不符
最後:
我感受Android應該是有監聽到App在後臺被殺死的方法的,我問了老闆和一些搞Android的兄弟,都沒有獲得想要的答案,若是有大神知曉,望告知,不勝感激!!!