Android 关于后台杀死App之后改变服务器状态的一些尝试
前言:
如题,我的需求是:我需要在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之后改变服务器状态的一些尝试的更多相关文章
- Android学习系列(7)--App轮询服务器消息
这篇文章是android开发人员的必备知识. 1.轮询服务器 一般的应用,定时通知消息可以采用轮询的方法从服务器拿取消息,当然实时消息通知的话,建议采用推送服务. 其中需要注意轮询的频率 ...
- Android中实现进入App之后检查网络状态
1,注册广播,一般使用静动态注册,即当程序退出的时候广播接受者就收不到消息使用方法context.registerReceiver()方法在MainActivity中的OnStart()方法中执行注册 ...
- Android学习第八弹之改变状态栏的颜色使其与APP风格一体化
公众号:smart_android 作者:耿广龙|loonggg 点击"阅读原文",可查看更多内容和干货 导语:沉浸式状态栏,改变状态栏的颜色使之与APP风格一体化是不是感觉很漂亮 ...
- Android中后台的劳动者“服务”
前言 作为四大组件之一的Service,想必不少开发者都是了解的,那具体熟悉吗?是不是对Service中的每个知识点是否了解,它与Activity的关系又是什么样的,我们所理解的后台服务跟Servic ...
- Android+Tomcat通过http获取本机服务器资源
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- 移动端测试===Android内存管理: 理解App的PSS
Android内存管理: 理解App的PSS 原文链接:http://www.littleeye.co/blog/2013/06/11/android-memory-management-unders ...
- Android内存优化6 了解Android是如何管理App内存
1, Dalvik & ART Android在4.4之前一直使用的Dalvik虚拟机作为App的运行VM的, 4.4中引入了ART作为开发者备选, 5.0起正式将ART作为默认VM了. 我们 ...
- android+nutz后台如何上传和下载图片
android+nutz后台如何上传和下载图片 发布于 588天前 作者 yummy222 428 次浏览 复制 上一个帖子 下一个帖子 标签: 无 最近在做一个基于android的ap ...
- 基于Android开发的天气预报app(源码下载)
原文:基于Android开发的天气预报app(源码下载) 基于AndroidStudio环境开发的天气app -系统总体介绍:本天气app使用AndroidStudio这个IDE工具在Windows1 ...
随机推荐
- Tips for Unix/Linux
@1: 在单个命令中创建目录树:不要逐层创建目录,尽量使用mkdir的-p选项: ~$ mkdir -p one/two/three # 假设目录one不存在 创建复杂的目录树: ~$ mkdir - ...
- 曾经跳过的坑------replace、替换斜杠反斜杠、时间格式化处理
JAVA 中: 坑一: replace没有用对象进行接收.直接使用 dateStr.replaceAll("\\/", "-"); 是不行的,至少得加上 &qu ...
- Oracle查询结果列的加减、求和、连接、列值相乘
select prod.amount,prod.plansum,(prod.plansum-prod.amount) as borrow,d.enum_value from ----结果集相减(sel ...
- openstack ocata版(脚本)控制节点安装
一.初始化环境: 1.更换yum源: yum install -y wget mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS- ...
- Loadrunder脚本篇——Run-time Settings之Preferences
打开Preferences设置对话框,这里提供了对运行时的参数选择设置 Enable Image and Text Check 开启图片和文本检查.允许用户在回放期间通过web_find(文本检测)或 ...
- 每天一个Linux命令(63)scp命令
scp(secure copy)用于进行远程文件拷贝. (1)用法: 用法: scp [参数] [源文件] [目标文件] (2)功能: 功能: scp在主机 ...
- Docker容器技术-Docker架构
一.Docker系统架构 1.Docker基础架构 1)Docker守护进程 负责容器的创建.运行和监控,以及镜像的构建和存储. docker daemon 2)Docker客户端 通过HTTP与Do ...
- 主攻ASP.NET MVC4.0之重生:Jquery Mobile 列表
代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title ...
- linux与windows 通过SecureCRT进行文件传输方式
linux与windows 通过SecureCRT进行文件传输方式 方式一:lrzsz是一款在Linux里可代替ftp上传和下载的程序.(小文件推荐,以4G为界限) # rz -bash: rz: c ...
- Spring的AOP面向切面编程
什么是AOP? 1.AOP概念介绍 所谓AOP,即Aspect orientied program,就是面向方面(切面)的编程. 功能: 让关注点代码与业务代码分离! 关注点: 重复代码就叫做关注点: ...