Android Service总结(上)

Service是android中在后台运行,不提供用户界面的一个组件。

Service可以有2种形式:启动的(Started)Service和绑定的(Bound)Service。

启动的Service是由一个组件(比如Activity)调用startService创建的,在后台独立行的组件(即使启动它的组件被销毁)。它并不返回运行结果。

绑定的Service可以在运行期间和进程内的其他组件(仅限于Activity,Content Provider, Service)进行交互,绑定的Service相当于一个服务器,调用它的组件相当于客户端,在运行期间客户端可以向Service发送请求,绑定,获取结果,还可以实现进程间通信(IPC)

一.启动的(Started)Service

1.创建和管理Service

创建一个Servcie:

1)创建一个类继承Service

public class MyService extends Service{
    @Override
    public void onCreate() {
        Log.v("test","onCreate");
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v("test","onStartCommand");
        return START_NOT_STICKY;
    }


    @Override
    public void onDestroy() {
        Log.v("test","onDestroy");
    }


    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

2)在manifest文件中声明Servcie:

<manifest ... >
  ...
  <application ... >
      <service android:name="com.example.test.workspace1.app.MyService" />
      ...
  </application>
</manifest>

启动Service:

在Activity或者其他组件中,可以通过Intent启动指定的Service

Intent intent = new Intent(this, MyService.class);
startService(intent);
停止Servcie:

可以在Activity或者其他组件中调用 stopService(Intent)或者在onStartCommand中调用 stopSelf()

2.生命周期和回调方法

在调用startService()方法后,如果service没有创建,则执行onCreate方法,之后执行onStartCommand方法。否则直接执行onStartCommand方法。当调用stopService或者stopSelf后,调用onDestory回调,然后销毁Servcie。



3.返回值

onStartCommand方法返回一个int值,这个返回值告诉系统应该怎么处理被系统关闭的Service,返回值可以是以下3个:

START_NOT_STICKY:当系统在onStartCommand返回后关闭Service后,不重新创建Service。

START_STICKY:当系统在onStartCommand返回后关闭Service,重新创建Service并且调用onStartCommand,但不重新传递上一个intent而是用null代替,除非用pendingIntent启动Service。

START_REDELIVER_INTENT:当系统在onStartCommand返回后关闭Service,重新创建Service并且调用onStartCommand,重新传递最新的ntent,pendingIntent按照顺序传递。这个返回值适用于后台操作需要恢复上一次的进度的情况。


4.使用IntentService

Service是运行在主线程中的,如果Servcie中有阻塞的操作,超过10秒的话会造成ANR。为避免这种情况发生,可以在Service中启用新的线程。或者继承IntentService类。

IntentService完成的工作:

1.创建一个单独的线程来执行 onStartCommand中的任务。

2.创建一个工作队列,每次将一个intent 传到onHandleIntent的实现中

3.提供一个 onStartCommand的默认实现,将intent送往工作队列,并由onHandleIntent处理

4.当所有任务完成后,自己调用 stopSelf

参照IntentService的源码:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    public IntentService(String name) {
        super();
        mName = name;
    }

    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    protected abstract void onHandleIntent(Intent intent);
在onCreate的时候创建了子线程,并用它的Looper对象创建一个handler用来接收任务请求,在onStartCommand中调用onStart发出handler请求Message中封装了请求的intent。在ServiceHandler这个内部类的Handler中的handleMessage里,调用onHandleIntent做具体的耗时操作,任务结束后,调用stopSelf结束Service。

使用IntentService要简单的多,实现自己的IntentService只需要2步:

1.重写构造方法。

2.实现onHandleIntent方法,耗时的操作写在onHandleIntent中。

public class HelloIntentService extends IntentService {

