Android 关于后台杀死App之后改变服务器状态的一些尝试

一万年来谁著史,三千里外欲封侯。这篇文章主要讲述Android 关于后台杀死App之后改变服务器状态的一些尝试相关的知识,希望能为你提供帮助。
前言:如题,我的需求是:我需要在App在后台运行(未退出),调出最近运行记录,杀死App服务时,程序能够向服务器发送一条指令,以此达到我想要的目的。
android方面刚刚才开始玩,我一开始想的是可不可以在Activity中监听到,比如onDestroy()方法,但是打Log看了之后是没有的。度娘是万能的,百度一波后,我在逼乎上找到了另一个思路,那就是创建一个Server,很多人的博客中也都指出了,App在后台被杀死时,Service的onTaskRemoved()方法是可以监听到的。
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 { 13private static final String TAG = "SimpleService"; 14 15/** 16* 绑定服务时才会调用 17* 必须要实现的方法 18* @param intent 19* @return 20*/ 21@Nullable 22@Override 23public IBinder onBind(Intent intent) { 24Log.d(TAG, "onBind: "); 25return null; 26} 27 28/** 29* 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。 30* 如果服务已在运行,则不会调用此方法。该方法只被调用一次 31*/ 32@Override 33public void onCreate() { 34super.onCreate(); 35} 36 37/** 38* 每次通过startService()方法启动Service时都会被回调。 39* @param intent 40* @param flags 41* @param startId 42* @return 43*/ 44@Override 45public int onStartCommand(Intent intent, int flags, int startId) { 46return START_STICKY; 47} 48 49/** 50* 服务销毁时的回调 51*/ 52@Override 53public void onDestroy() { 54super.onDestroy(); 55} 56 57@Override 58public void onStart(Intent intent, int startId) { 59super.onStart(intent, startId); 60} 61 62@Override 63public void onConfigurationChanged(Configuration newConfig) { 64super.onConfigurationChanged(newConfig); 65} 66 67@Override 68public void onLowMemory() { 69super.onLowMemory(); 70} 71 72@Override 73public void onTrimMemory(int level) { 74super.onTrimMemory(level); 75} 76 77@Override 78public boolean onUnbind(Intent intent) { 79return super.onUnbind(intent); 80} 81 82@Override 83public void onRebind(Intent intent) { 84super.onRebind(intent); 85Log.d(TAG, "onRebind: "); 86} 87 88@Override 89public void onTaskRemoved(Intent rootIntent) { 90super.onTaskRemoved(rootIntent); 91new Thread(new Runnable() { 92@Override 93public void run() { 94UserHttpClientUtil.exitCurrentAccount(LoginActivity.userInfoMapContextCache.get("userNo")); 95} 96}).start(); 97} 98 99 }

然后,在Activity中启动它
1 intent = new Intent(this, SimpleService.class); 2 getApplicationContext().startService(intent);

AndroidManifest.xml中
1 < service 2android:name=".SimpleService" 3android:enabled="true" 4android: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 { 14private static AndroidApplication instance; 15private static final String TAG = "AndroidApplication"; 16@Override 17public void onCreate() { 18super.onCreate(); 19instance = this; 20Intent intentService = new Intent(this, SimpleService.class); 21getApplicationContext().startService(intentService); 22} 23 24public static AndroidApplication getInstance(){ 25return instance; 26} 27 }

