Reprint address: http://blog.csdn.net/yuanzeyao/article/details/42386549
stay Android All resources are stored in the res directory, including drawable, layout, strings,anim and so on. When we add any resource to the project, it will correspond to that in the R class. Resource allocation is an id that we use to access resources in our applications. I believe that friends who have developed Andorid will not be unfamiliar with these, so this is not what I want to say today. What I want to learn with you today is how Android manages resources. In Android system, there are a lot of resources. Some of them are defined by xml files (drawable is image), such as layout, string, anim are xml files, while xml files such as layout, anim and strings are just parsing xml files and reading specified values, but the analysis of controls in layout files is more complex, such as for a Button, which needs to be solved. Analyzing all its attribute values, how does this work?
Here we first need to consider a question, is a control what attributes are defined? For example, what attributes does TextView have? Why can I only use style instead of android:theme when I set TextView? Where are all these information defined? To find out this problem, I have to get answers from source engineering. I use Android 4.1 project. If you use other versions, you may use some discrepancies.
Look at three documents first.
1,d:\android4.1\frameworks\base\core\res\res\values\attrs.xml
Looking at the attrs.xml file, I wonder if you think of anything? When we customize the control, will we create an attrs.xml file? The purpose of using attrs.xml file is to add attributes to our customized control. When you open this directory, you will see that a styleable named "Theme" is defined, as follows (I only intercept part)
In this file, most of the attributes that can be used in Android are defined. I'm talking about "definition" instead of "declaration". The biggest difference in the syntax of the same name is that the definition has format attributes, while the declaration has no format attributes.
2,d:\android4.1\frameworks\base\core\res\res\values\attrs_manifest.xml
The name of this file is similar to the name of the file above, that is, an additional manifest, so the idea is to define the attributes in the Android Manifest. XML file. Here is an important sentence.
Define a theme attribute, which is the theme attribute we usually use on Activity
3,d:\android4.1\frameworks\base\core\res\res\values\themes.xml
This file begins by defining a sytle called "Theme" as follows (screenshot)
This is the Theme that we usually use in Application or Activity. From this point of view, Theme is also a style. Why can style only be used in View/ViewGorup forever, while Theme can only be used in Activity or Application? Keep this in mind, and we'll answer it later.
Let's integrate the contents of these three files. Firstly, most of the attributes in Android are defined in attrs.xml file. That is to say, most of the attributes in all View/Activity are defined here later. Then, in attrs_manifest.xml, an attribute called theme is defined. Its value is then themes text. The Theme defined in the file or inherited from the style of "Theme".
With the above knowledge, let's analyze the two problems mentioned above.
1. Where are the properties of the TextView control (and other controls as well) defined?
2. Since Theme is also style, why can View only use style and Activity only use theme?
All View attribute definitions are in the attrs.xml file, so let's go to the attrs.xml file to find the styleable of TextView.
I only intercepted part of the above attributes. Please note that all the attributes here are "declarations". If you search for this styleable, you will find that the declaration of theme will not be found in the styleable of TextView, so it is ineffective to set theme attributes for any view. See the following code to see why.
Define an attrs.xml
Define a MyTextView
In attrs.xml, I defined an orientation attribute for MyTextView, and then read it in the constructor of MyTextView. Here we refer to the class TypeArray. We find that we need to pass in the value of R.style.MyTextView, which is provided by the system for us to access the MyTextView styleable. An id, when we need to get the value of orientation, we get it through R.style.MyTextView_orientation. Because there is no definition or declaration of the theme attribute in MyTextView, we can not find the ID of R.styleable.MyTextView_theme, so we can not parse its theme attribute. Again, back to the TextView styleable, because there is no definition of the theme attribute in the textView styleable, the theme is useless for the TextView. So even if you add the theme attribute to TextView, even if the compiler doesn't error you, the theme is ignored.
Let's look at how the properties of Activity are defined. Since Activity is defined in the AndroidManigest.xml file, we look in attrs_manifest.xml.
Obviously, Activity declares theme in styleable, so it can parse the theme attribute.
The above two questions have been answered, and the next topic to discuss is the acquisition process of Resources.
This topic was discussed in another article of mine. Deeper understanding of Context Here we will learn about the acquisition process of Resources.
In Android system, there are two main ways to obtain Resources, through Context and Package Manager.
First, let's look at what we get from Context. Here's a class diagram of Context related classes.
As you can see from the figure, Context has two subclasses, one is ContextWrapper, the other is ContextImpl, and ContextWrapper depends on ContextImpl. Combining with the source code, we will find that Context is an abstract class, its real implementation class is ContextImpl, and ContextWrapper, like his name, is just a layer of packaging for Contextext. Its function is to call the attribute mBase, which is essentially a variable of ContextImpl type. When we get Resources, we call the getResources method of Context, so let's look directly at the getResources method of ContextImpl.
We found that this method is very simple, that is to return the mResources attribute, then where does this attribute assign value? By looking for it, we found that it is actually creating ContextImpl and assigning value by calling Init. (Specific logic refers to "Deeper Understanding Context"). Here I first give the sequence diagram of getResource s method. Then track the source code.
Let's start with the init method.
We found that the assignment of mResource was done by calling getResource in LoadedApk, passing in parameters of ActivityThead type.
In the getResources method, we call the getTopLevelResources method of ActivityThrad, where mResDir is the path of the APK file (for the app installed by the user, this path is under / data/app apk). As you can see from the sequence diagram, getTopelResources actually calls a method with the same name. Let's look directly at the method of its homonym.
The logic of this code is not complicated. First, we get the resource from mActiveResouuces by key. If the resource is not null and is up-to-date, we return it directly. Otherwise, we create an AssetManager object and call the addAssetPath method of AssetManager. Then we create a Resour using the created AssetManager as a parameter. CES object, saved and returned. From the above sequence diagram, we find that when we create AssetManager, we call init method in its constructor. Let's see what the init method does.
It's a local method, so we have to look at the corresponding Jni code.
This calls the addDefaultAssets method of the local AssettManager.
In this case, ANDROID_ROOT saves the / system path, while kSystem Assets saves the / system path.
Remember what framework-res.apk is, all the resource files in the system.
At last, I understand that the principle is to load the resources of the system.
Next, look at the addAssetPath method. After entering the source code, you will find that it is also a local method and you need to look at the jni code.
The addAssetPath method of the local AssetManager method is called here. Like system resources, they are loaded in.
Let's take a look at the process for PackageManager to get resources.
Getting resources in Package Manager calls the getResourcesForApplication method. getResourcesForApplication also has a method of the same name. Let's see the one doing business.
- @Override public Resources getResourcesForApplication(
- ApplicationInfo app) throws NameNotFoundException {
- if (app.packageName.equals("system")) {
- return mContext.mMainThread.getSystemContext().getResources();
- }
- Resources r = mContext.mMainThread.getTopLevelResources(
- app.uid == Process.myUid() ? app.sourceDir
- : app.publicSourceDir, mContext.mPackageInfo);
- if (r != null) {
- return r;
- }
- throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
- }