设计模式:Builder模式

in 网站建设
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

博客主页

介绍:该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。

定义:将一个复杂的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

使用场景:

  1. 相同的方法,不同的执行顺序,产生不同的事件结果时。
  2. 多个部件或者零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
  3. 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候使用建造者模式非常合适。
  4. 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值。

UML类图

Product产品类,产品的抽象类
Builder抽象Builder类,规范产品的组建,一般是由子类实现具体的组建过程。
ConcreteBuilder具体的Builder类。
Director统一组装过程

Builder模式的简单实现

计算机抽象类,即Product角色

// 计算机抽象类,即Product角色
public abstract class Computer {
    protected String board; // 主板
    protected String display; // 显示器
    protected  String os; // 操作系统

    public void setBoard(String board) {
        this.board = board;
    }

    public void setDisplay(String display) {
        this.display = display;
    }

    public abstract void setOs();

    @Override
    public String toString() {
        return "Computer{" +
                "board='" + board + '\'' +
                ", display='" + display + '\'' +
                ", os='" + os + '\'' +
                '}';
    }
}

具体的Computer类,Macbook

// 具体的Computer类,Macbook
public class Macbook extends Computer {
    @Override
    public void setOs() {
        os = "Mac os X 10.10";
    }
}

抽象Builder类

// 抽象Builder类
public abstract class Builder {
    // 设置主板
    public abstract void buildBoard(String board);
    // 设置显示器
    public abstract void buildDisplay(String display);
    // 设置操作系统
    public abstract void buildOS();
    // 创建Computer
    public abstract Computer create();
}

具体的Builder类,MacbookBuilder

// 具体的Builder类,MacbookBuilder
public class MacbookBuilder extends Builder {
    private Computer computer = new Macbook();

    @Override
    public void buildBoard(String board) {
        computer.setBoard(board);
    }

    @Override
    public void buildDisplay(String display) {
        computer.setDisplay(display);
    }

    @Override
    public void buildOS() {
        computer.setOs();
    }

    @Override
    public Computer create() {
        return computer;
    }
}

Director类,负责构造Computer

// Director类,负责构造Computer
public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public void construct(String board, String display) {
        builder.buildBoard(board);
        builder.buildDisplay(display);
        builder.buildOS();
    }
}

测试代码

public class Test {
    public static void main(String[] args) {
        Builder builder = new MacbookBuilder();
        Director director = new Director(builder);

        director.construct("英特尔主板", "Retina显示器");

        System.out.println("Computer info: " + builder.create().toString());
    }
}
// Computer info: Computer{board='英特尔主板', display='Retina显示器', os='Mac os X 10.10'}

Director封装了构建复杂产品对象的过程,对外隐藏构建细节。但是在实际开发中,Director会被省略。直接使用一个Builder来进行对象的组装,这个Builder为链式调用,每个setter方法都返回自身,也就是return this。

Android源码中的Builder模式实现

在Android源码中,最常用到的Builder模式就是AlertDialog.Builder,使用该Builder来构建复杂的AlertDialog对象。

AlertDialog对话框的基本使用:

private void showDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setIcon(R.mipmap.ic_launcher);
    builder.setTitle("标题");
    builder.setMessage("正文内容");
    builder.setPositiveButton("Positive", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
    });
    builder.setNegativeButton("Negative", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
    });

    builder.setNeutralButton("Neutral", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
    });
    // 显示对话框
    builder.create().show();
}

接下来看看AlertDialog系统源码

public class AlertDialog extends AppCompatDialog implements DialogInterface {
    // AlertController 接收Builder成员变量 P 中的各个参数
    final AlertController mAlert;

    // 构造函数
    protected AlertDialog(@NonNull Context context) {
        this(context, 0);
    }
    
