0xA05 Android 10 源碼分析:Dialog加載繪製流程以及在Kotlin、DataBinding中的使用

引言

  • 這是 Android 10 源碼分析系列的第 5 篇
  • 分支:android-10.0.0_r14
  • 全文閱讀大概 10 分鐘

經過這篇文章你將學習到如下內容,將在文末總結部分會給出相應的答案java

  • Dialog的的建立流程?
  • Dialog的視圖怎麼與Window作關聯了?
  • 自定義CustomDialog的view的是如何綁定的?
  • 如何使用Kotlin具名可選參數構造類,實現構建者模式?
  • 相比於Java的構建者模式,經過具名可選參數構造類具備如下優勢?
  • 如何在Dialog中使用DataBinding?

閱讀本文以前,若是以前沒有看過 Apk加載流程之資源加載一Apk加載流程之資源加載二 點擊下方連接前去查看,這幾篇文章都是互相關聯的android

本文主要來主要圍繞如下幾個方面來分析:git

  • Dialog加載繪製流程
  • 如何使用Kotlin具名可選參數構造類,實現構建者模式
  • 如何在Dialog中使用DataBinding

源碼分析

在開始分析Dialog的源碼以前,須要瞭解一下Dialog加載繪製流程,涉及到的數據結構與職能github

在包 android.app 下:算法

  • Dialog:Dialog是窗口的父類,主要實現Window對象的初始化和一些共有邏輯
    • AlertDialog:繼承自Dialog,是具體的Dialog的操做實現類
    • AlertDialog.Builder:是AlertDialog的內部類,主要用於構造AlertDialog
  • AlertController:是AlertDialog的控制類
    • AlertController.AlertParams:是AlertController的內部類,負責AlertDialog的初始化參數

瞭解完相關的數據結構與職能,接下來回顧一下Dialog的建立流程編程

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(R.mipmap.ic_launcher);
builder.setMessage("Message部分");
builder.setTitle("Title部分");
builder.setView(R.layout.activity_main);

builder.setPositiveButton("肯定", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        alertDialog.dismiss();
    }
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        alertDialog.dismiss();
    }
});
alertDialog = builder.create();
alertDialog.show();
複製代碼

上面代碼都不會很陌生,主要使用了設計模式當中-構建者模式,設計模式

  1. 構建AlertDialog.Builder對象
  2. builder.setXXX 系列方法完成Dialog的初始化
  3. 調用builder.create()方法建立AlertDialog
  4. 調用AlertDialog的show()完成View的繪製並顯示AlertDialog

主要經過上面四步完成Dialog的建立和顯示,接下來根據源碼來分析每一個方法的具體實現,以及Dialog的視圖怎麼與Window作關聯安全

1 構建AlertDialog.Builder對象

AlertDialog.Builder builder = new AlertDialog.Builder(this);
複製代碼

AlertDialog.Builder是AlertDialog的內部類,用於封裝AlertDialog的構造過程,看一下Builder的構造方法 frameworks/base/core/java/android/app/AlertDialog.javabash

// AlertController.AlertParams類型的成員變量
private final AlertController.AlertParams P;
public Builder(Context context) {
    this(context, resolveDialogTheme(context, Resources.ID_NULL));
}
public Builder(Context context, int themeResId) {
    // 構造ContextThemeWrapper,ContextThemeWrapper 是 Context的子類,主要用來處理和主題相關的
    // 初始化成爲變量 P
    P = new AlertController.AlertParams(new ContextThemeWrapper(
            context, resolveDialogTheme(context, themeResId)));
}
複製代碼
  • ContextThemeWrapper 繼承自ContextWrapper,Application、Service繼承自ContextWrapper,Activity繼承自ContextThemeWrapper

context3

  • P是AlertDialog.Builder中的AlertController.AlertParams類型的成員變量
  • AlertParams中包含了與AlertDialog視圖中對應的成員變量,調用builder.setXXX系列方法以後,咱們傳遞的參數就保存在P中了

1.1 AlertParams封裝了初始化參數

