前言:

  如题,我的需求是:我需要在App在后台运行(未退出),调出最近运行记录,杀死App服务时,程序能够向服务器发送一条指令,以此达到我想要的目的。

  Android方面刚刚才开始玩,我一开始想的是可不可以在Activity中监听到,比如onDestroy()方法,但是打Log看了之后是没有的。度娘是万能的,百度一波后,我在逼乎上找到了另一个思路,那就是创建一个Server,很多人的博客中也都指出了,App在后台被杀死时,Service的onTaskRemoved()方法是可以监听到的。

Service的onTaskRemoved()监听App在后台被杀死:

  首先,一个Service类是必要的,其中onTaskRemoved()中的Http请求就是我需要跟服务器的交互

 package com.example.demo02;

 import android.app.Service;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log; import com.example.http.UserHttpClientUtil; public class SimpleService extends Service {
private static final String TAG = "SimpleService"; /**
* 绑定服务时才会调用
* 必须要实现的方法
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: ");
return null;
} /**
* 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。
* 如果服务已在运行,则不会调用此方法。该方法只被调用一次
*/
@Override
public void onCreate() {
super.onCreate();
} /**
* 每次通过startService()方法启动Service时都会被回调。
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
} /**
* 服务销毁时的回调
*/
@Override
public void onDestroy() {
super.onDestroy();
} @Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
} @Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
} @Override
public void onLowMemory() {
super.onLowMemory();
} @Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
} @Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
} @Override
public void onRebind(Intent intent) {
super.onRebind(intent);
Log.d(TAG, "onRebind: ");
} @Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
new Thread(new Runnable() {
@Override
public void run() {
UserHttpClientUtil.exitCurrentAccount(LoginActivity.userInfoMapContextCache.get("userNo"));
}
}).start();
} }

  然后,在Activity中启动它

 intent = new Intent(this, SimpleService.class);
getApplicationContext().startService(intent);

  AndroidManifest.xml中

 <service
android:name=".SimpleService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.demo02.AndroidApplication.intentService" />
</intent-filter>
</service>

  但是,我在测试的发现这种监听好像并不稳定,有时是可以监听到的,有时又监听不到,这肯定是不行的。(老式的Android是长按Home间调出最近运行记录,但是新式的Android并不是这样了,我不知道是不是这方面的原因)后来我又尝试重写Application,在Application中启动Service

 package com.example.demo02;

 import android.app.Application;
import android.content.res.Configuration;
import android.util.Log; import com.example.common.DefaultExceptionHandler;
import com.example.common.MyLifecycleHandler;
import com.example.http.UserHttpClientUtil; import static com.example.demo02.LoginActivity.userInfoMapContextCache; public class AndroidApplication extends Application {
private static AndroidApplication instance;
private static final String TAG = "AndroidApplication";
@Override
public void onCreate() {
super.onCreate();
instance = this;
Intent intentService = new Intent(this, SimpleService.class);
getApplicationContext().startService(intentService);
} public static AndroidApplication getInstance(){
return instance;
}
}

  但是结果仍然是一样的

  执念:我始终认为这一种方法是可行的,可能是我哪一方面写的有问题,如果有大神看出,望指正,不胜感激。

  这种方法暂时是走不通了,但是问题总是要解决的。经过一番思考,想出了一个上不得台面的方法:我其实需要的是在App在后台被杀死的情况下(非程序崩溃),改变一下用户的状态,那么我可不可以在程序中监听App处于前台还是后台,当处于前台时,每进入一个页面,我都更新一下状态为在线(这是为了无论从哪个页面进入后台,App再次进入前台时,状态都能够更新,这个可以在ActivityLifecycleCallbacks的onActivityResumed()方法中实现),当App位于后台运行时,我就更新状态为离线(我使用了Application中的onTrimMemory()方法来实现)。

一条小路:

  首先,需要判断一个App处于前台还是后台

 package com.example.common;

 import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast; import com.example.demo02.LoginActivity;
