Android之在IntentService中执行后台程序

来源:互联网 发布:可靠性软件招标2016 编辑:程序博客网 时间:2024/06/05 09:45

说明——

关于四大组件之一的Service,对它的基本用法不熟悉的可以去看看这个博客!

Service完全解析

除非我们特别为某个操作指定特定的线程,否则大部分在前台UI界面上的操作任务都执行在一个叫做UI Thread的特殊线程中。这可能存在某些隐患,因为部分在UI界面上的耗时操作可能会影响界面的响应性能。UI界面的性能问题会容易惹恼用户,甚至可能导致系统ANR错误。为了避免这样的问题,Android Framework提供了几个类,用来帮助你把那些耗时操作移动到后台线程中执行。那些类中最常用的就是IntentService.

创建IntentService

IntentService为在单一后台线程中执行任务提供了一种直接的实现方式。它可以处理一个耗时的任务并确保不影响到UI的响应性。另外IntentService的执行还不受UI生命周期的影响,以此来确保AsyncTask能够顺利运行。

但是IntentService有下面几个局限性:

  • 不可以直接和UI做交互。为了把他执行的结果体现在UI上,需要把结果返回给Activity。

  • 工作任务队列是顺序执行的,如果一个任务正在IntentService中执行,此时你再发送一个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕才开始执行。

  • 正在执行的任务无法打断。

    虽然有上面那些限制,然而在在大多数情况下,IntentService都是执行简单后台任务操作的理想选择。

Step 1: 为你的app创建一个IntentService组件,需要自定义一个新的类,它继承自IntentService,并重写onHandleIntent()方法,如下所示:

public class RSSPullService extends IntentService {    @Override    protected void onHandleIntent(Intent workIntent) {        // 这里可以得到传进来的intent,就可以获得intent所携带的数据        String dataString = workIntent.getDataString();        ...        // 对获得的数据进行操作,比如一些耗时的网络操作        ...    }}

注意:一个普通Service组件的其他回调,例如onCreate()、onStartCommand()会被IntentService自动调用。在IntentService中,要避免重写那些回调。

Step 2:在Manifest文件中定义IntentService

IntentService需要在manifest文件添加相应的条目如下所示:

<application    android:icon="@drawable/icon"    android:label="@string/app_name">    ...     <activity android:name=".MainActivity">     </activity>    <!--        android:exported 被设置为"false",        保证服务只会在这个App内部运行    --><service        android:name=".RSSPullService"        android:exported="false">         <!--         可以为服务添加相应的响应方式和过滤         <intent-filter >                <action android:name="com.example.android.threadsample.BROADCAST"/>            </intent-filter>    -->        </service>    ...<application/>

注意<service>标签并没有包含任何intent filter。因为发送任务给IntentService的Activity需要使用显式Intent,所以不需要filter。这也意味着只有在同一个app或者其他使用同一个UserID的组件才能够访问到这个Service。

至此,你已经有了一个基本的IntentService类,你可以通过构造Intent对象向它发送操作请求。

创建任务请求并发送到IntentService

为了创建一个任务请求并发送到IntentService。需要先创建一个显式Intent,并将请求数据添加到intent中,然后通过调用 startService() 方法把任务请求数据发送到IntentService。

下面是代码的示例:

  • 创建一个新的显式Intent用来启动IntentService。
/* * 创建一个Intent来启动RSSPullService,把一个链接存放进intent中 */Intent mServiceIntent = new Intent(getActivity(), RSSPullService.class);mServiceIntent.setData(Uri.parse(dataUrl));
  • 执行startService()开启服务
getActivity.startService(mServiceIntent);

注意
可以在Activity或者Fragment的任何位置发送任务请求。例如,如果你先获取用户输入,您可以从响应按钮单击或类似手势的回调方法里面发送任务请求。

一旦执行了startService(),IntentService在自己本身的onHandleIntent()方法里面开始执行这个任务,任务结束之后,不需要使用stopService()方法来停止这个服务,因为IntentService会自动停止这个Service

下一步是如何把工作任务的执行结果返回给发送任务的Activity或者Fragment。

利用IntentService将执行任务的结果返回给Activity或者Fragment

下面用一个实例来说明IntentService的一般工作步骤:

  • (1)在Activity中通过startService启动service,并传递参数。

  • (2)Service中接收参数,做耗时的处理,处理完毕,发送Broadcat,并把处理结果传递出来

  • (3)Activity中注册BroadcastReceiver,监听广播,更新UI。

