Easy Tutorial
❮ Android Tutorial Sensor4 Implementation Of Merge Sort ❯

10.8 LayoutInflater (Layout Service)

Category Android Basic Tutorial

Introduction:

>

This section continues with the LayoutInflater (Layout Service) in Android system services. When it comes to layouts, you might immediately think of writing an XML layout, then using setContentView() in an Activity to load and display it on the screen. However, under the hood, this process still relies on LayoutInflater, which uses Android's built-in Pull parser to parse the layout. LayoutInflater is commonly used in Android for dynamically loading layouts or adding controls. In this section, we will explore some practical uses of LayoutInflater in development.

Official API Documentation: LayoutInflater


1. Introduction to LayoutInflater


1) What is LayoutInflater?

>

Answer: A system service for loading layouts, which instantiates View objects corresponding to Layout XML files. It cannot be used directly and must be obtained via the getLayoutInflater() or getSystemService() methods to get an instance of LayoutInflater bound to the current Context!


2) Usage of LayoutInflater

① Three methods to get an instance of LayoutInflater:

LayoutInflater inflater1 = LayoutInflater.from(this);  
LayoutInflater inflater2 = getLayoutInflater();  
LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

Note: The latter two methods actually use the first method under the hood.

② Method to load a layout:

>

public View inflate (int resource, ViewGroup root, boolean attachToRoot) The method has three parameters:

① The resource ID of the layout to be loaded.

② A parent layout to wrap around the loaded layout. If not needed, pass null.

③ Whether to wrap the outermost layer of the loaded layout file with a root layout. If this parameter is not set, it defaults to true if root is not null, and has no effect if root is null. If root is not null and attachToRoot is true, the loaded layout will be wrapped with a root layout; if false, the root will have no effect. Simply put, it determines whether to add an outer container (root) to the loaded layout.


③ Setting attributes via LayoutInflater.LayoutParams:

>

For example, a RelativeLayout can add rules using the addRule method to set positions: whether relative to the parent container, another child control, or to set margins, etc. This is determined by your needs.


2. Loading Layout with Pure Java Code

>

We are accustomed to using XML to generate the layouts we need, but in certain cases, we need to dynamically add components or layouts using Java code.

However, it is not recommended to completely use Java code to create Android page layouts. Firstly, the code can become lengthy and complex, leading to confusion and making it difficult to separate business logic. We recommend using XML for layout and modifying components within it using Java code. However, there are times when dynamic addition of components using Java is necessary.

Process of loading layout with pure Java code:


——Step 1:

Create a container: LinearLayout ly = new LinearLayout(this);

Create a component: Button btnOne = new Button(this);

——Step 2:

Set attributes for the container or components: For example, for LinearLayout, you can set the orientation: ly.setOrientation(LinearLayout.VERTICAL); For components like Button: btnOne.setText("Button 1"); Refer to the Android API for setting attributes; usually, XML attributes can be set by adding set before the attribute name, such as setPadding(left, top, right, bottom);

——Step 3:

Add components or containers to the container. You may need to set the position or size of the components: You will need a class called LayoutParams, which can be seen as a package of information about the layout container, encapsulating position and size information. Here’s an example of setting size:

LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(  
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

For setting positions, typically we consider RelativeLayout: You use the addRule() method of LayoutParams. You can add multiple addRule() calls. For example, to set the alignment of a component within its parent container:

RelativeLayout rly = new RelativeLayout(this);  
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
lp2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);  
Button btnOne = new Button(this);  
rly.addView(btnOne, lp2);

To align relative to another component: (Note: You need to manually set an ID for the reference component) For example: After setting btnOne to center, place btnTwo below btnOne and align to the right of the parent container:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        RelativeLayout rly = new RelativeLayout(this);  
        Button btnOne = new Button(this);  
        btnOne.setText("Button 1");  
        Button btnTwo = new Button(this);  
        btnTwo.setText("Button 2");  
        // Set an ID for button 1  
        btnOne.setId(123);  
        // Set position for button 1, centered in the parent container  
        RelativeLayout.LayoutParams rlp1 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp1.addRule(RelativeLayout.CENTER_IN_PARENT);  
        // Set position for button 2, below button 1 and aligned to the right of the parent container  
        RelativeLayout.LayoutParams rlp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp2.addRule(RelativeLayout.BELOW, 123);  
        rlp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);  
        // Add components to the outer container  
        rly.addView(btnTwo, rlp2);  
        rly.addView(btnOne, rlp1);  
        // Set the current view to load rly  
        setContentView(rly);  
    }  
}

——Step 4:

Call setContentView() to load the layout object. Additionally, if you want to remove a View from a container, you can call container.removeView(component_to_remove);

