android 后台运行服务之创建后台服务篇


除非另行指定 , 大部分应用程序操作在前台称作为UI 线程的特殊线程中运行 。 这可能会造成问题 , 因为 长时间运行的操作 会影响 你的用户界面的 响应 。 这 干扰 用户交互操作 , 甚至可能导致 系统错误 。 为了避免这种情况, Android框架 提供了 一些类, 帮助您 关闭负载 操作 放在一个独立运行于后台的 线程 。 最有用的 是 intentservice 。

接下来将描述如下三种操作。

1. 创建一个后台服务

这IntentServic类给单个后台线程运行某个操作提供了一个直接了断的结构, 允许它处理长时间运行的操作,不影响用户界面的响应,同时,一个IntentService 也不会被多用户界面生命周期事件的影响,因此它继续运行的情况下,将关闭AsyncTask。

一个IntentService 有一些限制:

  • 不能和用户直接交互,为将结果更新UI, 必须发送结果给Activity。
  • 工作请求是有序的,如果一个操作正在IntentService中运行,而且发送另一个请求给IntentService, 这个请求需要等待知道第一个请求操作完成.
  • 运行在IntentService中的操作,不能够被中断.

然而,在大多数情况下,Intentservice 是简单的后台操作的首选方法。

接下来将给您讲述

如何创建您自己的IntentService子类以及创建请求回调方法onHandleIntent(),最后描述如何在Manifest 文件中定义IntentService。

a。创建一个IntentService

为创建一个IntentService 组件,定义一个继承于IntentService的类, 并且在该类中实现onHandleIntent()方法。

例子如下:
/**
 * This service pulls RSS content from a web site URL contained in the incoming Intent (see
 * onHandleIntent()). As it runs, it broadcasts its status using LocalBroadcastManager; any
 * component that wants to see the status should implement a subclass of BroadcastReceiver and
 * register to receive broadcast Intents with category = CATEGORY_DEFAULT and action
 * Constants.BROADCAST_ACTION.
 *
 */
public class RSSPullService extends IntentService {
    // Used to write to the system log from this class.
    public static final String LOG_TAG = "RSSPullService";

    // Defines and instantiates an object for handling status updates.
    private BroadcastNotifier mBroadcaster = new BroadcastNotifier(this);

    /**
     * An IntentService must always have a constructor that calls the super constructor. The
     * string supplied to the super constructor is used to give a name to the IntentService's
     * background thread.
     */
    public RSSPullService() {

        super("RSSPullService");
    }

    /**
     * In an IntentService, onHandleIntent is run on a background thread.  As it
     * runs, it broadcasts its current status using the LocalBroadcastManager.
     * @param workIntent The Intent that starts the IntentService. This Intent contains the
     * URL of the web site from which the RSS parser gets data.
     */
    @Override
    protected void onHandleIntent(Intent workIntent) {
        // Gets a URL to read from the incoming Intent's "data" value
        String localUrlString = workIntent.getDataString();

        // Creates a projection to use in querying the modification date table in the provider.
        final String[] dateProjection = new String[]
        {
            DataProviderContract.ROW_ID,
            DataProviderContract.DATA_DATE_COLUMN
        };

        // A URL that's local to this method
        URL localURL;

        // A cursor that's local to this method.
        Cursor cursor = null;

        /*
         * A block that tries to connect to the Picasa featured picture URL passed as the "data"
         * value in the incoming Intent. The block throws exceptions (see the end of the block).
         */
        try {

            // Convert the incoming data string to a URL.
            localURL = new URL(localUrlString);

            /*
             * Tries to open a connection to the URL. If an IO error occurs, this throws an
             * IOException
             */
            URLConnection localURLConnection = localURL.openConnection();

            // If the connection is an HTTP connection, continue
            if ((localURLConnection instanceof HttpURLConnection)) {

                // Broadcasts an Intent indicating that processing has started.
                mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_STARTED);

                // Casts the connection to a HTTP connection
                HttpURLConnection localHttpURLConnection = (HttpURLConnection) localURLConnection;

                // Sets the user agent for this request.
                localHttpURLConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);

                /*
                 * Queries the content provider to see if this URL was read previously, and when.
                 * The content provider throws an exception if the URI is invalid.
                 */
                cursor = getContentResolver().query(
                        DataProviderContract.DATE_TABLE_CONTENTURI,
                        dateProjection,
                        null,
                        null,
                        null);

                // Flag to indicate that new metadata was retrieved
                boolean newMetadataRetrieved;

                /*
                 * Tests to see if the table contains a modification date for the URL
                 */
                if (null != cursor && cursor.moveToFirst()) {

                    // Find the URL's last modified date in the content provider
                    long storedModifiedDate =
                            cursor.getLong(cursor.getColumnIndex(
                                    DataProviderContract.DATA_DATE_COLUMN)
                            )
                    ;

                    /*
                     * If the modified date isn't 0, sets another request property to ensure that
                     * data is only downloaded if it has changed since the last recorded
                     * modification date. Formats the date according to the RFC1123 format.
                     */
                    if (0 != storedModifiedDate) {
                        localHttpURLConnection.setRequestProperty(
                                "If-Modified-Since",
                                org.apache.http.impl.cookie.DateUtils.formatDate(
                                        new Date(storedModifiedDate),
                                        org.apache.http.impl.cookie.DateUtils.PATTERN_RFC1123));
                    }

                    // Marks that new metadata does not need to be retrieved
                    newMetadataRetrieved = false;

                } else {

                    /*
                     * No modification date was found for the URL, so newmetadata has to be
                     * retrieved.
                     */
                    newMetadataRetrieved = true;

                }

                // Reports that the service is about to connect to the RSS feed
                mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_CONNECTING);