    Step 1:创建一个IntentService,接收参数

RSSPullService.java

public class RSSPullService extends IntentService {// public static final String BROADCAST_ACTION =            "com.example.android.threadsample.BROADCAST";//构造方法必须重写 public RSSPullService() {          super("RSSPullService");      }      @Override      protected void onHandleIntent(Intent workIntent) {        //接收参数,做耗时的处理,处理完毕,发送Broadcat          //将数据打印出来       Log.i(TAG,dataString);        //接收到数据,做耗时处理        String result = downloadHtml(dataString);        Log.i("result",result);    }      ...}

Step 2:在MainActivity中通过startService启动IntentService,并传递参数

MainActivity.java

public class MainActivity extends AppCompatActivity {    MyReceiver receiver = new MyReceiver();    TextView mTextView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    regist();        bindView();    } private void bindView() {        mTextView = (TextView)this.findViewById(R.id.textView);        Button button = (Button)this.findViewById(R.id.button);        button.setOnClickListener(new View.OnClickListener() {            @Override        //创建一个显示Intent                  Intent serviceIntent = new Intent(MainActivity.this,RSSPullService.class);                //将百度网址传入Intent                serviceIntent.setData(Uri.parse("http://www.baidu.com"));                //启动服务                startService(serviceIntent);            }        });    }    ...}

Step 3:在MainActivity中注册广播,这里我们利用LocalBroadcastManager来注册广播,监听广播,

MainActivity.java

private void regist() {            IntentFilter intentFilter = new IntentFilter(RSSPullService.BROADCAST_ACTION);        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);        LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter);    }//取消注册 protected void onDestroy() {        super.onDestroy();        LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);    }

Step 4:在service中处理耗时操作,并发送Broadcat,并把处理结果传递出来

RssPullService.java

public class RSSPullService extends IntentService { private static final String TAG = "RSSPullService";    public static final String EXTENDED_DATA_STATUS =            "com.example.android.threadsample.STATUS";    private LocalBroadcastManager mLocalBroadcastManager;... protected void onHandleIntent(Intent intent) {           ...    //将耗时操作的结果放进Intent,调用LocalBroadcastManager.sendBroadcast将intent传递回去    Intent localIntent = new Intent(BROADCAST_ACTION);        localIntent.putExtra(EXTENDED_DATA_STATUS,result);        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);        mLocalBroadcastManager.sendBroadcast(localIntent);    }     ...     //处理耗时任务的方法 private String downloadHtml(String dataString) {        try {            URL url = new URL(dataString);            HttpURLConnection conn = (HttpURLConnection) url.openConnection();            InputStream in = conn.getInputStream();            ByteArrayOutputStream out = new ByteArrayOutputStream();            byte[] buff = new byte[1024];            int len = 0;            while ((len = in.read(buff)) != -1) {                out.write(buff, 0, len);            }            in.close();            Log.i("html",out.toByteArray().toString());            return new String(out.toByteArray());        } catch (Exception e) {            e.printStackTrace();            return "";        }    }}

Step 5:在Activity中创建广播,接收广播,更新UI

MainActivity.java

 private class MyReceiver extends BroadcastReceiver{        @Override        public void onReceive(Context context, Intent intent) {            String data = intent.getStringExtra(RSSPullService.EXTENDED_DATA_STATUS);            Log.i("test", data);            mTextView.setText(data);        }    }

最后别忘了加上网络权限:

 <uses-permission android:name="android.permission.INTERNET" />

执行结束,效果图如下:

这里写图片描述

我把主要的几个类的代码放上来:

MainActivity.java :

public class MainActivity extends AppCompatActivity {    MyReceiver receiver = new MyReceiver();    TextView mTextView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        regist();        bindView();    }    private void regist() {            IntentFilter intentFilter = new IntentFilter(RSSPullService.BROADCAST_ACTION);        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);        LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter);    }    private void bindView() {        mTextView = (TextView)this.findViewById(R.id.textView);        Button button = (Button)this.findViewById(R.id.button);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent serviceIntent = new Intent(MainActivity.this,RSSPullService.class);                serviceIntent.setData(Uri.parse("http://www.baidu.com"));                startService(serviceIntent);            }        });    }    private class MyReceiver extends BroadcastReceiver{        @Override        public void onReceive(Context context, Intent intent) {            String data = intent.getStringExtra(RSSPullService.EXTENDED_DATA_STATUS);            Log.i("test", data);            mTextView.setText(data);        }    }    protected void onDestroy() {        super.onDestroy();        LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);    }}

RssPullService.java :

public class RSSPullService extends IntentService {    public static final String BROADCAST_ACTION =            "com.example.android.threadsample.BROADCAST";    private static final String TAG = "RSSPullService";    public static final String EXTENDED_DATA_STATUS =            "com.example.android.threadsample.STATUS";    private LocalBroadcastManager mLocalBroadcastManager;    private ResponseReceiver receiver;    public RSSPullService() {        super("RSSPullService");    }    @Override    protected void onHandleIntent(Intent intent) {       String dataString = intent.getDataString();       Log.i(TAG,dataString);        String result = downloadHtml(dataString);        Log.i("result",result);        Intent localIntent = new Intent(BROADCAST_ACTION);        localIntent.putExtra(EXTENDED_DATA_STATUS,result);        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);        mLocalBroadcastManager.sendBroadcast(localIntent);    }    private String downloadHtml(String dataString) {        try {            URL url = new URL(dataString);            HttpURLConnection conn = (HttpURLConnection) url.openConnection();            InputStream in = conn.getInputStream();            ByteArrayOutputStream out = new ByteArrayOutputStream();            byte[] buff = new byte[1024];            int len = 0;            while ((len = in.read(buff)) != -1) {                out.write(buff, 0, len);            }            in.close();            Log.i("html",out.toByteArray().toString());            return new String(out.toByteArray());        } catch (Exception e) {            e.printStackTrace();            return "";        }    }}

AndroidManifest.xml:

<application>    ... <service            android:name=".RSSPullService"            android:exported="false">            <intent-filter >                <action android:name="com.example.android.threadsample.BROADCAST"/>            </intent-filter>            </service>    </application>    <uses-permission android:name="android.permission.INTERNET" />
0 0
原创粉丝点击