Android 四大组件 Service实现原理以及AIDL语言的使用详解

1、Service概念介绍以及生命周期解析

Service是Android系统提供的四大组件之一,它的地位与Activity是并列的,只不过没有Activity的使用频率高。顾名思义,Service就是运行在后台的一种服务程序,一般很少与用户交互,因此service没有可视化界面。

定义一个简单的service类比较简单,只需要继承Service类,实现其生命周期几个方法,然后在Manifest文件中添加service标签即可。

Service有自己的生命周期,我们可以使用startService()启动一个service或者使用bindService()来绑定一个存在的service,还可以通过RPC(远程进程调用)机制来实现不同进程中的service的调用。

Service的生命周期介绍 :

使用startService()启动 : onCreate() → onStart() ;

如果对已经启动的service继续调用startService的话,则只进行onStart() ;

使用stopService()关闭 : onDestroy() ;

使用bindService()启动绑定service时,只会调用onCreate() →onBind(),永远不会调用onStart() .

2、本地Service不和Activity进行交互情况

java code :

    public class ServiceA extends Service {  
      
        @Override  
        public void onCreate() {  
            super.onCreate();  
            Log.i("service", "onCreate...");  
        }  
          
        @Override  
        public void onStart(Intent intent, int startId) {  
            super.onStart(intent, startId);  
            //参数intent可以为activity向service传递相关信息   
            Log.i("service", "onStart..."+<span style="color:#CC33CC;">intent.getStringExtra("name")</span>);  
        }  
      
        @Override  
        public void onDestroy() {  
            super.onDestroy();  
            Log.i("service", "onDestroy...");  
        }  
      
          
            @Override  
        public IBinder onBind(Intent arg0) {  
            return null;//不需要和Activity进行交互时,可以直接返回null   
        }  
      
    }  
    public class MainActivity extends Activity {  
        private Button startBtn , stopBtn;  
        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.service_demo);  
            startBtn = (Button) findViewById(R.id.startBtn);  
            stopBtn = (Button) findViewById(R.id.stopBtn);  
            startBtn.setOnClickListener(listener);  
            stopBtn.setOnClickListener(listener);  
        }  
          
        private OnClickListener listener = new OnClickListener() {  
            @Override  
            public void onClick(View view) {  
                Intent service = new Intent();  
                service.setAction("<span style="color:#FF0000;">serviceA</span>");  
                //向service传递值   
                service.putExtra("name", "i am service");  
                switch (view.getId()) {  
                case R.id.startBtn:  
                    startService(service);  
                    break;  
                case R.id.stopBtn:  
                    stopService(service);  
                    break;  
                default:  
                    break;  
                }  
            }  
        };  
          
    }  

manifest:

    <service android:name="com.zj.service.ServiceA">  
                <intent-filter>  
                    <action android:name="serviceA"></action>  
                </intent-filter>  
            </service>  

3、本地Service与Activity进行交互情况

Java Code:

    /** 
        (1). 添加了一个public内部类继承Binder,并添加getService方法来返回当前的Service对象; 
        (2). 新建一个IBinder对象——new那个Binder内部类; 
        (3). onBind方法返还那个IBinder对象。 
     */  
    public class ServiceB extends Service {  
      
        private final IBinder mBinder = new MyBinder();  
          
        public class MyBinder extends Binder{  
            public ServiceB getService(){  
                Log.i("service", "ServiceB.this "+ServiceB.this);  
                return ServiceB.this;  
            }  
        }  
          
        @Override  
        public IBinder onBind(Intent arg0) {  
            Log.i("service", "onBind...");  
            return mBinder;  
        }  
      
        @Override  
        public void onCreate() {  
            super.onCreate();  
            Log.i("service", "onCreate...");  
        }  
      
        @Override  
        public void onDestroy() {  
            super.onDestroy();  
            Log.i("service", "onDestroy...");  
        }  
      
        @Override  
        public void onStart(Intent intent, int startId) {  
            super.onStart(intent, startId);  
            //使用bindService()绑定service时,永远不会调用onStart()方法   
            Log.i("service", "onStart...");  
        }  
              
            //测试service向activity传递信息   
            public String getData(){  
                  return "hello android !";  
            }  
     }  

    public class MainActivity extends Activity {  
        private Button  bindBtn , unbindBtn , dataBtn;  
        private ServiceB mService;  
        private boolean isRegist;//判断service是否已经成功注册   
        private String name;  
        private ServiceConnection conn = new ServiceConnection() {  
              
            //断开连接时调用   
            @Override  
            public void onServiceDisconnected(ComponentName arg0) {  
                Log.i("service", "onServiceDisconnected...");  
            }  
            //连接时调用   
            @Override  
            public void onServiceConnected(ComponentName arg0, IBinder binder) {  
                mService = ((MyBinder)binder).getService();  
                Log.i("service", "onServiceConnected..."+mService);  
            }  
        };  
          
          
        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.service_demo);  
            bindBtn = (Button) findViewById(R.id.bindBtn);  
            unbindBtn = (Button) findViewById(R.id.unbindBtn);  
            dataBtn = (Button)findViewById(R.id.getData);  
            bindBtn.setOnClickListener(listener);  
            unbindBtn.setOnClickListener(listener);  
            dataBtn.setOnClickListener(listener);  
        }  
          
        private OnClickListener listener = new OnClickListener() {  
            @Override  
            public void onClick(View view) {  
                Intent service = new Intent();  
                service.setAction("serviceB");  
                //向service传递值   
                service.putExtra("name", "i am service");  
                switch (view.getId()) {  
                case R.id.bindBtn:  
                    bindService(service, conn, Service.BIND_AUTO_CREATE);  
                    isRegist = true;  
                    break;  
                case R.id.unbindBtn:  
                    //如果没有先进行bindService就直接unbindService会抛出异常"Service not registered"   
                    if(isRegist){  
                        unbindService(conn);  
                        isRegist = false;  
                    }  
                    break;  
                case R.id.getData:  
                    //获取Service传递过来的值   
                    Toast.makeText(MainActivity.this, "service传递的值: "+mService.getData(), Toast.LENGTH_LONG).show();  
                    break;  
                default:  
                    break;  
                }  
            }  
        };  
          
    }  

Service : onCreate() → onBind() → Activity : onServiceConnected()  ; 可见onStart()是不会调用的!

4、远程Service与Activity的交互(AIDL的应用)

首先我们先上一个通俗的情景:在应用1中Activity绑定了一个Service,并且设置了一些值,此时我们想在应用2中调用该service并且想得到该值应该怎么做?我们都知道每个应用程序都运行在各自的进程中,并且android平台是不允许不同进程间进行直接的对象数据等传递的。如果必须进行跨进程之间的数据传递,那么我们就应该使用AIDL(Android Interface Definition Language)。

AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符;AIDL运行方法有任何类型的参数和返回值,在java的类型中,以下的类型使用时不需要导入包(import),基本数据类型、String、Map、List.当然为了避免出错,建议只要使用了,就导入包。

使用AIDL的步骤:

服务端(提供服务):

第1步:定义一个*.aidl文件,该文件里是符合aidl语言规范的接口定义,里面定义了外部应用可以访问的方法。当我们保存该文件的时候,eclipse会自动为我们在gen文件夹下生成一个相应的java接口文件。如:

    package com.zj.service;  
    interface IPerson{  
        void setName(String name);  
        String getName();  
    }    

第2步:实现AIDL文件生成的JAVA接口Stub

public class PersonImpl extends IPerson.Stub {  
  
    private String name;  
  
    @Override  
    public String getName() throws RemoteException {  
        return name;  
    }  
  
    @Override  
    public void setName(String name) throws RemoteException {  
        this.name = name;  
    }  
      
} 

第3步:定义一个自己的service,    并将其注册到androidManifest.xml文件中,例如:

    public class ServiceC extends Service {  
        private Stub iPerson = new PersonImpl();  
        @Override  
        public IBinder onBind(Intent arg0) {  
            Log.i("service", "onBind...");  
            return iPerson;  
        }  
    }   

    <service android:name="com.zj.service.ServiceC">  
        <intent-filter>  
            <action android:name="forServiceAidl"></action>  
        </intent-filter>  
    </service>  

注意这里一定要提供一个intent-filter,我们的客户端进程就是通过该action访问到服务端进程的哦。

我们都知道,在实现自己的service时,为了其他应用可以通过bindService来和我们的service进行交互,我们都要实现service中的onBind()方法,并且返回一个继承了Binder的内部类;在这里,eclipse自动为我们生成的RemoteServiceInterface.java中有一个实现了Binder的内部类,RemoteServiceInterface.Stub。AIDL要求我们,在这里不能再直接去实现Binder类了,而是去实现,AIDL提供给我们的Stub类。 实现stub类的同时,AIDL还要求我们同时实现我们在接口中定义的各种服务的具体实现。至此为止,我们的服务端已经和我们的aidl文件绑定到一起了哦。

