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 后台运行服务之发送工作请求给后台服务篇”讲述。

你可能感兴趣的:(android 后台运行服务之创建后台服务篇)