zoukankan      html  css  js  c++  java
  • Android studio 中创建AIDL Service

      1、概述

     AIDL在android系统中的作用

    AIDL,Android Interface definition language的缩写,它是一种android内部进程通信接口的描写叙述语言,通过它我们能够定义进程间的通信接口。近期看了下AIDL在Android系统中的使用方法,在网上看到非常多初学的朋友不太明确AIDL的实际作用,android提供了非常多进程间通信的组件,像action、broadcast、contentprovide都能够实现进程间的通信,为什么还要用AIDL这个东西呢?我在android源代码中实现了一个自己写的AIDL样例。用以简单解释下AIDL的作用。

    有开发过蓝牙或者WIFI应用的朋友肯定都知道,要去操作它必须先获得一个管理类,比方WIFI的管理类是WifiManager,通过getSystemService(Context.WIFI_SERVICE)就能够得到wifi的管理权限,这个提供了非常多的方法能够让用户去操作它,比方打开wifi能够调用setWifiEnabled(true)方法。

    那这个Manager究竟做了什么工作呢?是如何实现打开wifi的呢?事实上这个Manager仅仅是一个管理类,真正干活的另有其人,是一个叫WifiService的系统服务。

    在Android系统中有非常多的Manager。wifi的管理类叫WifiManager。蓝牙的管理类叫BluetoothManager,可是,仅仅要有xxxManager.java。就会有Ixxx.aidl,而且有xxxService.java。这个aidl类就是实现Manager和Service通信的桥梁。


    Binder驱动,Binderclient、服务端这三者之间的关系:

    binder通信的四个角色应该是client组件。server组件,serviceManagerbinder驱动。client组件和server组件进行通信,要通过ServiceManager查询server组件的引用。serverServiceManager注冊一个binder尸体,client通过ServiceManager获得binder实体的一个引用,这样clientserver就能够通信了

    2、Android studio 中AIDL的使用


    在eclipse里面操作时aidl文件个java文件都放在一个包下, client直接将该包拷贝到自己的文件夹下,然后能够另外建另外一个包放其它代码。

    但在android studio以下这样是不能够的,须要在src单独建一个AIDL文件夹,将aidl文件放在里面。java文件在另外的包下,这样就导致服务端项目与client项目的包名必须同样。在as中project相当于es的workspace,moudle相当于es的project,在eclipse里面是两个project在通信,so 我推測在as中是两个mould在通信。因此建了一个project(里面自带一个app module),让app moulde作为client然后又另外加了一个服务端moudle 叫aidlserver。

    在aidlserver的project视图以下的src以下右键new 选择AIDL ,AIDL Folder ,然后将自己的aidl文件放入当中。


    在Android Studio下创建AIDL Serivce。

            建立ADIL Service的步骤比建立普通Service要多一些,主要有:

            1、创建AIDL文件,在这里面定义远程接口。

            2、生成Java接口文件。

            3、建立一个Service的子类,而且记得在AndroidManifest.xml文件里配置。

           在client调用ADIL Servie:

            1、拷贝server端的AIDL文件,并生成Java接口文件。

            2、用BindService来调用Service,与调用普通Serivce相类似,仅仅是获取IBinder的方式有点不一样。


    以下是一个简单的样例

    一、建立服务端AIDL文件

            在项目名称上右键>NEW>AIDL>AIDL File,这样就创建了一个ADIL文件,命名为AIDLServerService.aidl

              

    package com.test.huangxingli.aidlserver;
    import com.test.huangxingli.aidlserver.Girl;
    // Declare any non-default types here with import statements
    
    interface AIDLServerService {
    
                String sayHello();
                Girl getGirl();
    }
    再创建Girl.aidl
    package com.test.huangxingli.aidlserver;
    parcelable Girl;

    建好这两个文件后再编写Girl.java .注意要先写Girl.aidl然后再写Girl.java 刚開始时 我先写的Girl.java 然后再写Girl.aidl时提示不能创建重名的文件。

    Girl.java例如以下:

    package com.test.huangxingli.aidlserver;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    /**
     * Created by huangxingli on 2015/3/27.
     */
    public class Girl  implements Parcelable{
    
        String name;
        int age;
    
        public Girl() {
    
        }
    
        public String getName() {
    
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(name);
            dest.writeInt(age);
    
        }
    
        public static final Creator<Girl> CREATOR=new Creator<Girl>() {
            @Override
            public Girl createFromParcel(Parcel source) {
                Girl girl=new Girl();
                girl.setName(source.readString());
                girl.setAge(source.readInt());
                return girl;
            }
    
            @Override
            public Girl[] newArray(int size) {
                return new Girl[size];
            }
        };
    }
    



    然后菜单中选择Build>Rebulid Project,这样就生成了java接口文件,地址在项目目录/app/build/generated/aidl里面

    如图

     

    接着写Service类MAIDLServerService,例如以下:

    package com.test.huangxingli.aidlserver;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    public class MAIDLServerService extends Service {
    
    
    
        public MAIDLServerService() {
        }
    
        AIDLServerService.Stub binder=new AIDLServerService.Stub() {
    
    
            @Override
            public String sayHello() throws RemoteException {
                return "hello, i am from AIDLServerService";
            }
    
            @Override
            public Girl getGirl() throws RemoteException {
                Girl girl=new Girl();
                girl.setAge(25);
                girl.setName("lily");
                return girl;
            }
        };
    
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
           return binder;
        }
    
    
    
    
    
    
    }
    
    然后在AndroidManifest.xml中里面将该服务器端的Service注冊一下:例如以下
    <?

    xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.huangxingli.aidlserver" > <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <service android:name="com.test.huangxingli.aidlserver.MAIDLServerService" android:process=":remote" > <intent-filter> <action android:name="com.test.huangxingli.aidlserver.MAIDLServerService"></action> </intent-filter> </service> </application> </manifest>


    server端结构如图


    二、建立clientAIDL文件

    首先要拷贝AIDL文件,这里要保证文件的内容一模一样,包含包的名称,比方本样例中服务器端AIDL文件所在包的名称是com.test.huangxingli.aidlserver,怎样做到这一点,先新建一个项目,然后在:项目目录/app/src/main目录下建立一个aidl目录。与java目录同级,在Android Studio中就能够看到这个文件夹。在这个文件夹上右键New>Package。建立一个com.test.huangxingli.aidlserver的包,再将aidl文件拷进去。这样才干保证生成的java接口文件全然一样。否则会提示找不到接口。參照下图操作



    核心部分:
    在网上非常多aidl程序client无法绑定Service,由于Android5.0以后,也就是说从Lollipop開始,service服务必须採用显示方式启动,否则会报错Service Intent must be explitict 怎样解决Android 5.0中出现的警告:Service Intent must be expli
    该链接中。第一种在加入setpackage这句代码后提示AIDL的service的绑定失败,另外一种方式攻克了改问题,我也是用另外一种方法解决

     结合我们的项目该怎么写了。例如以下:
      Intent mIntent = new Intent();
                    mIntent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService");
                    Intent eintent = new Intent(createExplicitFromImplicitIntent(MainActivity.this, mIntent));
                    bindService(eintent,connection,BIND_AUTO_CREATE);
    
                    MainActivity.this.startService(eintent);

    请注意,bindService 应在 startService之前

    以下是我的clientMainActivity.java的代码:
    package com.test.huangxingli.aidlserver;
    
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.content.pm.PackageManager;
    import android.content.pm.ResolveInfo;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.v7.app.ActionBarActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    import java.util.List;
    
    
    public class MainActivity extends ActionBarActivity {
    
        TextView textView;
        Button button;
        AIDLServerService aidlServerService;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            button= (Button) findViewById(R.id.button);
            textView= (TextView) findViewById(R.id.textView);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
    //                Intent intent=new Intent();
    //                intent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService");//你定义的service的action
    //                intent.setPackage(getPackageName());
    //
    //                bindService(intent,connection,BIND_AUTO_CREATE);
    
    
                    Intent mIntent = new Intent();
                    mIntent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService");
                    Intent eintent = new Intent(createExplicitFromImplicitIntent(MainActivity.this, mIntent));
                    bindService(eintent,connection,BIND_AUTO_CREATE);
    
                    MainActivity.this.startService(eintent);
    
                }
            });
    
        }
    
    
        /***
         * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent,
         * "java.lang.IllegalArgumentException: Service Intent must be explicit"
         *
         * If you are using an implicit intent, and know only 1 target would answer this intent,
         * This method will help you turn the implicit intent into the explicit form.
         *
         * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466
         * @param context
         * @param implicitIntent - The original implicit intent
         * @return Explicit Intent created from the implicit original intent
         */
        public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
            // Retrieve all services that can match the given intent
            PackageManager pm = context.getPackageManager();
            List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
    
            // Make sure only one match was found
            if (resolveInfo == null || resolveInfo.size() != 1) {
                return null;
            }
    
            // Get component info and create ComponentName
            ResolveInfo serviceInfo = resolveInfo.get(0);
            String packageName = serviceInfo.serviceInfo.packageName;
            String className = serviceInfo.serviceInfo.name;
            ComponentName component = new ComponentName(packageName, className);
    
            // Create a new intent. Use the old one for extras and such reuse
            Intent explicitIntent = new Intent(implicitIntent);
    
            // Set the component to be explicit
            explicitIntent.setComponent(component);
    
            return explicitIntent;
        }
    
        ServiceConnection connection=new ServiceConnection() {
    
            String content;
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                aidlServerService=AIDLServerService.Stub.asInterface(service);
                try {
                    content=aidlServerService.sayHello()+"
    ";
                    Girl girl=aidlServerService.getGirl();
                    content +="my name is "+girl.getName();
    
                    textView.setText(content);
    
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
    
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                aidlServerService=null;
            }
        };
    
    
    
    }
    

    好了,就到这里就能够执行程序了
    结果例如以下
    能够看到,点击BindService之后,服务端运行了onCreate和onBind的方法,而且client运行了onServiceConnected方法,调用原本在Server端才有的方法语句。标明server与client已经联通。

    资源下载

    代码先安装server端的代码。然后再安装client端的。。。




    參考文献:

    http://blog.csdn.net/huangxingli/article/details/44674751

    http://blog.csdn.net/lmj623565791/article/details/38461079

    http://blog.csdn.net/shenzhonglaoxu/article/details/42737195

    http://www.2cto.com/kf/201501/370478.html


  • 相关阅读:
    laydate 显示结束时间不小于开始时间
    [Draft]iOS.ObjC.Pattern.Builder-Pattern
    [Draft]iOS.Architecture.16.Truth-information-flow-and-clear-responsibilities-immutability
    iOS.ObjC.__attribute__.1-all-_attribute_-directives
    Security.ssl-pinning
    iOS.mach_msg_trap()
    iOS.redefinition-of-struct-x
    Swift.Operator-and-Items-in-Swift(1)
    iOS.Animation.Math-behind-CATransform3D
    Security.website-that-focus-on-mobile-app-security
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/7383902.html
Copyright © 2011-2022 走看看