Android四大组件之—— 使用服务进行后台操作
什么是服务
服务是一个没有可视化界面的组件,它可以在后台长期运行并进行各种操作。
服务的创建
我们只需要继承Service类并实现相应的方法即可创建服务
要想启动服务,还得在AndroidManifest中注册服务
服务类的示例代码
package com.whathecode.servicedemo; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.widget.Toast; public class ExtendsionService extends Service { /** * 当服务第一次被创建的时候调用此方法 */ @Override public void onCreate() { super.onCreate(); Toast.makeText(getBaseContext(), "服务被创建了", Toast.LENGTH_SHORT).show(); } /** * 当通过startService方法启动服务时此方法被调用 */ @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(getBaseContext(), "服务被启动了", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); } }
使用startService启动服务
主界面的逻辑代码:
package com.whathecode.servicedemo; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; public class MainActivity extends Activity { Intent service = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //创建服务 service = new Intent(this, ExtendsionService.class); } public void start(View view) { //启动服务 startService(service); } public void stop(View view) { //停止服务 stopService(service); } }
注册服务:
<service android:name="com.whathecode.servicedemo.BackgroundService"></service>
运行效果:
注意:
当我们第一次点击启动服务按钮的时候,onCreate方法和onStartCommand方法依次执行,
但在第二次点击启动服务按钮的时候,这个服务已经处于运行状态,onCreate方法不再执行第二次,
而onStartCommand方法总是在调用startService启动服务的时候执行。
onDestroy方法在stopService方法被调用后执行。
除了使用startService方法启动服务外,我们还可以使用Bind的方式启动服务。
前者和后者的不同在于:
服务的生命周期不依赖于启动者。服务被启动后一直在后台运行直到调用stopService被停止。
使用Bind方式启动服务,服务的生命周期依赖于启动者。即服务在启动者退出后自动销毁。
使用Bind方式启动服务
主要使用bindService方法启动服务,unbindService方法销毁服务。
使用此方式启动服务的好处是,bind定成功的时候服务返回一个IBinder对象,
我们可以通过在服务类里面实现这个对象,从而访问服务里面的具体方法。
从而达到和服务沟通的目的。
注意:
我们不能以直接实例化服务的方式调用里面的方法。
另外:
如果在退出服务的时候没有解绑,那么程序就会抛出异常IllegalArgumentException异常。
因此,每次调用bindService启动服务,完成后需要退出服务都需要使用unbindService 解绑。
示例代码:
package com.whathecode.servicedemo; 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.view.View; public class MainActivity extends Activity { Intent service = null; IReceptionist rpst; /** * bindService和unbindService方法使用的参数 */ private ServiceConnection conn = new ServiceConnection() { //此方法在服务连接被意外终止的时候被调用, @Override public void onServiceDisconnected(ComponentName name) { } //当服务被连接上的时候自动调用这个方法,第二个参数是服务类onBind方法中返回的对象 @Override public void onServiceConnected(ComponentName name, IBinder service) { rpst = (IReceptionist) service; rpst.callExtendsionNumber(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //创建服务 service = new Intent(this, ExtendsionService.class); } public void start(View view) { //启动服务 startService(service); } public void stop(View view) { //停止服务 stopService(service); } public void bind(View view) { //绑定服务 bindService(service, conn , BIND_AUTO_CREATE); } public void unBind(View view) { //解绑服务 unbindService(conn); } }
继承ServiceBinder对象,并实现自定义接口:
通过这个方式,我们可以暴露只需要的方法,实现代码的保护。
IReceptionist接口代码:
package com.whathecode.servicedemo; public interface IReceptionist { public void callExtendsionNumber(); }
ExtendsionService服务类代码:
package com.whathecode.servicedemo; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; import android.widget.Toast; public class ExtendsionService extends Service { private static final String TAG = "ExtendsionService"; /** * 当服务第一次被创建的时候调用此方法 */ @Override public void onCreate() { super.onCreate(); Toast.makeText(getBaseContext(), "服务被创建了", Toast.LENGTH_SHORT).show(); } /** * 当通过startService方法启动服务时此方法被调用 */ @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(getBaseContext(), "服务被启动了", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return new ServiceBinder(); } @Override public void onDestroy() { Toast.makeText(getBaseContext(), "服务被销毁了", Toast.LENGTH_SHORT).show(); Log.d(TAG, "服务被销毁了"); super.onDestroy(); } public void putExtendsion() { Toast.makeText(getBaseContext(), "正在帮你转接分机", Toast.LENGTH_SHORT).show(); } /** * * 继承Binder并实现IReceptionist接口 * 继承Binder类的目的是onBind方法中需要返回这个类型的对象 * * 实现IReceptionist接口是暴露方法的需要 */ private class ServiceBinder extends Binder implements IReceptionist { public void callExtendsionNumber() { putExtendsion(); } private void otherMethod() { } } }
运行效果:
注意看上图,我们在按下返回键的时候,Activity被销毁,由它启动的服务也跟着被销毁。
这样的服务貌似作用不大,有没有办法在退出Activity的时候不退出服务呢?
答案是有的:Android允许我们先启动一个服务,然后再调用bindService绑定到服务,
这样,我们既可以达到和服务沟通的目的,也可以使服务长期在后台运行。
看下图:
通过下面的图,就可以更清楚地理解上面代码的工作原理: