本片文章要实现Binder通信:模拟QQ三方登录功能。
客户端界面BinderDemo:
QQ登录页面:
登录成功则回到客户端页面,并带回登录用户信息,如下图:
先贴出服务端程序代码,即BinderQQ,目录结构如下:
AIDL文件:
// ILoginInterface.aidl
package com.source.binderqq;
// Declare any non-default types here with import statements
interface ILoginInterface {
//登陆
void login();
//登陆返回
void loginCallback(boolean status,String userInfo);
}
LoginService:
package com.source.binderqq;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.annotation.Nullable;
public class LoginService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new ILoginInterface.Stub() {
@Override
public void login() throws RemoteException {
//通过服务打开Activity
serviceStartActivity();
}
@Override
public void loginCallback(boolean status, String userInfo) throws RemoteException {
}
};
}
//唤醒登陆页面
private void serviceStartActivity() {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
//是否开启跨进程通信
boolean isStartRemote;
//AIDL定义接口
ILoginInterface iLoginInterface;
EditText etUserName;
EditText etPwd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etUserName = findViewById(R.id.et_username);
etPwd = findViewById(R.id.et_pwd);
//实现双向绑定,绑定Client程序
bindClientService();
}
private void bindClientService() {
Intent intent = new Intent();
intent.setAction("Client_ACTION");
intent.setPackage("com.source.binderdemo");
bindService(intent, conn, BIND_AUTO_CREATE);
isStartRemote = true;
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iLoginInterface = ILoginInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
public void login(View view) {
//模拟QQ登陆
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
String username = etUserName.getText().toString();
String pwd = etPwd.getText().toString();
if (username.equals("admin") && pwd.equals("123456")) {
try {
Toast.makeText(MainActivity.this, "登陆成功", Toast.LENGTH_LONG).show();
iLoginInterface.loginCallback(true, "admin->123456" + new Date().toLocaleString());
finish();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "用户名或密码错误", Toast.LENGTH_LONG).show();
}
}
});
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isStartRemote) {
unbindService(conn);
}
}
}
manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.source.binderqq">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".LoginService"
android:enabled="true"
android:exported="true"
android:process=":remote_qq_server">
<intent-filter>
<action android:name="QQ_Action" />
</intent-filter>
</service>
</application>
</manifest>
然后再贴出来客户端代码:
ILoginInterface:注意包名要和服务端一致
// ILoginInterface.aidl
package com.source.binderqq;
// Declare any non-default types here with import statements
interface ILoginInterface {
//登陆
void login();
//登陆返回
void loginCallback(boolean status,String userInfo);
}
ResultService:
public class ResultService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new ILoginInterface.Stub() {
@Override
public void login() throws RemoteException {
}
@Override
public void loginCallback(boolean status, String userInfo) throws RemoteException {
Log.d("Client", "登陆返回结果:" + status + "," + userInfo);
//通过广播向Activity传送数据
Intent intent = new Intent();
intent.putExtra("status", status);
intent.putExtra("userInfo", userInfo);
intent.setAction("com.source.binderdemo.LoginStatusService");
sendBroadcast(intent);
}
};
}
}
MainActivity:
/**
* 客户端程序,跳转到三方登陆页面
*/
public class MainActivity extends AppCompatActivity {
//是否开启跨进程通信
boolean isStartRemote;
//AIDL定义接口
ILoginInterface iLoginInterface;
MyReceiver receiver;
TextView tvLoginStatus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvLoginStatus = findViewById(R.id.tv_login_status);
//注册广播接收器
receiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.source.binderdemo.LoginStatusService");
MainActivity.this.registerReceiver(receiver, filter);
}
/**
* 获取广播数据
*
* @author jiqinlin
*/
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
boolean status = bundle.getBoolean("status");
String userInfo = bundle.getString("userInfo");
tvLoginStatus.setText(status + "," + userInfo);
}
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iLoginInterface = ILoginInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**
* 使用QQ登陆
*
* @param view
*/
public void useQQLogin(View view) {
if (iLoginInterface == null) {
Toast.makeText(this, "还没绑定服务,请先绑定", Toast.LENGTH_LONG).show();
} else {
try {
iLoginInterface.login();
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(this, "没有安装QQ应用", Toast.LENGTH_LONG).show();
}
}
}
/**
* 绑定远程服务
*
* @param view
*/
public void bind(View view) {
Intent intent = new Intent();
intent.setAction("QQ_Action");
intent.setPackage("com.source.binderqq");
bindService(intent, conn, BIND_AUTO_CREATE);
isStartRemote = true;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isStartRemote) {
unbindService(conn);
}
}
}
manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.source.binderdemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ResultService"
android:enabled="true"
android:exported="true"
android:process=":remote_client">
<intent-filter>
<action android:name="Client_ACTION" />
</intent-filter>
</service>
</application>
</manifest>
注意点:
1. AIDL的路径要保持和服务端一致
2. 服务的双向绑定
END.