AlertController.AlertParams 是AlertController的內部類,負責AlertDialog的初始化參數 frameworks/base/core/java/com/android/internal/app/AlertController.java數據結構

public AlertParams(Context context) {
mContext = context;
// mCancelable 用來控制點擊外部是否可取消,默承認以取消
mCancelable = true;
// LayoutInflater 主要來解析layout.xml文件
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
複製代碼

2 調用AlertDialog.Builder的setXXX系列方法

AlertDialog.Builder初始化完成以後,調用它的builder.setXXX 系列方法完成Dialog的初始化 frameworks/base/core/java/android/app/AlertDialog.java

// ... 省略了不少builder.setXXX方法
public Builder setTitle(@StringRes int titleId) {
    P.mTitle = P.mContext.getText(titleId);
    return this;
}
public Builder setMessage(@StringRes int messageId) {
    P.mMessage = P.mContext.getText(messageId);
    return this;
}
public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
    P.mPositiveButtonText = P.mContext.getText(textId);
    P.mPositiveButtonListener = listener;
    return this;
}
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
    P.mPositiveButtonText = text;
    P.mPositiveButtonListener = listener;
    return this;
}
// ... 省略了不少builder.setXXX方法
複製代碼

上面全部setXXX方法都是給Builder的成員變量P賦值,而且他們的返回值都是Builder類型,所以能夠經過消息璉的方式調用

builder.setTitle().setMessage().setPositiveButton()...
複製代碼

PS: 在Kotlin應該儘可能避免使用構建者模式,使用Kotlin中的具名可選參數,實現構建者模式,代碼更加簡潔,爲了避免影響閱讀的流暢性,將這部份內容放到了文末擴展閱讀部分

3 builder.create方法

builder.setXXX 系列方法以後調用builder.create方法完成AlertDialog構建,接下來看一下create方法 frameworks/base/core/java/android/app/AlertDialog.java

public AlertDialog create() {
    // P.mContext 是ContextWrappedTheme 的實例
    final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
    // Dialog的參數其實保存在P這個類裏面
    // mAler是AlertController的實例,經過這個方法把P中的變量傳給AlertController.AlertParams
    P.apply(dialog.mAlert);
    // 用來控制點擊外部是否可取消,mCancelable 默認爲true
    dialog.setCancelable(P.mCancelable);
    // 若是能夠取消設置回調監聽
    if (P.mCancelable) {
        dialog.setCanceledOnTouchOutside(true);
    }
    // 設置一系列監聽
    dialog.setOnCancelListener(P.mOnCancelListener);
    dialog.setOnDismissListener(P.mOnDismissListener);
    if (P.mOnKeyListener != null) {
        dialog.setOnKeyListener(P.mOnKeyListener);
    }
    // 返回 AlertDialog 對象
    return dialog;
}
複製代碼
  • 根據P.mContex 構建了一個AlertDialog
  • mAler是AlertController的實例,調用apply方法把P中的變量傳給AlertController.AlertParams
  • 設置是否能夠點擊外部取消,默承認以取消,同時設置回調監聽
  • 最後返回AlertDialog對象

3.1 如何構建AlertDialog

咱們來分析一下AlertDialog是如何構建的,來看一下它的造方法具體實現 frameworks/base/core/java/android/app/AlertDialog.java

AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
            createContextThemeWrapper);

    mWindow.alwaysReadCloseOnTouchAttr();
    // getContext() 返回的是ContextWrapperTheme
    // getWindow() 返回的是 PhoneWindow
    // mAlert 是AlertController的實例
    mAlert = AlertController.create(getContext(), this, getWindow());
}
複製代碼