    public HelloIntentService() {
        super("HelloIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

二.绑定的(Bound)Service

当实现一个可供绑定的Service时,需要在Service中提供Ibinder接口。有三种方式可以提供Ibinder接口,分别是继承Binder类,使用Messenger,使用AIDL。

(一).继承Binder类。

如果需要绑定的Service对应用是私有的,并且不存在跨进程的通信情况,那么应该使用这种方式。

实现方式:

1.在Service类中,创建继承Binder的类,这个类包含返回当前Service实例的方法,或者返回其他组件可以调用的公共方法。

2.在 onBind()回调中返回Binder类的实例。

3.在绑定Service的组件中,实例化ServiceConnection,并且在ServiceConnection的onServiceConnected回调中获得Binder的实例,用它调用Service中的公共方法。

例子:

Service:

public class MyService extends Service{

    private final IBinder mBinder = new LocalBinder();
    private final Random mGenerator = new Random();


    public class LocalBinder extends Binder {
        MyService getService() {
            return MyService.this;
        }
    }

    //onBind方法返回Binder的实现类
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    //供其他组件调用的公共方法
    public int getRandomNumber() {
        return mGenerator.nextInt(100);
    }


    @Override
    public void onCreate() {
        Log.v("test","onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v("test","onStartCommand");
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        Log.v("test","onDestroy");
    }
}
LocalBinder 类是Binder的实现类,里面提供了getService方法返回这个Service的实例,绑定此Service的组件可以在ServiceConnection的onServiceConnected中,通过这个方法获取Service的实例,以调用其他公共方法。

Activity:

public class MainActivity extends ActionBarActivity {

    private Button showNumber;
    private MyService mService;
    boolean mBound = false; //是否已经绑定了Service

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showNumber = (Button) findViewById(R.id.showNumber);
        showNumber.setOnClickListener(btnListener);
    }

    @Override
    protected void onStart() {
        super.onStart();
        //绑定Service
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    private ServiceConnection mConnection  = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            MyService.LocalBinder localBinder = (MyService.LocalBinder)iBinder;
            mService = localBinder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBound = false;
        }
    };

    private View.OnClickListener btnListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (mBound) {
                int num = mService.getRandomNumber();
                Toast.makeText(MainActivity.this, "number: " + num, Toast.LENGTH_SHORT).show();
            }
        }
    };
}
布局xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.test.workspace1.app.MainActivity">


    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true">


        <Button
            android:id="@+id/showNumber"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="显示随机数"
            android:layout_centerInParent="true"
            />

        </RelativeLayout>

</RelativeLayout>
这个Activity在onStart的时候绑定了Service,在绑定期间,通过Service的实例,不断调用其getRandomNumber方法以获得不同的随机数。

(二)使用Messenger

如果Service需要和其他进程交互(IPC),可以使用Messenger为Service提供接口。

使用Messenger的概要:

1.在Service内部实现Handler,接受客户端请求,这个Handler作为实例化Messenger的构造方法的参数

2.在Service的onBind()回调中通过创建的Messenger对象返回IBinder对象的实例。

3.客户端用Ibinder实例作为参数实例化 Messenger,Messenger用来向Service发送消息,Service在Handler内部的 handleMessage方法中处理请求。
例子:

应用A的Service:

public class MessengerService extends Service{

    //记录所有绑定的客户端数量
    private ArrayList<Messenger> mClients = new ArrayList<Messenger>();
    private int mValue = 0;

    private static final int MSG_REGISTER_CLIENT = 1;

    private static final int MSG_UNREGISTER_CLIENT = 2;

    private static final int MSG_SET_VALUE = 3;

    //这个handler接受客户端的请求
     class IncomingHandler extends Handler {

         //处理客户端的数据
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_REGISTER_CLIENT:
                     mClients.add(msg.replyTo);
                     break;
                 case MSG_UNREGISTER_CLIENT:
                     mClients.remove(msg.replyTo);
                     break;
                 case MSG_SET_VALUE:
                     mValue = msg.arg1;
                     for (int i = mClients.size()-1; i >= 0; i--) {
                         //向客户端发送客户端传来的最新数据
                         try {
                             mClients.get(i).send(Message.obtain(null, MSG_SET_VALUE, mValue, 0));
                         } catch (RemoteException e) {
                             mClients.remove(i);
                             e.printStackTrace();
                         }
                     }
                     break;
                 default:
                     super.handleMessage(msg);
             }
         }
     }

    //IncomingHandler作为Messenger的构造方法参数
    final Messenger mMessenger = new Messenger(new IncomingHandler());


    //onBind方法中通过创建的Messenger对象返回IBinder对象的实例
    @Override
    public IBinder onBind(Intent intent) {
        Log.v("test","onBind");
        return mMessenger.getBinder();
    }


    @Override
    public void onCreate() {
        Log.v("test","onCreate");
    }


    @Override
    public void onDestroy() {
        Log.v("test","onDestroy");
    }
}
在这个Service内部实现了IncomingHandler,接受客户端请求,这个Handler作为实例化Messenger(mMessenger)的构造方法的参数。在handler中,当收到MSG_SET_VALUE的消息后,将这个值发送给所有绑定它的客户端。
应用A的Manifest文件:

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".MessengerService" >
            <intent-filter>
                <action android:name="com.test.MessengerService" />
            </intent-filter>
        </service>
    </application>

