你的位置:首页 > 操作系统

[操作系统]android菜鸟学习笔记28


Service是Android中长期在后台运行的没有界面的组件,使用服务的优势在于:能够提高进程的优先级,系统不容易回收掉进程,即便回收了,内存充足的时候,会把进程重新创建。

1.服务的简单使用示例:

1.1.定义一个服务:

定义一个服务的方式是定义一个类继承自Service:

 1 public class MyService extends Service { 2  3    @Override 4  5    public IBinder onBind(Intent intent) { 6  7      // TODO Auto-generated method stub 8  9      return null;10 11    }12 13 }

注意到onBind()方法是个抽象方法,因而必须重写。

1.2.注册服务:

四大组件之一的Service,在使用之前也必须在清单文件中注册。

<service android:name="cn.csc.service.MyService"></service>

 

1.3.在MainActivity中启动这个服务:

启动服务的方式很简单,可以如同启动Activity一样,通过Intent对象进行服务的启动,启动服务的方法是startService(Intent intent),下面的代码在MainActivity的onCreate()方法中启动服务:

 1 protected void onCreate(Bundle savedInstanceState) { 2  3     super.onCreate(savedInstanceState); 4  5     setContentView(R.layout.activity_main); 6  7     Intent intent = new Intent(this, MyService.class); 8  9     startService(intent);10 11 }

1.4.运行效果:

 

2.观察服务的生命周期:

2.1修改MyService及MainActivity代码,重写生命周期回调的各个方法,输出标识信息:

MainActivity.java:

 1 public class MainActivity extends ActionBarActivity { 2  3   @Override 4  5   protected void onCreate(Bundle savedInstanceState) { 6  7     super.onCreate(savedInstanceState); 8  9     setContentView(R.layout.activity_main);10 11     Log.i("MainActivity","onCreate()");12 13     Intent intent = new Intent(this, MyService.class);14 15     startService(intent);16 17   }18 19    @Override20 21    protected void onStop() {22 23      // TODO Auto-generated method stub24 25      super.onStop();26 27      Log.i("MainActivity","onStop()");28 29    }30 31    @Override32 33    protected void onDestroy() {34 35      // TODO Auto-generated method stub36 37      super.onDestroy();38 39      Log.i("MainActivity","onDestroy()");40 41    }42 43    @Override44 45    protected void onPause() {46 47      // TODO Auto-generated method stub48 49      super.onPause();50 51      Log.i("MainActivity","onPause()");52 53    }54 55    @Override56 57    protected void onResume() {58 59      // TODO Auto-generated method stub60 61      super.onResume();62 63      Log.i("MainActivity","onResume()");64 65    }66 67    @Override68 69    protected void onStart() {70 71      // TODO Auto-generated method stub72 73      super.onStart();74 75      Log.i("MainActivity","onStart()");76 77    }78 79 }

MyService.java:

 1 public class MyService extends Service { 2  3    @Override 4  5    public IBinder onBind(Intent intent) { 6  7      // TODO Auto-generated method stub 8  9      Log.i("MyService","onBind()");10 11      return null;12 13    }14 15    @Override16 17    public void onCreate() {18 19      // TODO Auto-generated method stub20 21      super.onCreate();22 23      Log.i("MyService","onCreate()");24 25    }26 27    @Override28 29    public int onStartCommand(Intent intent, int flags, int startId) {30 31      // TODO Auto-generated method stub32 33      Log.i("MyService","onStartCommand()");34 35      return super.onStartCommand(intent, flags, startId);36 37    }38 39    @Override40 41    public void onDestroy() {42 43      // TODO Auto-generated method stub44 45      super.onDestroy();46 47      Log.i("MyService","onDestroy()");48 49    }50 51    @Override52 53    public boolean onUnbind(Intent intent) {54 55      // TODO Auto-generated method stub56 57      Log.i("MyService","onUnbind()");58 59      return super.onUnbind(intent);60 61    }62 63 }

 

2.2部署安装应用:

运行结果:

 

2.3退出当前应用:

 

查看运行中的进程:

 

服务仍然在运行。

点击Stop之后:

 

服务才停止运行。

总结

采用startService()方式开启服务后,先后调用了服务的onCrate()和onStartCommand()方法,Activity被销毁之后,服务仍然继续运行,只有当手动停止掉服务时,才会调用onDestory()方法。

可见,start方式开启服务时, 一旦服务开启跟调用者(开启者)就没有任何关系了。

开启者退出后,服务仍然在后台长期的运行,开启者与服务没有任何关联,因而不能调用服务里面的方法。

2.4在MainActivity中调用bindService()绑定服务:

 1 protected void onCreate(Bundle savedInstanceState) { 2  3     super.onCreate(savedInstanceState); 4  5     setContentView(R.layout.activity_main); 6  7     Log.i("MainActivity","onCreate()"); 8  9     Intent intent = new Intent(this, MyService.class);10 11     bindService(intent, new MyConn(), BIND_AUTO_CREATE);12 13 }

查看运行结果:

 

退出应用:

 

总结

采用绑定的方式开启服务,会先后调用:onCreate()、onBind(),Activity销毁后,Service紧跟着调用onunbind()、onDestory()也被销毁。

这种方式的服务跟随应用的结束而结束,不会长期驻留在后台,但是,这种方式下,Activity与Service产生了关联,因而可以调用Service提供的方法。那么在Activity中如何调用Service中的方法呢?

3.Activity调用本地服务方法:

主要步骤

1)在本地服务中添加需要被Activity调用的方法

2)定义一个接口,约定Activity通过该接口的实例调用本地服务的方法,该接口的实例由本地服务的onBind()方法传递给Activity

3) 在服务的内部创建一个内部类实现约定的接口,并在onBind()方法中返回该内部类的实例,由于onBind()方法返回的是IBinder类型的实例,所以该内部类还需要继承一个Ibinder接口的实现类,一般继承Binder类

4)在activity 绑定服务:bindService();

5)在服务成功绑定的时候 会执行一个方法 onServiceConnected 传递过来一个 IBinder对象

5)将传回的IBinder对象强制类型转化成约定接口的实例,从而调用接口里面的方法。

 