    // 构造AlertDialog
    protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
        super(context, resolveDialogTheme(context, themeResId));
        // 构造AlertController
        mAlert = new AlertController(getContext(), this, getWindow());
    }
    
    // 实际上调用的是mAlert的setTitle方法
    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
        mAlert.setTitle(title);
    }

    // 实际上调用的是mAlert的setCustomTitle方法
    public void setCustomTitle(View customTitleView) {
        mAlert.setCustomTitle(customTitleView);
    }

    public void setMessage(CharSequence message) {
        mAlert.setMessage(message);
    }
    
    // 省略...

    //************* Builder为AlertDialog的内部类 ******************
    public static class Builder {
        // 1. 存储AlertDialog的各个参数,如:title、message、icon等
        private final AlertController.AlertParams P;

        public Builder(@NonNull Context context) {
            this(context, resolveDialogTheme(context, 0));
        }

        // 2. 设置各个参数
        public Builder setTitle(@Nullable CharSequence title) {
            P.mTitle = title;
            return this;
        }

        public Builder setMessage(@Nullable CharSequence message) {
            P.mMessage = message;
            return this;
        }

        // 3. 构建AlertDialog,传递参数
        public AlertDialog create() {
            // 4. 调用new AlertDialog构造对象,并且将参数传递给AlertDialog
            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
            // 5. 将P中的参数应用到dialog中的mAlert对象中
            P.apply(dialog.mAlert);
            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);
            }
            return dialog;
        }

        public AlertDialog show() {
            final AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }
   }
}

在调用Builder类的create函数时会创建AlertDialog,并将Builder成员变量P中保存的参数应用到AlertDialog的mAlert对象中,即 P.apply(dialog.mAlert)

public void apply(AlertController dialog) {
    if (mCustomTitleView != null) {
        dialog.setCustomTitle(mCustomTitleView);
    } else {
        if (mTitle != null) {
            dialog.setTitle(mTitle);
        }
        if (mIcon != null) {
            dialog.setIcon(mIcon);
        }
        if (mIconId != 0) {
            dialog.setIcon(mIconId);
        }
        if (mIconAttrId != 0) {
            dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
        }
    }
    if (mMessage != null) {
        dialog.setMessage(mMessage);
    }
    if (mPositiveButtonText != null || mPositiveButtonIcon != null) {
        dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
                mPositiveButtonListener, null, mPositiveButtonIcon);
    }
    if (mNegativeButtonText != null || mNegativeButtonIcon != null) {
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
                mNegativeButtonListener, null, mNegativeButtonIcon);
    }
    if (mNeutralButtonText != null || mNeutralButtonIcon != null) {
        dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
                mNeutralButtonListener, null, mNeutralButtonIcon);
    }
     
    // 如果设置了mItems,则表示是单选或者多选列表,此时创建一个ListView
    if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
        createListView(dialog);
    }
    // 将mView设置给Dialog
    if (mView != null) {
        if (mViewSpacingSpecified) {
            dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
                    mViewSpacingBottom);
        } else {
            dialog.setView(mView);
        }
    } else if (mViewLayoutResId != 0) {
        dialog.setView(mViewLayoutResId);
    }
}

当获取到AlertDialog对象后,通过show函数就可以显示对话框。在看看Dialog的show函数:

// Dialog.java

public void show() {
    // 已经是显示状态,则return
    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;

    // 1. onCreate 调用
    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);
    }
    
    // 2. onStart 调用
    onStart();
    // 3. 获取DecorView
    mDecor = mWindow.getDecorView();
    // ...
    // 4. 获取布局参数
    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;
    }

    // 5. 将mDecor添加到WindowManager中
    mWindowManager.addView(mDecor, l);
    mShowing = true;
    // 发送一个显示Dialog的消息
    sendShowMessage();
}

在show函数主要做了以下事情:

  1. 通过dispatchOnCreate函数来调用AlertDialog的onCreate函数
  2. 然后调用AlertDialog的onStart函数
  3. 最后将Dialog的DecorView添加到WindowManager中

一般AlertDialog的内容视图构建应该在onCreate函数中,我们看看是不是:

// AlertDialog.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 调用了AlertController的installContent方法
    mAlert.installContent();
}

