如何运行后台Service?
Unless you specify otherwise, most of the operations you do in an app run in the foreground on a special thread called the UI thread. 除非特别指定,一般情况下所有在前台执行的操作都运行在名为UI的线程中。可能会存在某些隐患,因为部分在UI界面上的耗时操作可能会影响到界面的响应性能。UI界面的性能问题会容易惹恼用户,甚至可能导致系统的ANR。为了避免这样的问题,Android Framework提供了几个类,用来帮助你把那些耗时操作移动到后台线程中执行。
This annoys your users, and can even cause system errors. To avoid this, the Android framework offers several classes that help you off-load operations onto a separate thread running in the background. 经常使用的是IntentService类。
主题一:如何创建IntentService实例? --> 创建后台Service
The IntentService class provides a straightforward structure for running an operation on a single background thread. This allows it to handle long-running operations without affecting your user interface's responsiveness. 可以处理一个耗时的任务并确保不影响到UI的响应性能,IntentService的运行不受UI生命周期的影响。
IntentService存在的一些局限性:
It can't interact directly with your user interface. To put its results in the UI, you have to send them to an Activity.
IntentService不能直接和Activity交互,必须将运行结果反馈给Activity。
Work requests run sequentially. If an operation is running in an IntentService, and you send it another request, the request waits until the first operation is finished.
工作任务队列是顺序执行的;如果一个任务在IntentService中执行,此时再发送一个新的任务请求,这个任务会一直等待直到前一个任务执行完成为止。
An operation running on an IntentService can't be interrupted.
在IntentService中运行的任务不会被打断,除非进程被kill。
虽然有上述的几点局限,但IntentService仍然是执行简单后台任务的最佳选择。
如何创建IntentService?
为了在app中创建IntentService组件,需要继承IntentService,并覆写onHandleIntent()。
public class RSSPullService extends IntentService {
@Override
protected void onHandleIntent(Intent workIntent) {
// Gets data from the incoming Intent
String dataString = workIntent.getDataString();
...
// Do work here, based on the contents of dataString
...
}
}
需要注意的是:其他Service中的回调方法,比如:onStartCommand()会被自动调用。因此,在IntentService中应该避免覆写这些回调方法。
如何在AndroidManifest.xml文件中声明该Service?
注意:IntentService同样需要在AndroidManifest.xml文件中声明,类似于Service。
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
...
<!--
Because android:exported is set to "false",
the service is only available to this app.
-->
<service
android:name=".RSSPullService"
android:exported="false"/>
...
<application/>
在<service>标签中并没有使用<intent-filter>,因此Activity需要使用显式Intent传递任务请求给IntentService。同时,也意味着只有在同一个app或者其他使用同一个UserID的组件才能够访问到这个Service。
主题二:向IntentService发送任务请求
如何发送一个Intent来触发IntentService执行后台任务?
通过Intent可以传递一些数据给后台任务,可以在Activity和Fragment的任何时间点发送这个Intent。
执行步骤如下:
步骤一:创建Intent对象
/*
* Creates a new Intent to start the RSSPullService
* IntentService. Passes a URI in the
* Intent's "data" field.
*/
mServiceIntent = new Intent(getActivity(), RSSPullService.class);
mServiceIntent.setData(Uri.parse(dataUrl));
必须是显式的Intent,同时可以附带有相关的数据。
步骤二:启动该Intent,执行startService(Intent intent)
// Starts the IntentService
getActivity().startService(mServiceIntent);
注意可以在Activity或者Fragment的任何位置发送任务请求。例如,如果你先获取用户输入,您可以从响应按钮单击或类似手势的回调方法里面发送任务请求。一旦执行了startService(),IntentService在自己本身的onHandleIntent()方法里面开始执行这个任务,任务结束之后,会自动停止这个Service。
主题三:返回IntentService执行结果
我们需要获取在IntentService中执行的结果,而IntentService则需要反馈执行的结果和任务执行的状态。比如:根据后台任务执行的进度,让Activity更新UI。推荐的方法是使用LocalBroadcastManager,这个类可以限制Broadcast中的Intent只在本地App中使用。
如何反馈执行状态?
在IntentService中,创建Intent,并通过广播的方式发送出去,该Intent则附带有状态信息。
public final class Constants {
...
// Defines a custom Intent action
public static final String BROADCAST_ACTION =
"com.example.android.threadsample.BROADCAST";
...
// Defines the key for the status "extra" in an Intent
public static final String EXTENDED_DATA_STATUS =
"com.example.android.threadsample.STATUS";
...
}
public class RSSPullService extends IntentService {
...
/*
* Creates a new Intent containing a Uri object
* BROADCAST_ACTION is a custom Intent action
*/
Intent localIntent =
new Intent(Constants.BROADCAST_ACTION)
// Puts the status into the Intent
.putExtra(Constants.EXTENDED_DATA_STATUS, status);
// Broadcasts the Intent to receivers in this app.
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
...
}
如何接受上述步骤发出的广播?
具体实践如下:
为了接受广播的数据对象,需要使用BroadcastReceiver的子类并实现BroadcastReceiver.onReceive() 的方法,这里可以接收LocalBroadcastManager发出的广播数据。
// Broadcast receiver for receiving status updates from the IntentService
private class ResponseReceiver extends BroadcastReceiver
{
// Prevents instantiation
private DownloadStateReceiver() {
}
// Called when the BroadcastReceiver gets an Intent it's registered to receive
@
public void onReceive(Context context, Intent intent) {
...
/*
* Handle Intents here.
*/
...
}
}
一旦定义了BroadcastReceiver,也应该定义actions,categories与data用过滤广播。为了实现这些,需要使用IntentFilter。
// Class that displays photos
public class DisplayActivity extends FragmentActivity {
...
public void onCreate(Bundle stateBundle) {
...
super.onCreate(stateBundle);
...
// The filter's action is BROADCAST_ACTION
IntentFilter mStatusIntentFilter = new IntentFilter(
Constants.BROADCAST_ACTION); // Adds a data filter for the HTTP scheme
mStatusIntentFilter.addDataScheme("http");
...
为了给系统注册这个BroadcastReceiver和IntentFilter,需要通过LocalBroadcastManager执行registerReceiver()的方法。
// Instantiates a new DownloadStateReceiver
DownloadStateReceiver mDownloadStateReceiver =
new DownloadStateReceiver();
// Registers the DownloadStateReceiver and its intent filters
LocalBroadcastManager.getInstance(this).registerReceiver(
mDownloadStateReceiver,
mStatusIntentFilter);
...
一个BroadcastReceiver可以处理多种类型的广播数据。每个广播数据都有自己的ACTION。这个功能使得不用定义多个不同的BroadcastReceiver来分别处理不同的ACTION数据。为BroadcastReceiver定义另外一个IntentFilter,只需要创建一个新的IntentFilter并重复执行registerReceiver()即可。
/*
* Instantiates a new action filter.
* No data filter is needed.
*/
statusIntentFilter = new IntentFilter(Constants.ACTION_ZOOM_IMAGE);
...
// Registers the receiver with the new filter
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mDownloadStateReceiver,
mIntentFilter);
发送一个广播Intent并不会启动或重启一个Activity。即使是你的app在后台运行,Activity的BroadcastReceiver也可以接收、处理Intent对象;但是这不会迫使你的app进入前台。当你的app不可见时,如果想通知用户一个发生在后台的事件,建议使用Notification。永远不要为了响应一个广播Intent而去启动Activity。
如何运行后台Service?的更多相关文章
- Android 8.0 启动后台service 出错 IllegalStateException: Not allowed to start service Intent
错误原因: Android 8.0 不再允许后台service直接通过startService方式去启动, 具体行为变更如下: 如果针对 Android 8.0 的应用尝试在不允许其创建后台服务的情况 ...
- Android中如何像 360 一样优雅的杀死后台Service而不启动
http://my.oschina.net/mopidick/blog/277813 目录[-] 一.已知的 kill 后台应用程序的方法 方法: kill -9 pid 二.终极方法,杀死后台ser ...
- Remote System Explorer Operation总是运行后台服务,卡死eclipse
阿里云 > 教程中心 > android教程 > Remote System Explorer Operation总是运行后台服务,卡死eclipse Remote System E ...
- Android 启动后台运行程序(Service)
Android开发中,当需要创建在后台运行的程序的时候,就要使用到Service.Service 可以分为有无限生命和有限生命两种.特别需要注意的是Service跟Activities是不同的(简单来 ...
- 判断后台service是否在运行
public static boolean isServiceRunning(Context mContext,String className) { boolean isRunning = fals ...
- Win10/UWP开发—使用Cortana语音与App后台Service交互
上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比 ...
- 安卓利用Handlers,AsyncTask和Loaders运行后台程序
安卓的用户界面线程(user interface thread) 1.1 主线程 安卓修改用户界面并从一个单一用户界面线程中处理输入事件,这个线程也被称作主线程(main thread) Androi ...
- ansible shell 之运行后台程序
最近在使用ansible shell模块启动一个shell编写的脚本,该脚本主要功能式加载java的classpath并在后台运行这个java程序. 该脚本在linux shell中可以正常启动和停止 ...
- 跟着拉大锯大神学Android——网络编程中运行后台服务器端口占用问题
拉大锯网页地址:https://www.sunofbeach.net/u/1153952789488054272 跟着拉大锯大神学Android,在学到网络编程时,使用了大神搭建的用于学习的后台服务器 ...
随机推荐
- NOIp2018提高组 双栈排序
这真是道神奇的题目: 原题链接 首先我们要证明以下的性质: 若原序列为\(\{a_n\}\),\(a_i\)和\(a_j\)不能同时放入一个栈中,当且仅当\(i<j,a_i<a_j\),且 ...
- python中os.path.isdir()函数的使用
在python 中,os.path.isdir(path)函数主要用来判断函数内部的path是否为一个目录 具体关于这个函数的解说参考博客https://blog.csdn.net/xjp_xujip ...
- Decision tree(决策树)算法初探
0. 算法概述 决策树(decision tree)是一种基本的分类与回归方法.决策树模型呈树形结构(二分类思想的算法模型往往都是树形结构) 0x1:决策树模型的不同角度理解 在分类问题中,表示基于特 ...
- 队列优化的dijkstra
#include<iostream> #include<queue> #include<cstdio> #include<cstring> #inclu ...
- javascript节点移除
var itemdel = document.getElementById("test"); itemdel.removeChild(lis[0]); 兼容性较好 itemdel. ...
- [再寄小读者之数学篇](2014-06-20 求极限-H\"older 不等式的应用)
设非负严格增加函数 $f$ 在区间 $[a,b]$ 上连续, 有积分中值定理, 对于每个 $p>0$ 存在唯一的 $x_p\in (a,b)$, 使 $$\bex f^p(x_p)=\cfrac ...
- Highcharts开发图表
1.折线图 显示一个静态的折线图,显示如下数据 星期 温度 周一 9~14 周二 4~10 周三 1~7 周四 4~9 周五 5~11 周六 8~13 周天 7~10 新建demo1.html < ...
- ado.net 使用:ExecuteReader 无法获取输出参数
解决方法: 要获取到输出参数.需要连接关闭之后才行. 一般都是用using把打开数据库连接的reader包起来
- Hello jna
记录下这几天用jna3.5.0调c++写的dll的经历 os:win7 用jna调dll首先需要一个dll文件并有可调的方法,然后根据方法的名称,参数,返回值编写一个interface c++需要包含 ...
- Linux常用命令总结-软件测试面试专用