具体编码步骤:

1)修改MyService代码,添加一个供Activity调用的方法:

1 public void serviceMethod(){2 3      Toast.makeText(getApplicationContext(), "本地服务方法被调用", Toast.LENGTH_SHORT).show();4 5 }

2)定义一个双方约定的接口,用于调用前面添加的serviceMethod()方法:

1 public interface IMiddlePerson {2 3    public void callServiceMethod();4 5 }

3)在MyService中定义一个内部类继承自Binder并实现上面的约定接口:

 1 private class MiddlePerson extends Binder implements IMiddlePerson{ 2  3  4  5       @Override 6  7      public void callServiceMethod() { 8  9         // TODO Auto-generated method stub10 11          serviceMethod();12 13       }14 15      16 17 }

4)修改MyService的onBind()方法,返回上面定义的内部类的实例:

1 public IBinder onBind(Intent intent) {2 3      // TODO Auto-generated method stub4 5      Log.i("MyService","onBind()");6 7      return new MiddlePerson();8 9 }

5)在MainActivity中添加一个存放约定接口的引用的字段:

private IMiddlePerson imp;

 

6)修改MainActivity的布局文件,添加一个按钮:

 1 <Button 2  3     android:layout_width="wrap_content" 4  5     android:layout_height="wrap_content" 6  7     android:onClick="call" 8  9     android:layout_gravity="center_horizontal"10 11     android:text="@string/call_native_service" />

在MainActivity中添加public void call(View view)方法,用于按钮的点击回调:

1 public void call(View view){2 3      imp.callServiceMethod();4 5 }

7)修改MyConn的onServiceConnected方法,将IBinder类型的参数赋值给imp:

1 public void onServiceConnected(ComponentName name, IBinder service) {2 3         // TODO Auto-generated method stub4 5         Log.i("MainActivity","服务绑定了");6 7         imp = (IMiddlePerson) service;8 9 }

8)查看运行结果:

 

注: 如果又想服务能长期在后台运行,又想能够调用服务中的方法,则应如下顺序处理:

1)start方式开启服务(保证服务长期后台运行)

2)bind方式绑定服务(保证调用服务的方法)

在需要停止服务时,则需要按如下顺序:

3)unbind解除绑定服务

4)stopService停止服务。

这里,就不在测试了。

4.Activity调用远程服务的方法:

这里简单区分下本地服务和远程服务:

远程服务:调用者和服务在不同的工程代码里面。

本地服务:调用者和服务在同一个工程代码里面。

如果像调用同一个工程中的本地服务方法一样,绑定一个远程服务,直接会报错。这是因为绑定远程服务的方法与绑定本地服务的方法有所不同:

Android定义了aidl:android interface definition language  安卓接口定义语言来实现远程服务的绑定。

与绑定本地服务的主要不同在于:

约定的接口的定义不能带有任何访问修饰符,而且后缀名要改为.aidl,之后会自动生成一个名为Stub的内部类,服务中定义的内部类继承该内部类即可。

具体编码步骤:

4.1定义能远程绑定的服务:

1)定义IMiddlePeson.aidl:

1 package cn.csc.service;2 3 4 5 interface IMiddlePerson {6 7   void callServiceMethod();8 9 }

将在gen目录下自动生成:

 

打开自动生成的IMiddlePerson.java:

 

可以看到自动生成了Stub内部抽象类

2)在服务中添加要被远程调用的方法:

1 public void serviceMethod(){2 3      Log.i("MyService","远程服务方法被调用了。。。");4 5 }

3)在服务中定义内部类继承IMiddlePerson.Stub:

 1 private class MiddlePerson extends IMiddlePerson.Stub{ 2  3  4  5       @Override 6  7      public void callServiceMethod() { 8  9         // TODO Auto-generated method stub10 11          serviceMethod();12 13       }14 15      16 17 }

 

4)由于要被远程调用,所以不能使用显示意图了,需要在清单文件中注册服务时添加<intent-filter>生命能响应的动作:

1 <service android:name="cn.csc.service.MyService">2 3       <intent-filter >4 5         <action android:name="cn.csc.service.MyService"/>6 7       </intent-filter>8 9 </service>

至此,一个可以被远程绑定的服务就完成了,先把它部署到模拟器上。

4.2在另一个项目中绑定该远程服务:

1)将约定的接口IMiddlePerson.aidl文件连同所在包一同复制到该项目的src目录中:

 

可以看到,同样自动生成了IMiddlePerson.java文件

2)定义存放接口引用的字段:

private IMiddlePerson imp;

 

3)使用隐式意图绑定远程服务:

 1 Intent intent = new Intent(); 2  3 intent.setAction("cn.csc.service.MyService"); 4  5 bindService(intent, new MyConn(), BIND_AUTO_CREATE); 6  7 4)修改MyConn()中的onServiceConnected()方法: 8  9 public void onServiceConnected(ComponentName name, IBinder service) {10 11         // TODO Auto-generated method stub12 13         Log.i("MainActivity","服务绑定了");14 15         imp = IMiddlePerson.Stub.asInterface(service);16 17 }

 

调用远程服务的应用端也搞定了,然后部署,查看运行结果:

 

以上,就是今天学到的关于Service的一点知识。