Android之在IntentService中执行后台程序

说明——

关于四大组件之一的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>

    

<service
        android:name=".RSSPullService"
        android:exported="false">
         
        service>
    ...
<application/>

注意标签并没有包含任何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" />

执行结束,效果图如下:

Android之在IntentService中执行后台程序_第1张图片

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

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:



    ...

 ".RSSPullService"
            android:exported="false">
            
                "com.example.android.threadsample.BROADCAST"/>
            
            
    

    "android.permission.INTERNET" />

你可能感兴趣的:(android)