前言:

  如题,我的需求是:我需要在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. SQLServer导入Excel,复杂操作

    导入Excel 先导入的时候报错了, 提示未在本地计算机上注册"Microsoft.ACE.Oledb.12.0"提供程序.(System.Data),去网址下个软件安装就搞定了, ...

  2. python3 多线程编程

    python / 并发 / 线程 / 对象 / 编程   0.什么是线程 1. 多线程模块 2. 创建线程的方法 3. join()方法 4.isAlive()方法 5. name属性和daemon属 ...

  3. Springboot WebSocket例子

    Springboot整合WebSocket 1.application.properties #设置服务端口号 server.port=8080 #thymeleaf配置 #是否启用模板缓存. spr ...

  4. tomcat8配置tomcat-users.xml不生效

    一般想进入tomcat管理后台,只要在tomcat-users.xml配置文件中添加一下内容即可 <role rolename="manager-gui"/> < ...

  5. SOA 面向服务架构 阅读笔记(五)

    14 SOA 服务管理器 契约:契约中必须明确定义双方的责任,否则就会产生混乱. SOA可以管理端到端的流程. IT技术一直是与业务对齐的. 14.1.1 分解IT层 业务服务层 管道层 硬件层 管道 ...

  6. jQuery带缩略图焦点图插件

    在线演示 本地下载

  7. SQL Server 利用WITH AS递归获取层级关系数据

    WITH AS短语,也叫做子查询部分(subquery factoring),在SQL Server 2005中提供了一种解决方案,这就是公用表表达式(CTE),使用CTE,可以使SQL语句的可维护性 ...

  8. nginx的理解

    1.静态HTTP服务器 首先,Nginx是一个HTTP服务器,可以将服务器上的静态文件(如HTML.图片)通过HTTP协议展现给客户端. 配置: 2.反向代理服务器 什么是反向代理? 客户端本来可以直 ...

  9. Elasticsearch Suggester 学习

    suggester搜索就像百度搜索框中的提示类似. Elasticsearch 中提供类似的搜索功能. 答案就在Suggesters API. Suggesters基本的运作原理是将输入的文本分解为t ...

  10. 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 ...