PhoneWindows是何時建立的?AlertDialog繼承自Dialog,首先調用了super的構造方法,來看一下Dialog的構造方法 frameworks/base/core/java/android/app/Dialog.java

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    ...
    
    // 獲取WindowManager對象
    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    // 構建PhoneWindow
    final Window w = new PhoneWindow(mContext);
    // mWindow 是PhoneWindow實例
    mWindow = w;
    w.setCallback(this);
    w.setOnWindowDismissedCallback(this);
    w.setOnWindowSwipeDismissedCallback(() -> {
        if (mCancelable) {
            cancel();
        }
    });
    w.setWindowManager(mWindowManager, null, null);
    w.setGravity(Gravity.CENTER);
    // 繼承 Handler
    mListenersHandler = new ListenersHandler(this);
}
複製代碼
  • 獲取WindowManager對象,構建了PhoneWindow,到這裏咱們知道了PhoneWindow是在Dialog構造方法建立的
  • 初始化了Dialog的成員變量mWindow,mWindow 是PhoneWindow的實例
  • 初始化了Dialog的成員變量mListenersHandler,mListenersHandler繼承Handler

咱們回到AlertDialog構造方法,在AlertDialog構造方法內,調用了 AlertController.create方法,來看一下這個方法

public static final AlertController create(Context context, DialogInterface di, Window window) {
    final TypedArray a = context.obtainStyledAttributes(
            null, R.styleable.AlertDialog, R.attr.alertDialogStyle,
            R.style.Theme_DeviceDefault_Settings);
    int controllerType = a.getInt(R.styleable.AlertDialog_controllerType, 0);
    a.recycle();
    // 根據controllerType 使用不一樣的AlertController
    switch (controllerType) {
        case MICRO:
            // MicroAlertController 是matrix風格 繼承自AlertController
            return new MicroAlertController(context, di, window);
        default:
            return new AlertController(context, di, window);
    }
}
複製代碼

根據controllerType 返回不一樣的AlertController,到這裏分析完了AlertDialog是如何構建的

4 調用Dialog的show方法顯示Dialog

調用AlertDialog.Builder的create方法以後返回了AlertDialog的實例,最後調用了AlertDialog的show方法顯示dialog,可是AlertDialog是繼承自Dialog的,實際上調用的是Dialog的show方法 frameworks/base/core/java/android/app/Dialog.java

public void show() {
    // mShowing變量用於表示當前dialog是否正在顯示
    if (mShowing) {
        if (mDecor != null) {
            if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
            }
            mDecor.setVisibility(View.VISIBLE);
        }
        return;
    }
    
    mCanceled = false;

    // mCreated這個變量控制dispatchOnCreate方法只被執行一次
    if (!mCreated) {
        dispatchOnCreate(null);
    } else {
        // Fill the DecorView in on any configuration changes that
        // may have occured while it was removed from the WindowManager.
        final Configuration config = mContext.getResources().getConfiguration();
        mWindow.getDecorView().dispatchConfigurationChanged(config);
    }

    // 用於設置ActionBar
    onStart();
    // 獲取DecorView
    mDecor = mWindow.getDecorView();

    if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
        final ApplicationInfo info = mContext.getApplicationInfo();
        mWindow.setDefaultIcon(info.icon);
        mWindow.setDefaultLogo(info.logo);
        mActionBar = new WindowDecorActionBar(this);
    }
    // 獲取佈局參數
    WindowManager.LayoutParams l = mWindow.getAttributes();
    boolean restoreSoftInputMode = false;
    if ((l.softInputMode
            & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
        l.softInputMode |=
                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
        restoreSoftInputMode = true;
    }
    // 將DecorView和佈局參數添加到WindowManager中,完成view的繪製
    mWindowManager.addView(mDecor, l);
    if (restoreSoftInputMode) {
        l.softInputMode &=
                ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
    }

    mShowing = true;
    // 向Handler發送一個Dialog的消息,從而顯示AlertDialog
    sendShowMessage();
}
複製代碼
  • 判斷dialog是否已經顯示,若是顯示了直接返回
  • 判斷dispatchOnCreate方法是否已經調用,若是沒有則調用dispatchOnCreate方法
  • 獲取佈局參數添加到WindowManager,調用addView方法完成view的繪製
  • 向Handler發送一個Dialog的消息,從而顯示AlertDialog

4.1 dispatchOnCreate

在上面代碼中,根據mCreated變量,判斷dispatchOnCreate方法是否已經調用,若是沒有則調用dispatchOnCreate方法 frameworks/base/core/java/android/app/Dialog.java