但是结果仍然是一样的
执念:我始终认为这一种方法是可行的,可能是我哪一方面写的有问题,如果有大神看出,望指正,不胜感激。
这种方法暂时是走不通了,但是问题总是要解决的。经过一番思考,想出了一个上不得台面的方法:我其实需要的是在App在后台被杀死的情况下(非程序崩溃),改变一下用户的状态,那么我可不可以在程序中监听App处于前台还是后台,当处于前台时,每进入一个页面,我都更新一下状态为在线(这是为了无论从哪个页面进入后台,App再次进入前台时,状态都能够更新,这个可以在ActivityLifecycleCallbacks的onActivityResumed()方法中实现),当App位于后台运行时,我就更新状态为离线(我使用了Application中的onTrimMemory()方法来实现)。
一条小路:首先,需要判断一个App处于前台还是后台
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 25private static int resumed; 26private static int paused; 27private static int started; 28private static int stopped; 29 30@Override 31public void onActivityCreated(Activity activity, Bundle bundle) { 32 33} 34 35@Override 36public void onActivityStarted(Activity activity) { 37++started; 38} 39 40private Map< String, String> UpdateCurrentAccountMap = new HashMap< > (); 41private Context context; 42@Override 43public void onActivityResumed(Activity activity) { 44++resumed; 45context = activity.getApplicationContext(); 46new Thread(new Runnable() { 47@Override 48public void run() { 49if (userInfoMapContextCache.get("userNo") != null & & userInfoMapContextCache.get("userNo") != "") { 50UpdateCurrentAccountMap = UserHttpClientUtil.UpdateCurrentAccount(userInfoMapContextCache.get("userNo")); 51loginHandler.sendEmptyMessage(0); 52} 53} 54}).start(); 55} 56 57private Handler loginHandler = new Handler(){ 58@Override 59public void handleMessage(Message msg) { 60if (!UpdateCurrentAccountMap.get("lastLoginTime").equals(userInfoMapContextCache.get("lastLoginTime"))) { 61userInfoMapContextCache.clear(); 62Intent intent = new Intent(context, LoginActivity.class); 63intent.putExtra("isAccountReset", "true"); 64context.startActivity(intent); 65Toast.makeText(context, "当前账号已经在其他地方登陆,请重新登陆!", Toast.LENGTH_SHORT).show(); 66} 67} 68}; 69 70@Override 71public void onActivityPaused(Activity activity) { 72++paused; 73} 74 75@Override 76public void onActivityStopped(Activity activity) { 77++stopped; 78} 79 80@Override 81public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { 82 83} 84 85@Override 86public void onActivityDestroyed(Activity activity) { 87 88} 89 90public static boolean isApplicationVisible() { 91return started > stopped; 92} 93 94public static boolean isApplicationInForeground() { 95// 当所有 Activity 的状态中处于 resumed 的大于 paused 状态的,即可认为有Activity处于前台状态中 96return 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 { 14private static AndroidApplication instance; 15private static final String TAG = "AndroidApplication"; 16@Override 17public void onCreate() { 18super.onCreate(); 19instance = this; 20registerActivityLifecycleCallbacks(new MyLifecycleHandler()); 21} 22 23public static AndroidApplication getInstance(){ 24return instance; 25} 26 27@Override 28public void onTrimMemory(int level) { 29super.onTrimMemory(level); 30if (!MyLifecycleHandler.isApplicationInForeground()) { 31new Thread(new Runnable() { 32@Override 33public void run() { 34if (userInfoMapContextCache.get("userNo") != null & & userInfoMapContextCache.get("userNo") != "") { 35UserHttpClientUtil.exitCurrentAccount(userInfoMapContextCache.get("userNo")); 36} 37} 38}).start(); 39} 40} 41 42@Override 43public void onLowMemory() { 44super.onLowMemory(); 45Log.d(TAG, "onLowMemory: "); 46} 47 48@Override 49public void onTerminate() { 50super.onTerminate(); 51Log.d(TAG, "onTerminate: "); 52} 53 54@Override 55public void onConfigurationChanged(Configuration newConfig) { 56super.onConfigurationChanged(newConfig); 57Log.d(TAG, "onConfigurationChanged: "); 58} 59 }

不要忘记将你重写的Application在AndroidManifest中说明
< application android:name=".AndroidApplication"

但是这种方法有一个坏处,就是在调用系统相机或者相册时,App也是出于后台的,这跟当初的设计理念不符
最后:【Android 关于后台杀死App之后改变服务器状态的一些尝试】我感觉Android应该是有监听到App在后台被杀死的方法的,我问了老板和一些搞Android的兄弟,都没有得到想要的答案,如果有大神知晓,望告知,不胜感激!!!

    推荐阅读