1、服务是Android四大组件之一,在使用上可以分为本地服务和远程服务,本地服务是指在不影响用户操作的情况下在后台默默的执行一个耗时操作,例如下载,音频播放等。远程服务是指可以供其他应用程序调用的服务。
2、每个服务类都需要在AndroidMainfest.xml中使用<service>标签声明。
3、服务的启动方式分为两种Context.startService()和Context.bindService(), 服务的关闭可以通过外部调用Context.stopService()或者服务自身调用stopself()方法。
4、服务即不是一个单独的进程也不是一个单独的线程,它和应用程序运行在同进程的同线程中。为了能够不影响用户操作该应用程序,通常需要在服务中新建线程处理耗时操作。
服务有自己的声明周期,常用的回调方法有四个,分别是onCreate()、onStartCommand()、onBind()和onDestroy();
当外界首次调用startService()启动服务的时候,会首先调用onCreate(),然后调用onStartCommand(),如果此时再次调用startService(),则只执行onStartCommand()方法。当调用stopService()或者服务本身调stopself()方法是,服务会调用onDestroy(),停止下来。
我们也可以通过bindService()方法启动服务,调用此方法会首先调用onCreate(),然后调用onBind(),然后会调用实现的Binder中的所有方法。如果此时再次调用bindService()方法,服务不做任何操作。服务停止方法同上
startService()和bindService()方法可同时使用,但onCreate()方法仅会执行一次,当停止服务时,需要调用stopService()和unbindService()。而onDestroy()也是仅调用一次。
服务使用很简单,新建服务类继承Service(),并在相应的方法中实现相关操作即可,流程如下
1、新建服务类,继承自Service类
public Myservice extends Service { @override
public Ibinder onBind(Intent intent) { return null; } }
可以看到,Service唯一需要实现的方法就是onBind(),该方法在活动与服务进行通信的时候使用,我们暂时返回null即可
2、实现主要的方法onCreate(), onStartCommand(), onDestroy()
public Myservice extends Service { @override public Ibinder onBind(Intent intent) { return null; } @override public onCreate() { super.onCreate(); } @override public onStartCommand(Intent intent, int flags, int startId) { new Thread(new Runnable() { @Override public void run() { /*do something*/ } }).start(); return super.onStartCommand(intent, flags, startId); } @override public onDestroy() { super .onDestroy(); } }
onCreate()会在服务创建的时候调用,onStartCommand()会在服务启动的时候调用,onDestroy()会在服务销毁的时候调用,我们通常将耗时操作防盗onStartCommand()方法中,但是由于服务是和主线程处再同一个线程中,如果我们直接进行耗时操作,则会阻塞用户的前台操作,常用的方法如上,在onStartCommand()中新建一个线程,在线程中执行耗时操作。
另外,Android还提供了另外一种Service机制,对上述新建线程的操作做了封装,它就是IntentService,代码如下
public class MyIntentService extends IntentService { public MyIntentService() { super("MyIntentService"); } @Override
protected void onHandleIntent(Intent intent) { /*do something*/ } @Override public void onDestroy() { super .onDestroy(); } }
我们只需要将耗时操作放在onHandleIntent中即可,Android会自动建立新线程执行操作,需要注意的是需要实现无参的构造函数,在其中调用父类的构造方法。
3、在AndroidMainfest.xml中声明服务
<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=".MyService" /> <service android:name=".MyIntentService" /> </application>
4、到此为止,服务类已经建立完成,在活动中启动服务即可
// Intent intent = new Intent(this, MyIntentService.class); Intent intent = new Intent(this,MyService.class ); startService(intent); stopService(intent);
在活动不需要与服务进行通信的情况下,调用startService()方法启动Service,让Service在后台运行即可。但是大多数情况下,活动需要实时了解服务的状态,或者控制服务,就需要使用bindService()方法启动服务,使用Binder进行通信,其流程如下:
1、在服务中新建类继承自Binder,在新建的类中实现公共方法来设置或者获取服务的状态,代码如下
public class Myservice extends Service { ... class ServiceBinder extends Binder { public void setServiceStatus() { ... } public int getServiceStatus() { ... } ... } }
2、在服务中使用创建新建类的实例,在onBinder中返回
public class Myservice extends Service {
private ServiceBinder serviceBinder = new ServiceBinder();
@override
public IBinder onBind(Intent intent) {
return serviceBinder;
}
…
}
3、在活动中绑定服务,获取服务类中的Binder实例,与服务通信
public class MainActivity extends Activity { private MyService.ServiceBinder serviceBinder; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { ... } @Override public void onServiceConnected(ComponentName name, IBinder service) { serviceBinder = (MyService.serviceBinder)service; ... } }; ... }
当活动调用bindService()方法,与服务绑定成功后,会自动回调OnServiceConnected方法。当与服务解绑定后,会自动回调onServiceDisconnected;
可以看到在onServiceConnected方法中,我们获取了MyService中的Binder类实例ServiceBinder,这样的话我们就可以通过serviceBinder对服务进行设置或状态获取操作。
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/start_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Start Service" /> <Button android:id="@+id/stop_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Stop Service" /> <Button android:id="@+id/bind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Bind Service" /> <Button android:id="@+id/unbind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Unbind Service" /> <Button android:id="@+id/start_intent_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Start IntentService" /> </LinearLayout>
MainActivity.java
package com.example.servicetest; import android.app.Activity; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener { private Button startService; private Button stopService; private Button bindService; private Button unbindService; private Button intentService; private MyService.DownloadBinder downloadBiner; private ServiceConnection connection = new ServiceConnection() { public void onServiceDisconnected(android.content.ComponentName name) { … }; public void onServiceConnected(android.content.ComponentName name, android.os.IBinder service) { downloadBiner = (MyService.DownloadBinder)service; downloadBiner.startDownload(); downloadBiner.getProgress(); }; }; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startService = (Button)findViewById(R.id.start_service); stopService = (Button)findViewById(R.id.stop_service); bindService = (Button)findViewById(R.id.bind_service); unbindService = (Button)findViewById(R.id.unbind_service); intentService = (Button)findViewById(R.id.start_intent_service); startService.setOnClickListener(this); stopService.setOnClickListener(this); bindService.setOnClickListener(this); unbindService.setOnClickListener(this); intentService.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.start_service: Intent startIntent = new Intent(this, MyService.class); startService(startIntent); break; case R.id.stop_service: Intent stopIntent = new Intent(this, MyService.class); stopService(stopIntent); break; case R.id.bind_service: Intent bindIntent = new Intent(this, MyService.class); bindService(bindIntent, connection, BIND_AUTO_CREATE); break; case R.id.unbind_service: unbindService(connection); break;
case R.id.start_intent_service: Intent intentService = new Intent(this, MyIntentService.class); startService(intentService); break;
default: break; } } }
MyIntentService.java
package com.example.servicetest; import android.app.IntentService; import android.content.Intent; import android.util.Log; public class MyIntentService extends IntentService { public MyIntentService() { // TODO Auto-generated constructor stub super("MyIntentService"); } @Override protected void onHandleIntent(Intent intent) { // TODO Auto-generated method stub Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId()); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d("MyIntentService", "onDestroy executed"); } }
MyService.java
package com.example.servicetest; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MyService extends Service { private DownloadBinder mBinder = new DownloadBinder(); class DownloadBinder extends Binder { public void startDownload() { // TODO Auto-generated method stub Log.d("Myservice", "startDownlaod executed"); } public int getProgress() { Log.d("Myservice", "getProgress executed"); return 0; } } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub Log.d("Myservice", "onBind"); return mBinder; } @Override public void onCreate() { // TODO Auto-generated method stub Log.d("Myservice", "onCreate"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.d("Myservice", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { // TODO Auto-generated method stub Log.d("Myservice", "onDestroy"); super.onDestroy(); } }
效果图如下
可点击各个按钮,查看logcat,了解服务的声明周期,startService()和onBind()的混合调用,IntentService和Binder的使用方法。
远程服务尚未学习,待续…
本文参考《Android第一行代码》中的第九章