void dispatchOnCreate(Bundle savedInstanceState) {
    if (!mCreated) {
        // 調用 onCreate 方法
        onCreate(savedInstanceState);
        mCreated = true;
    }
}
複製代碼

在dispatchOnCreate方法中主要調用Dialog的onCreate方法, Dialog的onCreate方法是個空方法,因爲咱們建立的是AlertDialog對象,AlertDialog繼承於Dialog,因此調用的是AlertDialog的onCreate方法 frameworks/base/core/java/android/app/AlertDialog.java

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mAlert.installContent();
}
複製代碼

在這方法裏面調用了AlertController的installContent方法,來看一下具體的實現邏輯 frameworks/base/core/java/com/android/internal/app/AlertController.java

public void installContent() {
    // 獲取相應的Dialog佈局文件
    int contentView = selectContentView();
    // 調用setContentView方法解析佈局文件
    mWindow.setContentView(contentView);
    // 初始化佈局文件中的組件
    setupView();
}
複製代碼
  • 調用selectContentView方法獲取佈局文件,來看一下具體的實現 frameworks/base/core/java/com/android/internal/app/AlertController.java
private int selectContentView() {
    if (mButtonPanelSideLayout == 0) {
        return mAlertDialogLayout;
    }
    if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
        return mButtonPanelSideLayout;
    }
    return mAlertDialogLayout;
}
複製代碼

返回的佈局是mAlertDialogLayout,佈局文件是在AlertController的構造方法初始化的 frameworks/base/core/java/com/android/internal/app/AlertController.java

mAlertDialogLayout = a.getResourceId(
                R.styleable.AlertDialog_layout, R.layout.alert_dialog);
複製代碼
  • 調用Window.setContentView方法解析佈局文件,Activity的setContentView最後也是調用了Window.setContentView這個方法,具體的解析流程,能夠參考以前的文章Activity佈局加載流程 0xA03 Android 10 源碼分析:Apk加載流程之資源加載
  • 調用setupView方法初始化佈局文件中的組件, 到這裏dispatchOnCreate方法分析結束

4.2 調用mWindowManager.addView完成View的繪製

回到咱們的Dialog的show方法,在執行了dispatchOnCreate方法以後,又調用了onStart方法,這個方法主要用於設置ActionBar,而後初始化WindowManager.LayoutParams對象,最後調用mWindowManager.addView()方法完成界面的繪製,繪製完成以後調用sendShowMessage方法 frameworks/base/core/java/android/app/Dialog.java

private void sendShowMessage() {
    if (mShowMessage != null) {
        // Obtain a new message so this dialog can be re-used
        Message.obtain(mShowMessage).sendToTarget();
    }
}
複製代碼

向Handler發送一個Dialog的消息,從而顯示AlertDialog,該消息最終會在ListenersHandler中的handleMessage方法中被執行,ListenersHandler是Dialog的內部類,繼承Handler frameworks/base/core/java/android/app/Dialog.java

public void handleMessage(Message msg) {
    switch (msg.what) {
        case DISMISS:
            ((OnDismissListener) msg.obj).onDismiss(mDialog.get());
            break;
        case CANCEL:
            ((OnCancelListener) msg.obj).onCancel(mDialog.get());
            break;
        case SHOW:
            ((OnShowListener) msg.obj).onShow(mDialog.get());
            break;
    }
}
複製代碼

若是msg.what = SHOW,會執行OnShowListener.onShow方法,msg.what的值和OnShowListener調用setOnShowListener方法賦值的 frameworks/base/core/java/android/app/Dialog.java

public void setOnShowListener(@Nullable OnShowListener listener) {
    if (listener != null) {
        mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
    } else {
        mShowMessage = null;
    }
}
複製代碼

mListenersHandler構造了Message對象,當咱們在Dialog中發送showMessage的時候,被mListenersHandler所接收

4.3 自定義Dialog的view的是如何綁定的