在onCreate函数中主要调用了AlertController的installContent方法,Dialog中的onCreate函数只是一个空实现,视图的安装就在installContent函数中:

public void installContent() {
    final int contentView = selectContentView();
    // 设置窗口的内容视图布局
    mDialog.setContentView(contentView);
    // 初始化AlertDialog其他子视图的内容
    setupView();
}

installContent函数中调用了Window对象的setContentView,这个setContentView与Activity中的一摸一样。而这个布局就是mAlertDialogLayout,这个值在AlertController的构造函数中进行初始化。

public AlertController(Context context, AppCompatDialog di, Window window) {
    final TypedArray a = context.obtainStyledAttributes(null, R.styleable.AlertDialog,
            R.attr.alertDialogStyle, 0);
    // AlertDialog的布局id
    mAlertDialogLayout = a.getResourceId(R.styleable.AlertDialog_android_layout, 0);
     //....
    a.recycle();
}

AlertDialog也可以通过setView传入内容视图,AlertDialog预留了一个customPanel区域用来显示用户自定义的内容视图。来看下setupView函数:

private void setupView() {
    final View parentPanel = mWindow.findViewById(R.id.parentPanel);
    final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
    final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
    final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
    
    // 自定义内容区域
    final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
    // 如果设置了内容区域,那么将它显示在customPanel的custom布局里面
    setupCustomContent(customPanel);

    final View customTopPanel = customPanel.findViewById(R.id.topPanel);
    final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
    final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);

    // Resolve the correct panels and remove the defaults, if needed.
    final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
    final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
    final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
    // 设置内容区域
    setupContent(contentPanel);
    // 设置按钮区域
    setupButtons(buttonPanel);
    // 设置标题区域
    setupTitle(topPanel);

    final boolean hasCustomPanel = customPanel != null
            && customPanel.getVisibility() != View.GONE;
    final boolean hasTopPanel = topPanel != null
            && topPanel.getVisibility() != View.GONE;
    final boolean hasButtonPanel = buttonPanel != null
            && buttonPanel.getVisibility() != View.GONE;

    // Only display the text spacer if we don't have buttons.
    if (!hasButtonPanel) {
        if (contentPanel != null) {
            final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
            if (spacer != null) {
                spacer.setVisibility(View.VISIBLE);
            }
        }
    }

    if (hasTopPanel) {
        // Only clip scrolling content to padding if we have a title.
        if (mScrollView != null) {
            mScrollView.setClipToPadding(true);
        }

        // Only show the divider if we have a title.
        View divider = null;
        if (mMessage != null || mListView != null) {
            divider = topPanel.findViewById(R.id.titleDividerNoCustom);
        }

        if (divider != null) {
            divider.setVisibility(View.VISIBLE);
        }
    } else {
        if (contentPanel != null) {
            final View spacer = contentPanel.findViewById(R.id.textSpacerNoTitle);
            if (spacer != null) {
                spacer.setVisibility(View.VISIBLE);
            }
        }
    }

    if (mListView instanceof RecycleListView) {
        ((RecycleListView) mListView).setHasDecor(hasTopPanel, hasButtonPanel);
    }

    // Update scroll indicators as needed.
    if (!hasCustomPanel) {
        final View content = mListView != null ? mListView : mScrollView;
        if (content != null) {
            final int indicators = (hasTopPanel ? ViewCompat.SCROLL_INDICATOR_TOP : 0)
                    | (hasButtonPanel ? ViewCompat.SCROLL_INDICATOR_BOTTOM : 0);
            setScrollIndicators(contentPanel, content, indicators,
                    ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_BOTTOM);
        }
    }

    final ListView listView = mListView;
    if (listView != null && mAdapter != null) {
        listView.setAdapter(mAdapter);
        final int checkedItem = mCheckedItem;
        if (checkedItem > -1) {
            listView.setItemChecked(checkedItem, true);
            listView.setSelection(checkedItem);
        }
    }
}

深入了解WindowManager