                // Gets a response code from the RSS server
                int responseCode = localHttpURLConnection.getResponseCode();

                switch (responseCode) {

                    // If the response is OK
                    case HttpStatus.SC_OK:

                        // Gets the last modified data for the URL
                        long lastModifiedDate = localHttpURLConnection.getLastModified();

                        // Reports that the service is parsing
                        mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_PARSING);

                        /*
                         * Instantiates a pull parser and uses it to parse XML from the RSS feed.
                         * The mBroadcaster argument send a broadcaster utility object to the
                         * parser.
                         */
                        RSSPullParser localPicasaPullParser = new RSSPullParser();

                        localPicasaPullParser.parseXml(
                            localURLConnection.getInputStream(),
                            mBroadcaster);

                        // Reports that the service is now writing data to the content provider.
                        mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_WRITING);

                        // Gets image data from the parser
                        Vector<ContentValues> imageValues = localPicasaPullParser.getImages();

                        // Stores the number of images
                        int imageVectorSize = imageValues.size();

                        // Creates one ContentValues for each image
                        ContentValues[] imageValuesArray = new ContentValues[imageVectorSize];

                        imageValuesArray = imageValues.toArray(imageValuesArray);

                        /*
                         * Stores the image data in the content provider. The content provider
                         * throws an exception if the URI is invalid.
                         */
                        getContentResolver().bulkInsert(
                                DataProviderContract.PICTUREURL_TABLE_CONTENTURI, imageValuesArray);

                        // Creates another ContentValues for storing date information
                        ContentValues dateValues = new ContentValues();

                        // Adds the URL's last modified date to the ContentValues
                        dateValues.put(DataProviderContract.DATA_DATE_COLUMN, lastModifiedDate);

                        if (newMetadataRetrieved) {

                            // No previous metadata existed, so insert the data
                            getContentResolver().insert(
                                DataProviderContract.DATE_TABLE_CONTENTURI,
                                dateValues
                            );

                        } else {

                            // Previous metadata existed, so update it.
                            getContentResolver().update(
                                    DataProviderContract.DATE_TABLE_CONTENTURI,
                                    dateValues,
                                    DataProviderContract.ROW_ID + "=" +
                                            cursor.getString(cursor.getColumnIndex(
                                                            DataProviderContract.ROW_ID)), null);
                        }
                        break;

                }

                // Reports that the feed retrieval is complete.
                mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_COMPLETE);
            }

        // Handles possible exceptions
        } catch (MalformedURLException localMalformedURLException) {

            localMalformedURLException.printStackTrace();

        } catch (IOException localIOException) {

            localIOException.printStackTrace();

        } catch (XmlPullParserException localXmlPullParserException) {

            localXmlPullParserException.printStackTrace();

        } finally {

            // If an exception occurred, close the cursor to prevent memory leaks.
            if (null != cursor) {
                cursor.close();
            }
        }
    }

}
注意: 这其他常规的Service组件的回调方法, 例如onStartCommand() 是自动被IntentServices调用,在一个IntentService中, 应当避免重载那些回调方法。

b.在Manifest 文件中定义IntentService

一个IntentService 也需要在应用manifest 文件中应该一个入口(entry),使用<service>元素提供这个入口service,<service>元素 是<application>元素的子项。具体定义如下:
   <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/>

android:name 指定IntentService 类的名称,注意这<service>元素不包含intent filter,这Activity发送工作请求给intentService使用明确的Intent,因此没有filter的必要,这也意味这仅仅在同一个应用或其他具有相同user ID 的应用才能访问该服务。发送工作请求给后台服务将在下一篇“android 后台运行服务之发送工作请求给后台服务篇”讲述。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值