在上文分析中根據mCreated變量,判斷dispatchOnCreate方法是否已經調用,若是沒有則調用dispatchOnCreate方法,在dispatchOnCreate方法中主要調用Dialog的onCreate方法,因爲建立的是AlertDialog對象,AlertDialog繼承於Dialog,因此實際調用的是AlertDialog的onCreate方法,來完成佈局文件的解析,和佈局文件中控件的初始化

同理咱們自定義CustomDialog繼承自Dialog,因此調用的是自定義CustomDialog的onCreate方法,代碼以下

public class CustomDialog extends Dialog {
    Context mContext;
    // ... 省略構造方法
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.custom_dialog, null);
        setContentView(view);
    }

}
複製代碼

在onCreate方法中調用了 Dialog的setContentView 方法, 來分析setContentView方法 frameworks/base/core/java/android/app/Dialog.java

public void setContentView(@NonNull View view) {
    mWindow.setContentView(view);
}
複製代碼

mWindow是PhoneWindow的實例,最後調用的是PhoneWindow的setContentView解析佈局文件,Activity的setContentView最後也是調用了PhoneWindow的setContentView方法,具體的解析流程,能夠參考以前的文章Activity佈局加載流程 0xA03 Android 10 源碼分析:Apk加載流程之資源加載

總結

Dialog和Activity的顯示邏輯是類似的都是內部管理這一個Window對象,用WIndow對象實現界面的加載與顯示邏輯

Dialog的的建立流程?

  1. 構建AlertDialog.Builder對象
  2. builder.setXXX 系列方法完成Dialog的初始化
  3. 調用builder.create()方法建立AlertDialog
  4. 調用AlertDialog的show()初始化Dialog的佈局文件,Window對象等,而後執行mWindowManager.addView方法,開始執行繪製View的操做,最終將Dialog顯示出來

Dialog的視圖怎麼與Window作關聯了?

  • 在Dialog的構造方法中初始化了Window對象
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    ...
    // 獲取WindowManager對象
    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    // 構建PhoneWindow
    final Window w = new PhoneWindow(mContext);
    // mWindow 是PhoneWindow實例
    mWindow = w;
   ...
}
複製代碼
  • 調用Dialog的show方法,完成view的繪製和Dialog的顯示
public void show() {
    // 獲取DecorView
    mDecor = mWindow.getDecorView();
    // 獲取佈局參數
    WindowManager.LayoutParams l = mWindow.getAttributes();
    // 將DecorView和佈局參數添加到WindowManager中
    mWindowManager.addView(mDecor, l);
}
複製代碼

最終會經過WindowManager將DecorView添加到Window之中,用WIndow對象實現界面的加載與顯示邏輯

自定義CustomDialog的view的是如何綁定的?

  • 調用Dialog的show方法,在該方法內部會根據mCreated變量,判斷dispatchOnCreate方法是否已經調用,若是沒有則調用dispatchOnCreate方法,在dispatchOnCreate方法中主要調用Dialog的onCreate方法
  • 自定義CustomDialog繼承自Dialog,因此調用的是自定義CustomDialog的onCreate方法,在CustomDialog的onCreate方法中調用setContentView方法,最後調用的是PhoneWindow的setContentView解析佈局文件,解析流程參考0xA03 Android 10 源碼分析:Apk加載流程之資源加載

如何使用Kotlin具名可選參數構造類,實現構建者模式?

這部份內容參考擴展閱讀部分

相比於Java的構建者模式,經過具名可選參數構造類具備如下優勢?

  • 代碼很是的簡潔
  • 每一個參數名均可以顯示的,聲明對象時無須按照順序書寫,很是的靈活
  • 構造函數中每一個參數都是val聲明的,在多線程併發業務場景中更加的安全
  • Kotlin的require方法,讓咱們在參數約束上更加的友好

如何在Dialog中使用DataBinding?

這部份內容參考擴展閱讀部分

擴展閱讀

1. Kotlin實現構建者模式

剛纔在上文中提到了,在Kotlin中應該儘可能避免使用構建者模式,使用Kotlin的具名可選參數構造類,實現構建者模式,代碼更加簡潔