经过 Dialog 的源码分析,已经知道 Dialog 的内容视图最终是通过 WindowManager 显示到手机屏幕上的。其实不仅是 Dialog ,所有需要显示到屏幕上的内容(包括 Activity)都是通过 WindowManager 操作的,它是一个非常重要的子系统,也就是WMS(WindowManagerService)。

获取 WindowManager 通过Context的getSystemService方法。各种系统服务会注册到SystemServiceRegistry中的一个map容器中,然后通过该服务的字符串来获取,WindowManager也是其中一个服务。

registerService(Context.WINDOW_SERVICE, WindowManager.class,
            new CachedServiceFetcher<WindowManager>() {
    @Override
    public WindowManager createService(ContextImpl ctx) {
        return new WindowManagerImpl(ctx);
    }});

从这段代码最后一行可知,WindowManager 在Java层的具体实现类是WindowManagerImpl。接下来看看Dialog是怎么获取WindowManagerImpl的:

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
 
    // 1. 获取WindowManager
    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

    final Window w = new PhoneWindow(mContext); 
    mWindow = w;
    // 2. 设置Window的回调
    w.setCallback(this);
    // 3. 设置Window的WindowManager对象
    w.setWindowManager(mWindowManager, null, null);
}

通过Window对象的setWindowManager函数将Window对象与WindowManager建立了联系。

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
                             boolean hardwareAccelerated) {
    if (wm == null) {
        wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    }
    // 调用了createLocalWindowManager函数
    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}

调用的是WindowManagerImpl中的createLocalWindowManager函数

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    return new WindowManagerImpl(mContext, parentWindow);
}

这个方法很简单,创建一个WindowManagerImpl对象,与SystemServiceRegistry中注册的WindowManagerImpl不同的是,多了一个parentWindow参数。说明这个WindowManagerImpl对象是与具体的Window关联的。

接下俩看看WindowManagerImpl核心代码:

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Context mContext;
    // Window对象
    private final Window mParentWindow;

    public WindowManagerImpl(Context context) {
        this(context, null);
    }

    private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        mParentWindow = parentWindow;
    }

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        mGlobal.updateViewLayout(view, params);
    }

    @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }
    // ...
}

WindowManagerImpl只是一个代理类,真实实现的是WindowManagerGlobal类。调用addView方法将View显示到屏幕上,来分析下WindowManagerGlobal中的addView实现

// WindowManagerGlobal.java

// 将View添加到WindowManager中
public void addView(View view, ViewGroup.LayoutParams params,
                    Display display, Window parentWindow) {
    // ...
    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        // 1.构建ViewRootImpl
        root = new ViewRootImpl(view.getContext(), display);
        // 2.给View设置布局参数
        view.setLayoutParams(wparams);
        // 3.将View添加到View列表中
        mViews.add(view);
        // 4.将ViewRootImpl对象root添加到mRoots列表中
        mRoots.add(root);
        mParams.add(wparams);

        // do this last because it fires off messages to start doing things
        try {
            // 5. 调用ViewRootImpl的setView方法将View显示到手机窗口中
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
        }
    }
}

上面分析到的ViewRootImpl,很多人已经非常熟悉了。它作为native层与java层View系统通信的桥梁,如熟知的 performTraversals 函数就是收到系统绘制View的消息后,通过调用视图树的各个节点的performMeasure、performLayout、performDraw方法来绘制整课视图树。

来看下ViewRootImpl的构造函数

public ViewRootImpl(Context context, Display display) {
        mContext = context;
        // 1.获取Window Session,也就是与WindowManagerService建立连接
        mWindowSession = WindowManagerGlobal.getWindowSession();
        // ...
        // 保存当前线程,更新UI的线程只能是创建ViewRootImpl时的线程
        // 我们在应用开发中,如果在子线程中更新UI会抛出异常,但并不是因为只有UI线程才能更新UI
        // 而是因为ViewRootImpl是在UI线程中创建的
        mThread = Thread.currentThread()
}

其中WindowManagerGlobal.getWindowSession()就是与Native层建立通信的地方。

