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 ...
随机推荐
- SQLServer导入Excel,复杂操作
导入Excel 先导入的时候报错了, 提示未在本地计算机上注册"Microsoft.ACE.Oledb.12.0"提供程序.(System.Data),去网址下个软件安装就搞定了, ...
- python3 多线程编程
python / 并发 / 线程 / 对象 / 编程 0.什么是线程 1. 多线程模块 2. 创建线程的方法 3. join()方法 4.isAlive()方法 5. name属性和daemon属 ...
- Springboot WebSocket例子
Springboot整合WebSocket 1.application.properties #设置服务端口号 server.port=8080 #thymeleaf配置 #是否启用模板缓存. spr ...
- tomcat8配置tomcat-users.xml不生效
一般想进入tomcat管理后台,只要在tomcat-users.xml配置文件中添加一下内容即可 <role rolename="manager-gui"/> < ...
- SOA 面向服务架构 阅读笔记(五)
14 SOA 服务管理器 契约:契约中必须明确定义双方的责任,否则就会产生混乱. SOA可以管理端到端的流程. IT技术一直是与业务对齐的. 14.1.1 分解IT层 业务服务层 管道层 硬件层 管道 ...
- jQuery带缩略图焦点图插件
在线演示 本地下载
- SQL Server 利用WITH AS递归获取层级关系数据
WITH AS短语,也叫做子查询部分(subquery factoring),在SQL Server 2005中提供了一种解决方案,这就是公用表表达式(CTE),使用CTE,可以使SQL语句的可维护性 ...
- nginx的理解
1.静态HTTP服务器 首先,Nginx是一个HTTP服务器,可以将服务器上的静态文件(如HTML.图片)通过HTTP协议展现给客户端. 配置: 2.反向代理服务器 什么是反向代理? 客户端本来可以直 ...
- Elasticsearch Suggester 学习
suggester搜索就像百度搜索框中的提示类似. Elasticsearch 中提供类似的搜索功能. 答案就在Suggesters API. Suggesters基本的运作原理是将输入的文本分解为t ...
- ubuntu12.04 错误:phonon: No such file or directory; phonon模块的安装
http://blog.csdn.net/xsl1990/article/details/9009919 错误:phonon: No such file or directory 1)sudo ap ...