在 "Effective Java" 書中介紹構建者模式時,是這樣子描述它的:本質上builder模式模擬了具名的可算參數,就像Ada和Python中的同樣

關於Java用構建者模式實現自定義dialog,這裏就不展現了,能夠百度、Google搜索一下,代碼顯得很長........幸運的是,Kotlin是一門擁有具名可選參數的變成語言,Kotlin中的函數和構造器都支持這一特性,接下里咱們使用具名可選參數構造類,實現構建者模式,點擊JDataBinding前往查看,核心代碼以下:

class AppDialog(
    context: Context,
    val title: String? = null,
    val message: String? = null,
    val yes: AppDialog.() -> Unit
) : DataBindingDialog(context, R.style.AppDialog) {

    init {
        requireNotNull(message) { "message must be not null" }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestWindowFeature(Window.FEATURE_NO_TITLE)

        setContentView(root)
        display.text = message
        btnNo.setOnClickListener { dismiss() }
        btnYes.setOnClickListener { yes() }
    }
}
複製代碼

調用方式也更加的簡單

AppDialog(
        context = this@MainActivity,
        message = msg,
        yes = {
            // do something
        }).show()
複製代碼

相比於Java的構建者模式,經過具名可選參數構造類具備如下優勢:

  • 代碼很是的簡潔
  • 每一個參數名均可以顯示的,聲明對象時無須按照順序書寫,很是的靈活
  • 構造函數中每一個參數都是val聲明的,在多線程併發業務場景中更加的安全
  • Kotlin的require方法,讓咱們在參數約束上更加的友好

2. 如何在Dialog中使用DataBinding

DataBinding是什麼?查看Google官網,會有更詳細的介紹

DataBinding 是 Google 在 Jetpack 中推出的一款數據綁定的支持庫,利用該庫能夠實如今頁面組件中直接綁定應用程序的數據源

在使用Kotlin的具名可選參數構造類實現Dailog構建者模式的基礎上,用DataBinding進行二次封裝,加上DataBinding數據綁定的特性,使Dialog變得更加簡潔、易用

Step1: 定義一個基類DataBindingDialog

abstract class DataBindingDialog(@NonNull context: Context, @StyleRes themeResId: Int) :
    Dialog(context, themeResId) {

    protected inline fun <reified T : ViewDataBinding> binding(@LayoutRes resId: Int): Lazy<T> =
        lazy {
            requireNotNull(
                DataBindingUtil.bind<T>(LayoutInflater.from(context).inflate(resId, null))
            ) { "cannot find the matched view to layout." }
        }

}
複製代碼

Step2: 改造AppDialog

class AppDialog(
    context: Context,
    val title: String? = null,
    val message: String? = null,
    val yes: AppDialog.() -> Unit
) : DataBindingDialog(context, R.style.AppDialog) {
    private val mBinding: DialogAppBinding by binding(R.layout.dialog_app)

    init {
        requireNotNull(message) { "message must be not null" }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestWindowFeature(Window.FEATURE_NO_TITLE)

        mBinding.apply {
            setContentView(root)
            display.text = message
            btnNo.setOnClickListener { dismiss() }
            btnYes.setOnClickListener { yes() }
        }

    }
}
複製代碼

同理DataBinding在Activity、Fragment、Adapter中的使用也是同樣的,利用Kotlin的inline、reified、DSL等等語法,能夠設計出更加簡潔並利於維護的代碼

關於基於DataBinding封裝的DataBindingActivity、DataBindingFragment、DataBindingDialog基礎庫相關代碼,後續也會陸續完善基礎庫,點擊JDataBinding前往查看,歡迎start

結語

致力於分享一系列Android系統源碼、逆向分析、算法相關的文章,每篇文章都會反覆推敲,結合新的技術,帶來一些新的思考,寫出更通俗易懂的文章,若是你同我同樣喜歡coding,一塊兒來學習,期待與你一塊兒成長

系列文章

Android 10 源碼系列

工具系列

逆向系列

相關文章
相關標籤/搜索