import com.example.http.UserHttpClientUtil; import java.util.HashMap;
import java.util.Map; import static com.example.demo02.LoginActivity.userInfoMapContextCache; /**
* 判断一个App处于前台还是后台
*/
public class MyLifecycleHandler implements Application.ActivityLifecycleCallbacks{ private static int resumed;
private static int paused;
private static int started;
private static int stopped; @Override
public void onActivityCreated(Activity activity, Bundle bundle) { } @Override
public void onActivityStarted(Activity activity) {
++started;
} private Map<String, String> UpdateCurrentAccountMap = new HashMap<>();
private Context context;
@Override
public void onActivityResumed(Activity activity) {
++resumed;
context = activity.getApplicationContext();
new Thread(new Runnable() {
@Override
public void run() {
if (userInfoMapContextCache.get("userNo") != null && userInfoMapContextCache.get("userNo") != "") {
UpdateCurrentAccountMap = UserHttpClientUtil.UpdateCurrentAccount(userInfoMapContextCache.get("userNo"));
loginHandler.sendEmptyMessage(0);
}
}
}).start();
} private Handler loginHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (!UpdateCurrentAccountMap.get("lastLoginTime").equals(userInfoMapContextCache.get("lastLoginTime"))) {
userInfoMapContextCache.clear();
Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra("isAccountReset", "true");
context.startActivity(intent);
Toast.makeText(context, "当前账号已经在其他地方登陆,请重新登陆!", Toast.LENGTH_SHORT).show();
}
}
}; @Override
public void onActivityPaused(Activity activity) {
++paused;
} @Override
public void onActivityStopped(Activity activity) {
++stopped;
} @Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override
public void onActivityDestroyed(Activity activity) { } public static boolean isApplicationVisible() {
return started > stopped;
} public static boolean isApplicationInForeground() {
// 当所有 Activity 的状态中处于 resumed 的大于 paused 状态的,即可认为有Activity处于前台状态中
return resumed > paused;
}
}

  然后,重写Application

 package com.example.demo02;

 import android.app.Application;
import android.content.res.Configuration;
import android.util.Log; import com.example.common.DefaultExceptionHandler;
import com.example.common.MyLifecycleHandler;
import com.example.http.UserHttpClientUtil; import static com.example.demo02.LoginActivity.userInfoMapContextCache; public class AndroidApplication extends Application {
private static AndroidApplication instance;
private static final String TAG = "AndroidApplication";
@Override
public void onCreate() {
super.onCreate();
instance = this;
registerActivityLifecycleCallbacks(new MyLifecycleHandler());
} public static AndroidApplication getInstance(){
return instance;
} @Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (!MyLifecycleHandler.isApplicationInForeground()) {
new Thread(new Runnable() {
@Override
public void run() {
if (userInfoMapContextCache.get("userNo") != null && userInfoMapContextCache.get("userNo") != "") {
UserHttpClientUtil.exitCurrentAccount(userInfoMapContextCache.get("userNo"));
}
}
}).start();
}
} @Override
public void onLowMemory() {
super.onLowMemory();
Log.d(TAG, "onLowMemory: ");
} @Override
public void onTerminate() {
super.onTerminate();
Log.d(TAG, "onTerminate: ");
} @Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d(TAG, "onConfigurationChanged: ");
}
}

  不要忘记将你重写的Application在AndroidManifest中说明

<application
android:name=".AndroidApplication"

  但是这种方法有一个坏处,就是在调用系统相机或者相册时,App也是出于后台的,这跟当初的设计理念不符

