• android菜鸟学习笔记28----Android中的Service生命周期及本地和远程服务绑定的实现


    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       @Override
    20 
    21       protected void onStop() {
    22 
    23            // TODO Auto-generated method stub
    24 
    25            super.onStop();
    26 
    27            Log.i("MainActivity","onStop()");
    28 
    29       }
    30 
    31       @Override
    32 
    33       protected void onDestroy() {
    34 
    35            // TODO Auto-generated method stub
    36 
    37            super.onDestroy();
    38 
    39            Log.i("MainActivity","onDestroy()");
    40 
    41       }
    42 
    43       @Override
    44 
    45       protected void onPause() {
    46 
    47            // TODO Auto-generated method stub
    48 
    49            super.onPause();
    50 
    51            Log.i("MainActivity","onPause()");
    52 
    53       }
    54 
    55       @Override
    56 
    57       protected void onResume() {
    58 
    59            // TODO Auto-generated method stub
    60 
    61            super.onResume();
    62 
    63            Log.i("MainActivity","onResume()");
    64 
    65       }
    66 
    67       @Override
    68 
    69       protected void onStart() {
    70 
    71            // TODO Auto-generated method stub
    72 
    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       @Override
    16 
    17       public void onCreate() {
    18 
    19            // TODO Auto-generated method stub
    20 
    21            super.onCreate();
    22 
    23            Log.i("MyService","onCreate()");
    24 
    25       }
    26 
    27       @Override
    28 
    29       public int onStartCommand(Intent intent, int flags, int startId) {
    30 
    31            // TODO Auto-generated method stub
    32 
    33            Log.i("MyService","onStartCommand()");
    34 
    35            return super.onStartCommand(intent, flags, startId);
    36 
    37       }
    38 
    39       @Override
    40 
    41       public void onDestroy() {
    42 
    43            // TODO Auto-generated method stub
    44 
    45            super.onDestroy();
    46 
    47            Log.i("MyService","onDestroy()");
    48 
    49       }
    50 
    51       @Override
    52 
    53       public boolean onUnbind(Intent intent) {
    54 
    55            // TODO Auto-generated method stub
    56 
    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 stub
    10 
    11                  serviceMethod();
    12 
    13            }
    14 
    15           
    16 
    17 }

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

    1 public IBinder onBind(Intent intent) {
    2 
    3            // TODO Auto-generated method stub
    4 
    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 stub
    4 
    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 stub
    10 
    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 stub
    12 
    13                  Log.i("MainActivity","服务绑定了");
    14 
    15                  imp = IMiddlePerson.Stub.asInterface(service);
    16 
    17 }

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

     

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

  • 相关阅读:
    关于数组的排序和拷贝!
    append和appendTo的区别!
    Layui的一点小理解(上)
    winfrom数据导出
    检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配
    文件监听
    C# winform 启动外部程序
    bat命令复制文件
    3.将模型添加到 ASP.NET Core MVC 应用
    2.将视图添加到 ASP.NET Core MVC 应用
  • 原文地址:https://www.cnblogs.com/dqrcsc/p/4652498.html
Copyright © 2020-2023  润新知