应用B的Activity:

public class MainActivity extends ActionBarActivity {

    private Messenger mService = null;
    private boolean mBound = false;
    private TextView mCallbackText;

    private static final int MSG_REGISTER_CLIENT = 1;
    private static final int MSG_UNREGISTER_CLIENT = 2;
    private static final int MSG_SET_VALUE = 3;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button bindBtn = (Button) findViewById(R.id.bind);
        bindBtn.setOnClickListener(mBindListener);
        Button unbindBtn = (Button) findViewById(R.id.unbind);
        unbindBtn.setOnClickListener(mUnbindListener);
        mCallbackText = (TextView)findViewById(R.id.text);

    }

    private View.OnClickListener mBindListener = new View.OnClickListener() {
        public void onClick(View v) {
            doBindService();
        }
    };

    private View.OnClickListener mUnbindListener = new View.OnClickListener() {
        public void onClick(View v) {
            doUnbindService();
        }
    };

    private void doBindService() {
        Intent intent = new Intent("com.test.MessengerService");
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        mBound = true;
        mCallbackText.setText("绑定.");
    }

    private void doUnbindService() {
        if (mBound) {
            if (mService != null) {
                try {
                    //向Service发送解除绑定的消息
                    Message msg = Message.obtain(null, MSG_UNREGISTER_CLIENT);
                    msg.replyTo = mMessenger;
                    mService.send(msg);

                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            unbindService(mConnection);
            mBound = false;
            mCallbackText.setText("解除绑定.");

//            msg = Message.obtain(null, MSG_SET_VALUE, this.hashCode(), 0);
//            mService.send(msg);
        }
    }


    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mService = new Messenger(iBinder);
            Toast.makeText(MainActivity.this, "与Service建立连接", Toast.LENGTH_SHORT).show();
            try {
                Message msg = Message.obtain(null, MSG_REGISTER_CLIENT);
                msg.replyTo = mMessenger;
                mService.send(msg);

                //向Service发送一串字符
                msg = Message.obtain(null, MSG_SET_VALUE, this.hashCode(), 0);
                mService.send(msg);

            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mService = null;
            Toast.makeText(MainActivity.this, "与Service断开连接", Toast.LENGTH_SHORT).show();
        }
    };

    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SET_VALUE:
                    mCallbackText.setText("service传递的数字: " + msg.arg1);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    //与Service中初始化的方法一样
    final Messenger mMessenger = new Messenger(new IncomingHandler());
}
MainActivity在绑定Service后,在onServiceConnected回调中通过new Messenger(iBinder);得到Service的Messenger对象,通过这个Messenger对象发送消息,Service的handler可以接收到请求并处理,同时在MainActivity中有个全局变量mMessenger,它初始化的方法和Service中是一样的。在onServiceConnected中将它赋值给Message对象的replyTo属性,通过Service的Messenger对象发送给Service的handler,这样Service中可以通过Activity发送过去的Messenger对象,向Activity发送请求,由Activity中的handler处理。

以上的Service和Activity在2个不同的APP中,它们完成的交互是:Activity将一段hashCode发送给绑定的Service,Service记录所有绑定自己的客户端,并且一旦收到最新的hashCode,就将他们发送给所有绑定的客户端,所有绑定的客户端中的Activity收到返回的hashCode后显示在TextView上。这样就通过Messenger对象,完成了2个不同进程收发消息的交互。

运行效果:


相比Messenger,AIDL适用于让多个APP同时访问你的Service进行通信的情况,一般的应用用不到AIDL,下篇单独写。

绑定Service的生命周期:


当Service在客户端调用bindService时是不会回调onStartCommand方法的,而是调用onBind,调用unbindService后,onUnbind方法回调,接下来是onDestroy。

当一个Service绑定了多个客户端时,只有所有的客户端调用unbindService后,Service才会销毁。

Service有2个回调方法 onRebind和 onUnbind,当onUnbind返回true时,客户端调用bindService时,Service会执行onRebind方法而不是onBind。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值