Screenshot:


3. Dynamically Adding Controls or XML Layouts with Java Code

>

In the second point, we explained loading layouts using pure Java code, which is not commonly used. More often, we dynamically add View controls and dynamically load XML layouts.

1) Dynamically adding View with Java code

There are two ways to dynamically add components, differing in whether you need to call setContentView(R.layout.activity_main) first. Below is an example of adding a Button using both methods:

First, write a layout file: activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/RelativeLayout1"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  

    <TextView   
        android:id="@+id/txtTitle"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="I am a layout loaded from an XML file"/>  

</RelativeLayout>

First method without calling setContentView() first:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        Button btnOne = new Button(this);  
        btnOne.setText("I am a dynamically added button");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);
        LayoutInflater inflater = LayoutInflater.from(this);
        RelativeLayout rly = (RelativeLayout) inflater.inflate(
                R.layout.activity_main, null)
                .findViewById(R.id.RelativeLayout1);
        rly.addView(btnOne, lp2);
        setContentView(rly);
    }
}

The second method does not require setContentView() to load the layout file first:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btnOne = new Button(this);
        btnOne.setText("I am a dynamically added button");
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);
        RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);
        rly.addView(btnOne, lp2);
    }
}

Analysis Summary:

>

The code is simple. After creating the button, we create a LayoutParams object to set the Button's size, and then use the addRule() method to set the Button's position!

First Method: By using LayoutInflate's inflate() method to load the activity_main layout, we obtain the outer container, then add the button to the container with addView, and finally call setContentView().

Second Method: Since we have already loaded the layout using the setContentView() method, we can now find the outer container using findViewById, then add the button with addView, and finally call setContentView().

Additionally, the setContentView() sets the view node to the root node of the entire XML.


2) Dynamically Loading XML Layout in Java Code

Next, we'll switch to loading an XML file dynamically! Dynamically adding an XML file! First, let's write the main layout file and the dynamically loaded layout file:

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/btnLoad"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Load Layout Dynamically"/>
</RelativeLayout>

inflate.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:id="@+id/ly_inflate" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="I am a layout loaded by Java code" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="I am a small button in the layout" />
</LinearLayout>

Next, in our MainActivity.java, we dynamically load the XML layout:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Obtain the LayoutInflater object;
        final LayoutInflater inflater = LayoutInflater.from(this);
        // Obtain the outer container object
        final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);
        Button btnLoad = (Button) findViewById(R.id.btnLoad);
        btnLoad.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // Load the layout object to be added
                LinearLayout ly = (LinearLayout) inflater.inflate(
                        R.layout.inflate, null, false).findViewById(
                        R.id.ly_inflate);
                // Set the size and position of the loaded layout
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
                lp.addRule(RelativeLayout.CENTER_IN_PARENT);
                rly.addView(ly, lp);
            }
        });
    }
}

Code Analysis:

>

① Obtain the container object:

final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);

② Obtain the Inflater object, and load the XML of the layout to be added, find the outermost root node via findViewById:

final LayoutInflater inflater = LayoutInflater.from(this);
LinearLayout ly = (LinearLayout) inflater.inflate(R.layout.inflate, null, false)
   .findViewById(R.id.ly_inflate);

③ Set the size and position information for this container:

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
               LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
       lp.addRule(RelativeLayout.CENTER_IN_PARENT);

④ Add to the outer container:

rly.addView(ly, lp);

4. Source Code of LayoutInflater's inflate() Method

>

Finally, here is the source code of LayoutInflater's inflate() method for those interested. It's essentially just Pull parsing.

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {
        final AttributeSet attrs = Xml.asAttributeSet(parser);
        mConstructorArgs[0] = mContext;
        View result = root;
        try {
            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG &&
                    type != XmlPullParser.END_DOCUMENT) {
            }
            if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
                        + ": No start tag found!");
            }
            final String name = parser.getName();
            if (TAG_MERGE.equals(name)) {
                if (root == null || !attachToRoot) {
                    throw new InflateException("merge can be used only with a valid "
                            + "ViewGroup root and attachToRoot=true");
                }
                rInflate(parser, root, attrs);
            } else {
                View temp = createViewFromTag(name, attrs);
                ViewGroup.LayoutParams params = null;
                if (root != null) {
                    params = root.generateLayoutParams(attrs);
                    if (!attachToRoot) {
                        temp.setLayoutParams(params);
                    }
                }
                rInflate(parser, temp, attrs);
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }
                if (root == null || !attachToRoot) {
                    result = temp;
                }
            }
        } catch (XmlPullParserException e) {
            InflateException ex = new InflateException(e.getMessage());
            ex.initCause(e);
            throw ex;
        } catch (IOException e) {
            InflateException ex = new InflateException(
                    parser.getPositionDescription()
                    + ": " + e.getMessage());
            ex.initCause(e);
            throw ex;
        }
        return result;
    }
}