最后:

  我感觉Android应该是有监听到App在后台被杀死的方法的,我问了老板和一些搞Android的兄弟,都没有得到想要的答案,如果有大神知晓,望告知,不胜感激!!!

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

  1. Android学习系列(7)--App轮询服务器消息

    这篇文章是android开发人员的必备知识. 1.轮询服务器     一般的应用,定时通知消息可以采用轮询的方法从服务器拿取消息,当然实时消息通知的话,建议采用推送服务.    其中需要注意轮询的频率 ...

  2. Android中实现进入App之后检查网络状态

    1,注册广播,一般使用静动态注册,即当程序退出的时候广播接受者就收不到消息使用方法context.registerReceiver()方法在MainActivity中的OnStart()方法中执行注册 ...

  3. Android学习第八弹之改变状态栏的颜色使其与APP风格一体化

    公众号:smart_android 作者:耿广龙|loonggg 点击"阅读原文",可查看更多内容和干货 导语:沉浸式状态栏,改变状态栏的颜色使之与APP风格一体化是不是感觉很漂亮 ...

  4. Android中后台的劳动者“服务”

    前言 作为四大组件之一的Service,想必不少开发者都是了解的,那具体熟悉吗?是不是对Service中的每个知识点是否了解,它与Activity的关系又是什么样的,我们所理解的后台服务跟Servic ...

  5. Android+Tomcat通过http获取本机服务器资源

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  6. 移动端测试===Android内存管理: 理解App的PSS

    Android内存管理: 理解App的PSS 原文链接:http://www.littleeye.co/blog/2013/06/11/android-memory-management-unders ...

  7. Android内存优化6 了解Android是如何管理App内存

    1, Dalvik & ART Android在4.4之前一直使用的Dalvik虚拟机作为App的运行VM的, 4.4中引入了ART作为开发者备选, 5.0起正式将ART作为默认VM了. 我们 ...

  8. android+nutz后台如何上传和下载图片

    android+nutz后台如何上传和下载图片  发布于 588天前  作者 yummy222  428 次浏览  复制  上一个帖子  下一个帖子  标签: 无 最近在做一个基于android的ap ...

  9. 基于Android开发的天气预报app(源码下载)

    原文:基于Android开发的天气预报app(源码下载) 基于AndroidStudio环境开发的天气app -系统总体介绍:本天气app使用AndroidStudio这个IDE工具在Windows1 ...

随机推荐

  1. Android 结束进程的方法forceStopPackage

    ActivityManager sd = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE); Method method = Clas ...

  2. 在C#中动态编译T4模板代码

    转: http://www.wxzzz.com/1438.html 资料: https://cnsmartcodegenerator.codeplex.com/SourceControl/latest ...

  3. iOS 结构简单清晰的 设置页面

    这个是也是看了人家的代码,觉得甚是简单清晰,也是比较容易扩展.拿来学习一下 效果展示: 重点有以下2处: 1 .建立groupModel 列清组元素:当前组list 集合, 是否有header 或者 ...

  4. spring data jpa是什么?

    JPA是一个Java编程语言接口规范,Hibernate ORM是JPA规范的一个实现.   Spring Data JPA能干什么 在开始之前,先举个简单的例子. 一张表user有三个字段,id.n ...

  5. [转]u盘读不出来怎么办大汇总

    今天遇到的问题 http://www.upantool.com/jiaocheng/xiufu/2016/9958.html u盘读不出来怎么办大汇总 2016-12-14 21:42 来源: 本站整 ...

  6. 基于IG的特征评分方法

    本文简单介绍了熵.信息增益的概念,以及如何使用信息增益对监督学习的训练样本进行评估,评估每个字段的信息量. 1.熵的介绍       在信息论里面,熵是对不确定性的测量.通俗来讲,熵就是衡量随机变量随 ...

  7. debian下使用dynamic printk分析usb网卡驱动

    在<debian下使用dynamic printk分析usb转串口驱动执行流程>中使用了usb转串口,当前例子使用usb网卡分析驱动(dm9601芯片). 仍然需要使能dynamic pr ...

  8. 文件系统中跳转【TLCL】

    pwd - Print name of current working directory cd - Change directory ls - List directory contents Lin ...

  9. Linux Ctrl+Z VS Ctrl+C 以及+Z的使用方法

    问题及处理: Ctrl+Z是将任务中断,但是此任务并没有结束,他仍然在进程中他只是维持挂起的状态,用户可以使用fg/bg操作继续前台或后台的任务,fg命令重新启动前台被中断的任务,bg命令把被中断的任 ...

  10. Mac键盘图标与对应快捷按键标志汇总 分类

    Mac键盘图标与对应快捷按键 ⌘——Command () win键 ⌃ ——Control ctrl键 ⌥——Option (alt) ⇧——Shift ⇪——Caps Lock fn——功能键就是 ...