Preface
Today I saw a Tencent interview question about Android multi-process, so let’s talk about it today.
How to create multiple processes in Android
1) The first type, as everyone knows, is to AndroidManifest
assign android:process
attributes to the four major components .
<activity android:name="com.example.uithread.UIActivity"
android:process=":test"/>
<activity android:name="com.example.uithread.UIActivity2"
android:process="com.example.test"/>
As you can see, android:process
there are two ways of expression:
:test
. ":" means to add the current package name in front of the current process name, if the current package name is com.example.jimu. Then the process name should be com.example.jimu:test. This kind of process starting with a colon belongs to the private process of the current application, and other application components cannot run in the same process with him.com.example.test
. The second way of expression is a complete naming method, which is the process name of the new process, which belongs to the global process, and other applications can run into the same process by way of shareUID.
To put it simply shareUID
: Normally, each app in Android is a separate process, which corresponds to a unique linux user ID, so the files or components of the application can be kept visible only to the application. But there is also a way to share files with different apks, which is through shareUID, which allows different apks to use the same user ID. Post usage:
//app1
<manifest package="com.test.app1"
android:sharedUserId="com.test.jimu"
>
//app2
<manifest package="com.test.app2"
android:sharedUserId="com.test.jimu"
>
//app1中获取app2的上下文:
Context mContext=this.createPackageContext("com.test.app2", Context.CONTEXT_IGNORE_SECURITY);
2) The second method of creating a process is native
to fork a process in the layer through JNI .
This is more complicated. I searched for some information on the Internet and found a fork of an ordinary process:
//主要代码
long add(long x,long y) {
//fpid表示fork函数返回的值
pid_t fpid;
int count=0;
fpid=fork();
}
//结果:
USER PID PPID VSZ RSS STAT NAME
root 152 1 S zygote
u0_a66 17247 152 297120 44096 S com.example.jni
u0_a66 17520 17247 0 0 Z com.example.jni
The final result is that a process can be created, but it is not running, the memory occupied is 0, and it is in the state of a zombie program.
But it fork
comes out through ordinary processes . We know that all processes in Android are fork out directly through the zygote process (fork can be understood as a copy of the current process hatched). So I don’t know if it can be successful to operate the zygote process directly. Anyone who knows it can tell you about it in the WeChat discussion group.
By the way, some friends may ask, why all processes must use zygote
process fork?
- This is because
fork
the behavior is to copy the entire user's spatial data and all system objects, and only copy the current thread to the new process. In other words, the parent process其他线程
disappears in the child process. In order to prevent various problems (such as deadlocks and inconsistent states), only thezygote
process, this single-threaded process, will fork the new process. - And
zygote
some initialization work will be done in the process, such as starting the virtual machine and loading system resources. In this way, the child process can be directly shared when fork, and efficiency is improved. This is also the advantage of this mechanism.
Is there any problem with using multiple processes for an application?
As mentioned above, the method of creating a process is very simple. Just write an android:process attribute. Isn’t it that simple to use? Obviously not, multiple processes in an application will cause various problems, mainly as follows:
- The static member and singleton patterns are completely invalid . Because each process is assigned to an independent virtual machine, and different virtual machines have different address spaces in memory allocation, so accessing objects of the same class in different processes, that is, different virtual machines, will generate more Copies.
- The thread synchronization mechanism is completely invalid . As above, different memory cannot guarantee thread synchronization, because the objects locked by threads are different.
- SharedPreferences is no longer reliable . A previous article about SharedPreferences said this, SharedPreferences does not support multi-process.
- Application will be created multiple times . Multi-process actually corresponds to multiple applications, so the process of creating a new process actually starts a new application, and naturally a new Application is created. Application and virtual machine correspond to the components in a process one-to-one.
IPC method in Android
Since there are many problems with multiple processes, there is naturally a solution. Although memory cannot be shared, data interaction can be carried out, that is, multi-process communication can be carried out, referred to as IPC.
The following will specifically talk about the eight IPC methods in Android:
1. The four major components of Bundle Android support the use of intents Bundle
to transfer data , so the direct inter-process communication of the four major components can use Bundle. But the Bundle has a size limit. Note that bundle
the data transfer limit is 1M. If your data exceeds this size, you need to use other communication methods.
2. File sharing is the way that multiple processes 读写一个文件
exchange data and complete inter-process communication. But this method has a big drawback that multi-threaded reading and writing are prone to problems, that is 并发问题
, if concurrent reading or concurrent writing occurs, they are prone to problems, so this method is suitable for direct communication between processes that do not require high data synchronization.
Someone may be surprised here, is SharedPreference
n't it just reading and writing xml files? Why doesn't it support inter-process communication?
- This is because the system has
SharedPreference
a read-write cache strategy, that is, there is a cache of SharedPreference files in memory, which involves memory, which is definitely not so reliable in multi-process.
3. Messenger Messenger
is used to transfer the Message object, and the data we want to transfer can be placed in the Message . It is a lightweight IPC solution, and the underlying implementation is AIDL.
Look at the usage, client and server communication:
//客户端
public class MyActivity extends Activity {
private Messenger mService;
private Messenger mGetReplyMessager=new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
//收到消息
break;
}
super.handleMessage(msg);
}
}
private ServiceConnection mConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
Message msg = Message.obtain(null,0);
Bundle bundle = new Bundle();
bundle.putString("test", "message1");
msg.setData(bundle);
msg.replyTo = mGetReplyMessager; //设置接受消息者
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent i=new Intent(this,ServerService.class);
bindService(i,mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
//服务端
public class ServerService extends Service {
Messenger messenger = new Messenger(new MessageHandler());
public ServerService() {
}
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
private class MessageHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0:
//收到消息并发送消息
Messenger replyTo = msg.replyTo;
Message replyMsg = Message.obtain(null,1);
Bundle bundle = new Bundle();
bundle.putString("test","111");
replyMsg.setData(bundle);
try {
replyTo.send(replyMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
super.handleMessage(msg);
}
}
}
4. AIDL
Although Messenger can send and receive messages, it cannot process a large number of messages at the same time, and it cannot cross-process methods. But AIDL can do it, here is a brief description of AIDL
the use process:
The server first establishes a Service to listen to the client's connection request, then creates an AIDL file, declares the interface exposed to the client in this AIDL file, and finally implements this AIDL
interface in the Service .
The client needs to bind the service of this server, and then convert the Binder
object returned by the server into the attributes of the AIDL interface, and then it can call the methods in the AIDL.
5. ContentProvider
Everyone should be familiar with this, one of the four major components, specifically for data sharing between different applications. Its underlying implementation is achieved through Binder. There are two main steps:
1. Declare Provider
<provider
android:authorities="com.test.lz" //provider的唯一标识
android:name=".BookProdiver"
android:permission="com.test.permission"
android:process=":provider"/>
- android:authorities, a unique identifier, generally use the package name. When accessing data, the outside world is accessed through uri, which consists of four parts
content://com.test.lz/ table/ 100
| | | |
固定字段 Authority 数据表名 数据ID
- android:permission, permission attributes, and more
readPermission,writePermission
. If the provider declares permission-related attributes, other applications must also declare the corresponding permissions to perform read and write operations. such as:
//应用1
<permission android:name="me.test.permission" android:protectionLevel="normal"/>
<provider
android:authorities="com.test.lz"
android:name=".BookProdiver"
android:permission="com.test.permission"
android:process=":provider"/>
//应用2
<uses-permission android:name="me.test.permission"/>
2. Then external applications can access the data through the add, delete, check and modify method of getContentResolver().
6. Socket
Sockets are used a lot in network communication, such as TCP and UDP. Regarding Socket communication, borrow a picture on the network to illustrate:
Then simply paste the key code:
//申请权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
//服务端
ServerSocket serverSocket = new ServerSocket(8688);
while(isActive) {
try {
//不断获取客户端连接
final Socket client = serverSocket.accept();
new Thread(){
@Override
public void run() {
try {
//处理消息
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
} catch (IOException e) {
e.printStackTrace();
}
}
//客户端
Socket socket = null;
while(socket==null){
//为空代表链接失败,重连
try {
socket = new Socket("localhost",8688);
out = new PrintWriter(socket.getOutputStream(),true);
handler.sendEmptyMessage(1);
final Socket finalSocket = socket;
new Thread(){
@Override
public void run() {
try {
reader = new BufferedReader(new InputStreamReader(finalSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
while(!MainActivity.this.isFinishing()){
//循环读取消息
try {
String msg = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
} catch (IOException e) {
e.printStackTrace();
}
}
7. Binder connection pool
About the introduction of Binder, the previous article has already said. Here mainly talk about a Binder's actual use of technology- Binder连接池
. Since every AIDL request has to open a service to prevent too many services from being created, the Binder连接池
technology is cited . The main function of the Binder connection pool is to Binder
uniformly forward the requests of each business module to the remote Service for execution, thereby avoiding the Service
process of repeated creation . Post the working principle of Binder connection pool:
- Each business module creates its own AIDL interface and implements this interface, and then provides its own unique identifier and its corresponding Binder object to the server.
- For the server side, only one Service is needed. The server side provides a queryBinder interface, which can return the corresponding Binder object to them according to the characteristics of the business module. After different business modules get the required Binder object You can make remote method calls.
How to use it? Or simply post the key source code
public class BinderPoolImpl extends IBinderPool.Stub {
private static final String TAG = "Service BinderPoolImpl";
public BinderPoolImpl() {
super();
}
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
Log.e(TAG, "binderCode = " + binderCode);
IBinder binder = null;
switch (binderCode) {
case 0:
binder = new SecurityCenterImpl();
break;
case 1:
binder = new ComputeImpl();
break;
default:
break;
}
return binder;
}
}
public class BinderPool {
//...
private IBinderPool mBinderPool;
private synchronized void connectBinderPoolService() {
Intent service = new Intent();
service.setComponent(new ComponentName("com.test.lz", "com.test.lz.BinderPoolService"));
mContext.bindService(service, mBinderPoolConnection, Context.BIND_AUTO_CREATE);
}
public IBinder queryBinder(int binderCode) {
IBinder binder = null;
try {
if (mBinderPool != null) {
binder = mBinderPool.queryBinder(binderCode);
}
} catch (RemoteException e) {
e.printStackTrace();
}
return binder;
}
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Log.e(TAG, "binderDied");
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
mBinderPool = null;
connectBinderPoolService();
}
};
}
8. BroadcastReceiver
Broadcasting, needless to say more~ For example, we can monitor system startup broadcasts, network change broadcasts, etc., which all reflect the role of inter-process communication.
to sum up
Prepare for the interview before the interview!
Next, I will share a review route for the interview. If you are also preparing for an interview but don't know how to review efficiently, you can refer to my review route. If you have any questions, please feel free to communicate with each other. Come on!
Here is a direction for everyone to learn systematically:
1. Watch the video for systematic learning
The experience of Crud in the past few years has made me realize that I am really a fighter in the rookie. It is also because of Crud that my technology is relatively fragmented, and it is not deep enough to be systematic, so it is necessary to study again. What I lack is the system knowledge, the poor structural framework and the thinking, so learning through videos is better and more comprehensive. Regarding video learning, individuals can recommend to study at station B. There are many learning videos on station B. The only drawback is that they are free and easily outdated.
In addition, I have collected several sets of videos myself, and I can share them with you if I need them.
2. To systematically sort out knowledge and improve reserves
There are so many knowledge points in client development, and there are still so little things in the interview. Therefore, there are no other tricks for the interview, just look at how well you prepare for these knowledge points. So, when you go out for an interview, it is good to see which stage you have reached in your review.
System learning direction:
-
Essential skills for architects to build foundations: in-depth Java generics + annotations in simple language + concurrent programming + data transmission and serialization + Java virtual machine principles + reflection and class loading + dynamic proxy + efficient IO
-
Android advanced UI and FrameWork source code: advanced UI promotion + Framework kernel analysis + Android component kernel + data persistence
-
360° overall performance tuning: design ideas and code quality optimization + program performance optimization + development efficiency optimization
-
Interpretation of open source framework design ideas: hot repair design + plug-in framework interpretation + component framework design + image loading framework + network access framework design + RXJava responsive programming framework design + IOC architecture design + Android architecture component Jetpack
-
NDK module development: NDK basic knowledge system + underlying image processing + audio and video development
-
WeChat Mini Program: Mini Program Introduction + UI Development + API Operation + WeChat Docking
-
Hybrid development and Flutter: Html5 project combat + Flutter advanced
After the knowledge is sorted out, it is necessary to check and fill in the vacancies. Therefore, for these knowledge points, I have prepared a lot of e-books and notes on hand. These notes provide a perfect summary of each knowledge point.
3. Read the source code, look at the actual combat notes, and learn the ideas of God
"Programming language is the way the programmer expresses, and the architecture is the programmer's cognition of the world". Therefore, if programmers want to quickly understand and learn the architecture, reading the source code is essential. Reading the source code is to solve problems + understand things, and more importantly: to see the ideas behind the source code; programmers say: read ten thousand lines of source code, and practice ten thousand kinds of practices.
Mainly contains WeChat MMKV source code, AsyncTask source code, Volley source code, Retrofit source code, OkHttp source code, etc.
4. On the eve of the interview, sprint through questions
Within a week before the interview, you can start sprinting. Please keep in mind that when brushing the questions, the technology is the first priority, and the algorithm is basic, such as sorting, etc., and the intellectual questions are generally not asked unless they are school recruits.
Regarding the interview questions, I personally prepared a set of systematic interview questions to help you learn from one another:
There are also a series of Android learning resources that took more than a year to organize: Android源码解析、Android第三方库源码笔记、Android进阶架构师七大专题学习、历年BAT面试题解析包、Android大佬学习笔记
wait.
The above content is free to share with everyone, friends who need the full version, click here to see all the content .