Summary of This Section:

This section explains Android's LayoutInflater (layout service) and how to dynamically load views and widgets. It is hoped that this will be helpful for beginners learning about widgets. That's all for now, thank you.

-2.6.0 Basic Usage of Other Common Dialogs

-2.6.1 Basic Usage of PopupWindow

-2.6.2 Menu

-2.6.3 Simple Usage of ViewPager

-2.6.4 Simple Usage of DrawerLayout

-3.1.1 Event Handling Mechanism Based on Listeners

-3.2 Event Handling Mechanism Based on Callbacks

-3.3 Analysis of Handler Message Passing Mechanism

-3.4 TouchListener vs OnTouchEvent + Multi-touch

-3.5 Listening for Content Changes in EditText

-3.6 Responding to System Setting Events (Configuration Class)

-3.7 AsyncTask Asynchronous Tasks

-3.8 Gestures

-4.1.1 Introduction to Activity

-4.1.2 Getting Started with Activity

-4.1.3 Advanced Activity

-4.2.1 Introduction to Service

-4.2.2 Advanced Service

-4.2.3 Expert Service

-4.3.1 Introduction to BroadcastReceiver

-4.3.2 In-depth BroadcastReceiver

-4.4.1 Introduction to ContentProvider

-4.4.2 Further Exploration of ContentProvider - Document Provider

-4.5.1 Basic Usage of Intent

-4.5.2 Passing Complex Data with Intent

-5.1 Basic Overview of Fragment

-5.2.1 Fragment Example - Bottom Navigation Bar Implementation (Method 1)

-5.2.2 Fragment Example - Bottom Navigation Bar Implementation (Method 2)

-5.2.3 Fragment Example - Bottom Navigation Bar Implementation (Method 3)

-5.2.4 Fragment Example - Bottom Navigation Bar + ViewPager Page Swipe

-5.2.5 Fragment Example - Simple Implementation of News/Shopping App List Fragment

-6.1 Data Storage and Access - File Storage and Reading

-6.2 Data Storage and Access - SharedPreferences for Saving User Preferences

-6.3.1 Data Storage and Access - Introduction to SQLite Database

-6.3.2 Data Storage and Access - Further Exploration of SQLite Database

-7.1.1 Android Network Programming and Learning HTTP Protocol

-7.1.2 Learning Android HTTP Request and Response Headers

-7.1.3 Android HTTP Request Method: HttpURLConnection

-7.1.4 Android HTTP Request Method: HttpClient

-7.2.1 Android XML Data Parsing

-7.2.2 Android JSON Data Parsing

-7.3.1 Android File Upload

-7.3.2 Android File Download (1)

-7.3.3 Android File Download (2)

-7.4 Android Calling WebService

-7.5.1 Basic Usage of WebView

-7.5.2 WebView and JavaScript Interaction Basics

-7.5.3 WebView Considerations After Android 4.4

-7.5.4 WebView File Download

-7.5.5 WebView Cache Issues

-7.5.6 WebView Handling Webpage Error Codes

-7.6.1 Socket Learning Network Basics Preparation

-7.6.2 TCP Protocol Based Socket Communication (1)

-7.6.3 TCP Protocol Based Socket Communication (2)

-7.6.4 UDP Protocol Based Socket Communication

-8.1.1 Summary of 13 Drawable Types in Android Part 1

-8.1.2 Summary of 13 Drawable Types in Android Part 2

-8.1.3 Summary of 13 Drawable Types in Android Part 3

-8.2.1 Comprehensive Analysis of Bitmap Part 1

-8.2.2 OOM Issues Caused by Bitmap

-8.3.1 Detailed Explanation of Three Drawing Tools

-8.3.2 Drawing Class Practical Examples

-8.3.3 Paint API - MaskFilter

-8.3.4 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 1)

-8.3.5 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 2)

-8.3.6 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 3)

-8.3.7 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 4)

-8.3.8 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 5)

-8.3.9 Paint API - ColorFilter (Color Filter) (1/3)

-8.3.10 Paint API - ColorFilter (Color Filter) (2/3)

-8.3.11 Paint API - ColorFilter (Color Filter) (3/3)

-8.3.12 Paint API - PathEffect (Path Effect)

-8.3.13 Paint API - Shader (Image Rendering)

-8.3.14 Paint Enum/Constants and ShadowLayer Shadow Effect

WeChat Subscription

English:

❮ Android Tutorial Sensor4 Implementation Of Merge Sort ❯