public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                // 1.获取WindowManagerService
                IWindowManager windowManager = getWindowManagerService();
                // 2.与WindowManagerService建立一个Session
                sWindowSession = windowManager.openSession(
                        new IWindowSessionCallback.Stub() {
                            @Override
                            public void onAnimatorScaleChanged(float scale) {
                                ValueAnimator.setDurationScale(scale);
                            }
                        });
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return sWindowSession;
    }
}

// 获取WindowManagerService
public static IWindowManager getWindowManagerService() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowManagerService == null) {
            sWindowManagerService = IWindowManager.Stub.asInterface(
                    ServiceManager.getService("window"));
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return sWindowManagerService;
    }
}

在getWindowSession函数中,Fragework层先通过getWindowManagerService函数获取到IWindowManager对象,在函数中通过ServiceManager.getService函数获取WMS,并将WMS转为IWindowManager类型。来看下ServiceManager.getService函数代码:

// ServiceManager.java

public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return Binder.allowBlocking(rawGetService(name));
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

该函数返回的是IBinder对象,说明Android Fragework与WMS之间通过Binder机制进行通信的。

此时Dialog或者Activity的View并不能显示在手机屏幕上,WMS 只是负责管理手机屏幕上View的z-order,也就是说 WMS 管理当前状态下哪个View应该在最上层显示。MWS 管理的并不是 Window,而是View,只不过它管理的是属于某个Window下的View。

与WMS 建立Session后就调用ViewRootImpl的setView方法,该方法会向 WMS 发起显示Dialog或者Activity中的DecorView请求

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        // 1.请求布局
        requestLayout();
        try {
              // 2.向 WMS 发送请求
              res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                       getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                       mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                       mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,mTempInsets);
        }
    }
}

在来看看requestLayout函数

public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals(); // 发送执行doTraversal函数
    }
}

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        // 执行performTraversals函数
        performTraversals();
    }
}

执行performTraversals函数,触发整个视图树的绘制操作。

private void performTraversals() {
   // 1. 获取Surface对象,用于图形绘制
   // 2. 测量整个视图树的各个View的大小,performMeasure函数
   // 3. 布局整个视图树,performLayout函数
   // 4. 绘制整棵视图树,performDraw函数
}

在performDraw中,Framework会获取到图形绘制表面Surface对象,然后获取它的可绘制区域,也就是Canvas对象,然后Framework在这个Canvas对象上绘制。

private void performDraw() {
    // ...
    try {
        // 调用绘制函数
        boolean canUseAsync = draw(fullRedrawNeeded);
    }
    // ...
}

private boolean draw(boolean fullRedrawNeeded) {
    // 1. 获取绘制表面
    Surface surface = mSurface;
    // 2. 绘制表面需要更新
    if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
        // 3. 使用GPU绘制,也就是硬件加速
        if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
            // 使用硬件渲染器绘制
            mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
        } else {
           // 4. 使用CPU绘制图形
           if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
                  scalingRequired, dirty, surfaceInsets)) {
               return false;
           }
        }
    }
}

来看下CPU绘制的代码

// 使用CPU绘制图形
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
                             boolean scalingRequired, Rect dirty, Rect surfaceInsets) {

    // Draw with software renderer.
    final Canvas canvas;

    try {
        dirty.offset(-dirtyXOffset, -dirtyYOffset);
        final int left = dirty.left;
        final int top = dirty.top;
        final int right = dirty.right;
        final int bottom = dirty.bottom;
        // 1. 获取知道区域的Canvas对象,用于Framework层绘制
        canvas = mSurface.lockCanvas(dirty);
    }

    try {
        // 2. 从DecorView开始绘制,也就是整个Window的根视图,这会引起整棵树的重绘
        mView.draw(canvas);
    } finally {
        try {
            // 3. 释放Canvas锁,然后通知SurfaceFlinger更新这块区域
            surface.unlockCanvasAndPost(canvas);
        }
    }
    return true;
}

如果我的文章对您有帮助,不妨点个赞鼓励一下(^_^)

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看