1. 多進程
開啟方式:
-
android:process = ":remote"
android:process="完整報包名"
2. 基本概念
2.1 AIDL
2.1.1 AIDL的基本概念
- 當客戶端發(fā)起請求時,當前線程會被掛起,所以如果一個遠程方法是很耗時的榨馁,那么不能在UI線程中發(fā)起此遠程請求;
- 服務端的
Binder
方法運行在Binder線程池中输钩,所以Binder方法不管是否耗時都應該采用同步的方法去實現(xiàn) - 所有能在
Binder
中傳輸的類都需要實現(xiàn)IInterface
這個類 - 內部
Stub
類就是Binder
2.1.2 實現(xiàn)AIDL的基本步驟
步驟1:創(chuàng)建服務端工程IPC_Server
步驟2:創(chuàng)建AIDL文件IMyService.AIDl
// IMyService.aidl
package com.example.ipc_server;
// Declare any non-default types here with import statements
interface IMyService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
List<Student> getStudent();
void addStudent(in Student student);
}
- AIDL支持的數據類型:基本數據類型,String和Charsequence仲智,ArrayList买乃,HashMap,Parcelable坎藐,AIDL
- 注意:如果使用了Parcelable對象为牍,需要創(chuàng)建和對象同名的aidl文件
- 注意:除了基本數據類型,其他類型需要表明方向:
in
out
inout
- 注意:aidl接口不支持靜態(tài)常量岩馍,只能寫方法
步驟3:Server端實現(xiàn)
package com.example.ipcdemo;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
public class ServerService extends Service {
private static final String TAG = "ServerService";
public final static int MSG_FROM_CLIENT = 1;
private Binder mBinder = new IBookInterface.Stub() {
@Override
public List<Book> getBook() throws RemoteException {
// 具體代碼
return null;
}
@Override
public void addBook(Book book) throws RemoteException {
//具體代碼
}
};
public ServerService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
步驟4:Client端實現(xiàn)
package com.example.ipcdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IBookInterface iBookInterface = IBookInterface.Stub.asInterface(iBinder); //轉化成aidl接口 IBookInterface.adil
try {
iBookInterface.addBook(new Book("大頭兒子與小頭爸爸", 10));
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.btn);
final Intent intent = new Intent(this, ServerService.class);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
bindService(intent, connection, BIND_AUTO_CREATE);
}
});
}
}
2.1.3 推薦閱讀
- [Android]Service和Activity雙向通信的兩種方式
- Android 通過AIDL在兩個APP之間Service通信
- 帶你了解android的IPC機制
- AIDL碉咆,在Stub類中的asInterface函數
3. Android中的IPC方式
3.1 使用Bundle
- 四大組件中的
Activity
,Service
蛀恩,Receiver
都支持在Intent中傳遞Bundle
-
Bundle
繼承了Parcelable
接口疫铜,因此可以在不同的進程中傳遞數據
3.2 使用文件進行傳輸
- 利用序列化和反序列化操作將對象寫入文件并讀取
- 但是反序列化操作只能保證內容上是一樣的,本質上還是兩個對象
- 可能會產生并發(fā)讀寫問題
3.3 使用Messenger
- 使用串行的方式來處理消息双谆,大量消息時效率低
package com.example.ipcdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Messenger mMessenger;
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mMessenger = new Messenger(iBinder);
Message msg = new Message();
msg.what = ServerService.MSG_FROM_CLIENT;
Bundle bundle = new Bundle();
bundle.putString("msg", "Hello!!!");
msg.setData(bundle);
try {
mMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.btn);
final Intent intent = new Intent(this, ServerService.class);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
bindService(intent, connection, BIND_AUTO_CREATE);
}
});
}
}
package com.example.ipcdemo;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import androidx.annotation.NonNull;
public class ServerService extends Service {
private static final String TAG = "ServerService";
public final static int MSG_FROM_CLIENT = 1;
static class ServerHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
switch(msg.what) {
case MSG_FROM_CLIENT:
Log.d(TAG, "handleMessage: receive message from client!" + msg.getData().getString("msg"));
break;
}
}
}
public ServerService() {
}
@Override
public IBinder onBind(Intent intent) {
ServerHandler serverHandler = new ServerHandler();
Messenger messenger = new Messenger(serverHandler);
return messenger.getBinder();
}
}
3.3 ContentProvider
- 抽象類壳咕,需要實現(xiàn)
onCreate()
,query
,update
,insert
,delete
,getType
- 注冊
- 繼承
SQLiteDatabaseHelper
,操作數據庫 - 注意:
query
,update
,insert
,delete
存在并發(fā)訪問顽馋,因此要注意線程安全和同步 - 注意:
SqliteDatabase
對象內部操作數據庫有同步處理谓厘,但多個SqliteDatabase
對象之間不能保證同步
3.4 Socket
實現(xiàn)步驟:
- 設置網絡權限
<INTERNET>
<ACCESS_NETWORK_STATE>
注意:不能在主線程訪問網絡
- 在服務端Server創(chuàng)建
ServerSocket
監(jiān)聽8688
端口
-
BufferedReader
讀取客戶端數據 -
PrintWriter
給客戶端發(fā)送數據
- 在客戶端Client創(chuàng)建Socket連接
8688
端口
-
BufferedReader
讀取服務端數據 -
PrintWriter
給服務端發(fā)送數據
package com.example.socketdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
public class ClientActivity extends AppCompatActivity {
private static final String TAG = "ClientActivity";
Socket socket = null;
PrintWriter out = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
Intent intent = new Intent(this, Server.class);
startService(intent);
new Thread(new Runnable() {
@Override
public void run() {
try {
socket = new Socket("localhost",8688);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
out = new PrintWriter(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, "run: sendMessage ");
out.println("123");
}
}
}).start();
}
}
package com.example.socketdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class Server extends Service {
private static final String TAG = "Server";
boolean mIsServiceDestroyed = false;
public Server() {
}
@Override
public void onCreate() {
super.onCreate();
new socketThread().start();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
class socketThread extends Thread {
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8688);
} catch (IOException e) {
e.printStackTrace();
}
if(!mIsServiceDestroyed) {
try {
final Socket client = serverSocket.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
responseClient(client);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void responseClient(Socket client) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
out.println("Hello");
while(!mIsServiceDestroyed) {
String str = in.readLine();
Log.d(TAG, "responseClient: " +str);
if(str == null) {
break;
}
out.println("Hello " + new Random().nextInt(3));
}
Log.d(TAG, "Client Quit" );
client.close();
}
}
參考資料:
https://blog.csdn.net/ding3106/article/details/80714410
我的問題:Socket連接不上
網上的解決方法:
1.設置訪問的ip為10.0.2.2
模擬器默認把
127.0.0.1
和localhost
當做本身了,在模擬器上可以用10.0.2.2
代替127.0.0.1
和localhost
寸谜,另外如果是在局域網環(huán)境可以用192.168.0.x
或者192.168.1.x
(根據具體配置)連接本機,這樣應該就不會報錯了竟稳。
目前這個辦法對我沒用
2. 網絡問題
可正常建立連接的:1,同處于一個校園網(使用狀態(tài)信息或者wifi信息里的ip連接)2. 服務器開熱點(移動網打開的情況下)熊痴,客戶端連狀態(tài)信息里面的ip
https://blog.csdn.net/qq_37735413/article/details/80012390
https://www.cnblogs.com/1995hxt/p/4469389.html