AIDL
来源:互联网 发布:股票资产分析软件 编辑:程序博客网 时间:2024/05/02 03:52
AIDL
AIDL:Android Interface Definition Language
AIDL是一种接口描述语言,常用于进程间通信(IPC,Inter-Process Communication),编译器会根据定义的aidl文件自动生成同名的java文件,通过预先定义的接口以及Binder机制进行进程间通信。客户端通过bindService与远程服务器建立连接,远程服务器返回一个IBinder对象,客户端通过asInterface方法获取这个IBinder对象,进而可以通过IBinder对象调用远程服务器的方法。
SsoAuth.aidl(远程调用端)
// SsoAuth.aidlpackage com.songzheng.cilent_server;// Declare any non-default types here with import statementsinterface SsoAuth { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); /** * 实现Sso授权 */ void ssoAuth(String userName, String pwd);}
创建一个AIDL文件并且声明远程要调用的方法后Build->Make Project后会自动生成一个同名的.java文件。服务端和客户端都必须要有相同的AIDL文件,并且AIDL文件包名必须是相同的。
服务端中完成AIDL文件的编码和.Java文件的生成之后,要写一个服务,当客户端绑定服务时服务的onBind方法返回一个IBinder对象,这样服务端就可以通过这个IBinder对象远程访问服务中的方法。注意返回的IBinder对象继承自AIDL文件生成的java文件的Stub静态抽象类。
v
SinaSsoAuthService.java(远程调用端)
package com.songzheng.cilent_server;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;import android.widget.Toast;/** * Created by make on 2016/11/20. */public class SinaSsoAuthService extends Service{ private SinaSsoImpl mBinder = new SinaSsoImpl(); @Override public void onCreate() { super.onCreate(); Log.e("SinaSsoAuthService", "Service onCreate!!!"); } @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } private class SinaSsoImpl extends SsoAuth.Stub{ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public void ssoAuth(String userName, String pwd) throws RemoteException { //Toast.makeText(getApplicationContext(), "执行Sso登录:用户名:" + userName + " 密码:" + pwd, Toast.LENGTH_SHORT).show(); Log.e("SinaSsoAuthServiec", "执行Sso登录:用户名:" + userName + " 密码:" + pwd); } }}
在ssoAuth方法中我试图使用Toast显示一段提示,但是报错:java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare(),原因是非主线程中默认没有创建Looper对象,需要调用Looper的prepare方法启动Looper。
这样远程调用端的逻辑就完成了,接下来是Client。
Client有和服务端相同的AIDL文件和.java文件,并且AIDL文件包名相同。在MainActivity中设置一个Button的点击监听事件,点击按钮绑定服务并且连接成功时在ServiceConnection中的onServiceConnected方法获取远程服务器端返回的IBinder对象,通过SsoAuth.Stub.asInterface方法将IBinder对象转换成SsoAuth对象,进而调用远程服务器端的方法。这里由于Android 5.0以上版本Google出于安全角度不允许隐式绑定Service,阅读源码后发现在validateServiceIntent中会判断Component和Package是否为null,只要有一个不为null就不会进而判断SDK版本了。
官方推荐解决方案:
Intent mIntent = new Intent();mIntent.setAction("XXX.XXX.XXX");//你定义的service的actionmIntent.setPackage(getPackageName());//这里你需要设置你应用的包名context.startService(mIntent);
我没试,而是直接在网上找了一段代码。
MainActivity.java:(客户端)
package com.songzheng.cilent;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.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import com.songzheng.cilent_server.SsoAuth;import java.util.List;public class MainActivity extends AppCompatActivity { private Button btSsoAuth; private SsoAuth mBinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btSsoAuth = (Button) findViewById(R.id.bt_ssoauth); btSsoAuth.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mBinder == null) { bindSsoAuthService(); } else { doSsoAuth(); } } }); } private void bindSsoAuthService() { final Intent intent = new Intent(); intent.setAction("com.songzheng.aidl.SinaSsoAuthService"); final Intent eIntent = new Intent(createExplicitFromImplicitIntent(this, intent)); bindService(eIntent, mConnection, BIND_AUTO_CREATE); Log.e("MainActivity", "bindSsoAuthService"); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.e("onServiceConnected", "onServiceConnected"); mBinder = SsoAuth.Stub.asInterface(iBinder); doSsoAuth(); } @Override public void onServiceDisconnected(ComponentName componentName) { mBinder = null; } }; private void doSsoAuth() { Log.e("doSsoAuth", "doSsoAuth"); try { Log.e("doSsoAuth", "mBinder.ssoAuth()"); Log.e("doSsoAuth", mBinder.toString()); mBinder.ssoAuth("TestCount", "TestPwd"); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } /*** * 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; }}
这样就完成了进程间通信。
- AIDL
- aidl
- AIDL
- AIDL
- AIDL
- AIDL
- AIDL
- aidl
- aidl
- AIDL
- AIDL
- aidl
- AIDL
- AIDL
- AIDL
- aidl
- aidl
- AIDL
- 读书和写代码一样
- leetcode 412. Fizz Buzz
- ES的连接方式:
- 快速排序
- PHP实现排序算法----基数排序(Radix Sort)
- AIDL
- 内存分析:
- 二叉排序树(新建,插入,查找,删除)(C语言编写)
- 解决pip install国外源太慢的问题
- [Android]安全第一步,使用IDA初步调试一个c/c++的exe文件
- 线性代数学习笔记4
- linux的用户安装目录
- 自己写简单的LinkedList
- pip网络超时解决办法