[Android基础]Service

来源:互联网 发布:三星scx3400扫描软件 编辑:程序博客网 时间:2024/06/02 05:57

一、

Service主要有两种用途:

1.执行耗时操作。因为Service是工作在UI线程(即主线程)中的,所以当想在Service中执行耗时操作,应该新建一个线程。

2.用于组件之间的交互。通过将某些功能以Service组件的形式进行封装,然后提供给其他应用组件调用。


二、

Service的生命周期:

Service有两种调用的方式,根据调用方式的不同,有不同的生命周期。


1.启动模式(即startService())

如果Service用于执行长时间运行的操作,则一般采用启动模式。

如果当前指定的Service实例没有被创建,则调用Service的onCreate()来创建一个实例。

否则直接调用Service的onStartCommand()来运行Service。因此Service的onStartCommand()可能会重复调用多次。所以在onStartCommand()中要注意线程同步。



2.绑定模式(即bindService())

如果Service用于提供一种封装的功能供其他组件使用,则一般采用绑定模式。

如果当前指定的Service实例没有被创建,则调用Service的onCreate()来创建一个实例。

实例启动后,将调用onBind()。onBind将返回一个IBinder接口实例,IBinder允许客户端回调Service的方法。在绑定模式下,Android将调用者(如Activity)和Service绑定在一起,当调用者退出时,Service先后调用onUnbind()和onDestroy()退出。注意onBind只一次,不可多次绑定。



三、

启动模式下的Service:

重点就是onStartCommand()了:

@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubreturn super.onStartCommand(intent, flags, startId);}

它的返回值可以取:

START_NOT_STICKY

如果Service在它启动后(从onStartCommand()返回后)被kill掉,那么它将不会被重启。适用场景:网上下载数据。

START_REDELIVER_INTENT

如果Service在它启动后(从onStartCommand()返回后)被kill掉,那么它将会被重启(onCreate()方法会执行),onStartCommand()会执行。并且最后传给它的Intent通过onStartCommand()会被重新传给它。这种模式保证了传递给它的Intent一定会被处理完毕。适用场景:关键业务处理。

START_STICKY

如果Service在它启动后(从onStartCommand()返回后)被kill掉,那么它将会被重启(onCreate()方法会执行),onStartCommand()不会执行。但是Intent不被保留,此时Intent的值为null。适用场景:后台播放音乐。



同时注意的是onStartCommand()中的多请求下的线程同步。

在开发Service组件的过程中,经常要涉及线程及线程同步等复杂的问题。这是我们可以使用IntentService(继承Service)。

IntentService:异步处理服务,新开一个线程,当完成所有的任务以后自己关闭。

IntentService有以下特点:

1.创建一个工作队列,它每次将一个Intent传递到onHandleIntent(),解决了同步的问题。

2.当所有请求被处理完成后,将自动停止服务。

3.提供了一个返回null的onBind()方法的默认实现。

4.提供了onStartCommand()方法的默认实现,它将所有的Intent发送到一个工作队列,并进一步发送到onHandleIntent()方法。

继承IntentService的类至少要实现两个函数:构造函数和onHandleIntent()函数。要覆盖IntentService的其它函数时,注意要通过super调用父类的对应的函数。


下面用一个例子展示一下:

package com.example.test;import java.text.SimpleDateFormat;import android.app.IntentService;import android.content.Intent;import android.os.Bundle;import android.util.Log;/* * IntentService注意点: * 1.通过一个无参数的构造方法,并在方法中调用超类中以字符串为参数的构造方法 * 其中字符串被用来作为IntentService的工作线程的名称 * 2.可以覆盖onCreate(),onDestory()等方法,不过必须在方法的最后调用超类 * 的对应方法的实现,否则将抛出意外 */public class TestService extends IntentService {private int span;public TestService() {super("TestService");}@Overrideprotected void onHandleIntent(Intent intent) {Log.v("onHandleIntent", "服务启动时间" + getCurrentTime());Bundle bundle = intent.getBundleExtra("bundle");span = bundle.getInt("waitTime");long endTime = System.currentTimeMillis() + span * 1000;Log.v("onHandleIntent", "服务持续时间" + span);while (System.currentTimeMillis() <  endTime) {try {synchronized (this) {wait(endTime - System.currentTimeMillis());}} catch (InterruptedException e) {e.printStackTrace();}}}@Overridepublic void onDestroy() {Log.v("onHandleIntent", "服务摧毁时间" + getCurrentTime());super.onDestroy();}private String getCurrentTime() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String date = sdf.format(new java.util.Date());return date;}}

package com.example.test;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);((Button) findViewById(R.id.start)).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this,TestService.class);Bundle bundle = new Bundle();double a = Math.random() * 10;a = Math.ceil(a);int randomNum = new Double(a).intValue();bundle.putInt("waitTime", randomNum);intent.putExtra("bundle", bundle);//Toast.makeText(getApplicationContext(), randomNum + "", Toast.LENGTH_SHORT).show();startService(intent);}});((Button) findViewById(R.id.end)).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {stopService(new Intent(MainActivity.this,TestService.class));}});}}

快速点击四次start按钮:


四、

绑定模式下的Service:

1.本地绑定

要实现对Service组件功能的调用,Service组件要做以下改造:

a.将Service组件的功能封装到一个接口中

b.实现一个内部类,它继承Bind类(即实现IBinder接口),并实现上面的接口

c.在Service组件的onBind()中,返回b中的内部类对象,供其他组件使用


下面用一个例子展示一下:

package com.example.test2;public interface ICount {public abstract int getCount();}


package com.example.test2;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;public class CountService extends Service {private int count;private ServiceBinder serviceBinder = new ServiceBinder();@Overridepublic void onCreate() {super.onCreate();new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}count++;Log.v("CountService", "Count is" + count);}}}).start();}@Overridepublic IBinder onBind(Intent intent) {return serviceBinder;}public class ServiceBinder extends Binder implements ICount {@Overridepublic int getCount() {return count;}}}

package com.example.test2;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.Menu;import android.view.MenuItem;public class MainActivity extends Activity implements ServiceConnection {private ICount iCount;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bindService(new Intent("com.example.test2.CountService"), this, BIND_AUTO_CREATE);}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {iCount = (ICount) service;Log.v("MainActivity", iCount.getCount() + "");}@Overridepublic void onServiceDisconnected(ComponentName name) {iCount = null;}@Overrideprotected void onDestroy() {unbindService(this);super.onDestroy();}}

<service             android:name=".CountService">            <intent-filter >                <action android:name="com.example.test2.CountService"/>            </intent-filter>                  </service>



2.远程绑定

0 0
原创粉丝点击