同一个应用中的Activity为该Service中赋值:

    public class MainActivity extends Activity {  
          
        private IPerson iPerson;  
        private Button bindBtn,unbindBtn;  
          
        private ServiceConnection conn = new ServiceConnection() {  
              
            //断开连接时调用   
            @Override  
            public void onServiceDisconnected(ComponentName arg0) {  
            }  
            //连接时调用   
            @Override  
            public void onServiceConnected(ComponentName arg0, IBinder binder) {  
                iPerson = IPerson.Stub.asInterface(binder);  
                if(iPerson!=null){  
                    try {  
                        iPerson.setName("Service AIDL");  
                        Toast.makeText(MainActivity.this, "赋值成功!", Toast.LENGTH_LONG).show();  
                    } catch (RemoteException e) {  
                        e.printStackTrace();  
                        Toast.makeText(MainActivity.this, "赋值失败!", Toast.LENGTH_LONG).show();  
                    }  
                }  
            }  
        };  
          
          
        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.service_aidl);  
            bindBtn = (Button)findViewById(R.id.bindBtn);  
            unbindBtn = (Button)findViewById(R.id.unbindBtn);  
            bindBtn.setOnClickListener(listener);  
            unbindBtn.setOnClickListener(listener);  
        }  
          
        private OnClickListener listener = new OnClickListener() {  
            @Override  
            public void onClick(View view) {  
                switch (view.getId()) {  
                case R.id.bindBtn:  
                    //本应用中需要在manifest中配置RemoteService   
                    bindService(new Intent("forServiceAidl"), conn, Service.BIND_AUTO_CREATE);  
                    break;  
                case R.id.unbindBtn:  
                    unbindService(conn);  
                    break;  
                default:  
                    break;  
                }  
            }  
        };  
          
    }  

客户端:
       第1步:客户端要想使用该服务,肯定要先知道我们的服务在aidl文件中到底对外提供了什么服务,对吧?所以,第一步,我们要做的就是,将aidl文件拷贝一份到客户端的程序中(这里一定要注意,包路径要和服务端的保持一致哦,例如服务端为cn.com.chenzheng_java.remote.a.aidl,那么在客户端这边也应该是这个路径)。

      第2步:我们都知道,想要和service交互,我们要通过bindService方法,该方法中有一个ServiceConnection类型的参数。而我们的主要代码便是在该接口的实现中。

      第3步:在ServiceConnection实现类的onServiceConnected(ComponentName name, IBinder service)方法中通过类似remoteServiceInterface = RemoteServiceInterface.Stub.asInterface(service);方式就可以获得远程服务端提供的服务的实例,然后我们就可以通过remoteServiceInterface 对象调用接口中提供的方法进行交互了。(这里的关键是通过*.Stub.asInterface(service);方法获取一个aidl接口的实例哦)

       我们前面在服务端中说过了,必须提供一个intent-filter来匹配请求是否合法,所以我们在客户端访问服务的时候,还必须传递包含了匹配action的Intent哦。

客户端中使用服务端中的service范例:

    public class MainActivity extends Activity {  
      
        private IPerson person;  
        private Button btn;  
          
        private ServiceConnection conn = new ServiceConnection() {  
            @Override  
            public void onServiceDisconnected(ComponentName arg0) {  
            }  
            //因为有可能有多个应用同时进行RPC操作,所以同步该方法   
            @Override  
            public synchronized void onServiceConnected(ComponentName arg0, IBinder binder) {  
                //获得IPerson接口   
                person = IPerson.Stub.asInterface(binder);  
                if(person != null){  
                    try {  
                        //RPC方法调用   
                        String name = person.getName();  
                        Toast.makeText(MainActivity.this, "远程进程调用成功!值为 : "+name, Toast.LENGTH_LONG).show();  
                    } catch (RemoteException e) {  
                        e.printStackTrace();  
                        Toast.makeText(MainActivity.this, "远程进程调用失败! ", Toast.LENGTH_LONG).show();  
                    }  
                }  
            }  
        };  
          
        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.main);  
            btn = (Button)findViewById(R.id.btn);  
            btn.setOnClickListener(new OnClickListener() {  
                @Override  
                public void onClick(View arg0) {  
                    //该应用中不需要在manifest中配置RemoteService   
                    bindService(new Intent("forServiceAidl"), conn, Service.BIND_AUTO_CREATE);  
                }  
            });  
        }  
    }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值