如何运行后台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。

时间: 2024-12-28 11:27:49

如何运行后台Service?的相关文章

Android中如何像 360 一样优雅的杀死后台Service而不启动

http://my.oschina.net/mopidick/blog/277813 目录[-] 一.已知的 kill 后台应用程序的方法 方法: kill -9 pid 二.终极方法,杀死后台service而不自启动: am (Activity Manager)命令 一.已知的 kill 后台应用程序的方法 android.os.Process.killProcess(pid); activityManager.killBackgroundProcesses(pkgName); kill -9

Android高手之路之获取正在运行的service,以及判断某个service是否正在运行

注:本文改自http://blog.csdn.net/android_tutor/article/details/5824581 其实主要是用了activityManager的getRunningServices来获取正在运行的service的列表.然后用正在运行的服务的名称去比对相等. 看代码: package com.example.runningservice; import java.util.List; import android.app.Activity; import andro

Remote System Explorer Operation总是运行后台服务,卡死eclipse

阿里云 > 教程中心 > android教程 > Remote System Explorer Operation总是运行后台服务,卡死eclipse Remote System Explorer Operation总是运行后台服务,卡死eclipse 发布时间:2018-01-18 来源:网络 上传者:用户 关键字: operation 后台 Explorer 总是 运行 Eclipse System Remote 服务 发表文章 摘要:自己刚开始做Android项目,发现在使用可视化

Android 启动后台运行程序(Service)

Android开发中,当需要创建在后台运行的程序的时候,就要使用到Service.Service 可以分为有无限生命和有限生命两种.特别需要注意的是Service跟Activities是不同的(简单来说可以理解为后台与前台的区别),例如,如果需要使用Service的话,需要调用startService(),从而利用startService()去调用Service中的OnCreate()和onStart()方法来启动一个后台的Service.      启动一个Service的过程如下:conte

利用Vitamio,mediaplayer后台service播放m3u8流

Service 相关文件转载:http://www.cnblogs.com/lwbqqyumidi/p/4181185.html http://blog.csdn.net/richnaly/article/details/7829501 http://www.cnblogs.com/yejiurui/archive/2013/11/18/3429451.html http://blog.csdn.net/yuzhiboyi/article/details/7558176 (1)Service 一

Win10/UWP开发—使用Cortana语音与App后台Service交互

上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比调用前台的App,调用后台任务有个有点就是App不用被启动即可为用户提供服务. 要想使用Cortana调用App后台任务,首先我们需要定义VCD文件,我们依旧使用上篇中的代码,让它支持Cortana调用后台任务. 创建后台任务 新增一个[Windows运行时组件]项目,暂时起名叫做:XiaoMiBa

ansible shell 之运行后台程序

最近在使用ansible shell模块启动一个shell编写的脚本,该脚本主要功能式加载java的classpath并在后台运行这个java程序. 该脚本在linux shell中可以正常启动和停止,但是使用ansible shell模块却每次都启动后进程都消失了,日志没有任何异常,pid文件也生成了. 后来经过一个同事的猜想,是否有程序将该进程kill掉了. 于是产生了以下几种猜想: 1.ansible shell模块执行完shell脚本,就立即关闭当前的shell,进程也就被关闭了. an

Android 如何判断指定服务是否在运行中 &ldquo;Service&rdquo;

如何判断一个服务是否正在运行中: /** * 判断某个服务是否正在运行的方法 * * @param mContext * @param serviceName 是包名+服务的类名 * @return true代表正在运行,false代表服务没有正在运行 */ public static boolean isServiceWork(Context mContext, String serviceName) { boolean isWork = false; ActivityManager myAM

ASP.NET定时调用WebService 运行后台代码

效果: 通过在网站的Global.asax的Application_Start方法中 加入定时器 定时调用WebService 该WebService的一个方法 负责在后台 向数据库的某个表加入数据 步骤: 1.通过VS 新建一个网站 2.加入Global.asax 3.加入WebService 编辑 并 加入引用 4.对Global.as 效果:通过在网站的Global.asax的Application_Start方法中加入定时器 定时调用WebService该WebService的一个方法