专栏首页曾大稳的博客Android setContentView()源码流程分析

Android setContentView()源码流程分析

我们在Activity创建的时候,都用调用setContentView()函数来设置界面,下面我们通过源码来分析setContentView()的流程。 我们先看Activity里面的setContentView进去查看:

/**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     *
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

函数如下: 我们再次点击setContentView进去查看发现是一个Window的抽象方法,所以我们要找到对应的实现类,我们点击getWindow()进去查看最终得到:

mWindow = new PhoneWindow(this, window);

我们得到了他的实现类PhoneWindow,然后在PhoneWindow找到setContentView函数:

@Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

    @Override
    public void setContentView(View view) {
        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            view.setLayoutParams(params);
            final Scene newScene = new Scene(mContentParent, view);
            transitionTo(newScene);
        } else {
            mContentParent.addView(view, params);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

可以发现都是把这个View加到了mContentParent这个ViewGroup里面去了,这个mContentParent是什么呢?我们急着看源码,发现在installDecor()方法里面:

mContentParent = generateLayout(mDecor);

继续点进去:

protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.

        TypedArray a = getWindowStyle();

        if (false) {
            System.out.println("From style:");
            String s = "Attrs:";
            for (int i = 0; i < R.styleable.Window.length; i++) {
                s = s + " " + Integer.toHexString(R.styleable.Window[i
![无标题.png](http://upload-images.jianshu.io/upload_images/4658633-9a3a758cbac9f8aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
]) + "="
                        + a.getString(i);
            }
            System.out.println(s);
        }

        //根据style属性做一些列的判断...

      //在做一些列的判断得到layoutResource
        layoutResource=.... //这里用R.layout.screen_simple来分析
       
        mDecor.startChanging();

        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        mContentRoot = (ViewGroup) in;

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
  
       //......

        mDecor.finishChanging();

        return contentParent;
    }

从这段代码可以知道,通过一系列的判断,得到相对于的layoutResource,然后通过mLayoutInflater.inflate(layoutResource, null);得到这个View,将其加入到mDecor,其中mContentParent最终为一个ID_ANDROID_CONTENT = com.android.internal.R.id.content的一个ViewGroup,在这里我们拿R.layout.screen_simple布局来看看

<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/assets/res/layout/screen_simple.xml
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License"); 
** you may not use this file except in compliance with the License. 
** You may obtain a copy of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** Unless required by applicable law or agreed to in writing, software 
** distributed under the License is distributed on an "AS IS" BASIS, 
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
** See the License for the specific language governing permissions and 
** limitations under the License.
*/

This is an optimized layout for a screen, with the minimum set of features
enabled.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
         android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:foregroundInsidePadding="false"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

可以知道这个mContentParent为一个FrameLayout,这时候我们应该知道,我们setContentView其实就是把那个View加入到一个idcom.android.internal.R.id.contentFrameLayout里面,而这个idcom.android.internal.R.id.contentFrameLayoutparentView又是加在mDecor里面,我们来看看这个mDecor是什么,在installDecor()函数中:

if (mDecor == null) {
      mDecor = generateDecor();
      mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
      mDecor.setIsRootNamespace(true);
      if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
          mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
      }
  }
protected DecorView generateDecor() {
       return new DecorView(getContext(), -1);
   }

可以发现这个mDecor就是一个new的一个DecorView,我们继续看:

private final class DecorView extends FrameLayout

这个DecorView其实也是一个FrameLayout,这个时候我们就可以得到这样一张图:

在这基础上我们看AppCompatActivitysetContentView函数:

  @Override
  public void setContentView(@LayoutRes int layoutResID) {
      getDelegate().setContentView(layoutResID);
  }


  /**
   * @return The {@link AppCompatDelegate} being used by this Activity.
   */
  @NonNull
  public AppCompatDelegate getDelegate() {
      if (mDelegate == null) {
          mDelegate = AppCompatDelegate.create(this, this);
      }
      return mDelegate;
  }

/**
   * Create a {@link android.support.v7.app.AppCompatDelegate} to use with {@code activity}.
   *
   * @param callback An optional callback for AppCompat specific events
   */
  public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
      return create(activity, activity.getWindow(), callback);
  }
 private static AppCompatDelegate create(Context context, Window window,
          AppCompatCallback callback) {
      final int sdk = Build.VERSION.SDK_INT;
      if (sdk >= 23) {
          return new AppCompatDelegateImplV23(context, window, callback);
      } else if (sdk >= 14) {
          return new AppCompatDelegateImplV14(context, window, callback);
      } else if (sdk >= 11) {
          return new AppCompatDelegateImplV11(context, window, callback);
      } else {
          return new AppCompatDelegateImplV7(context, window, callback);
      }
  }

可以看到最终进入到了AppCompatDelegatecreate方法,这个函数通过new 23 14 11 7就可以看出是为了兼容不同的版本,我们点进去就可以看到AppCompatDelegateImplV23–>AppCompatDelegateImplV14–>AppCompatDelegateImplV11–>AppCompatDelegateImplV7依次继承的,我们最终查看到AppCompatDelegateImplV7setContentView函数:

@Override
    public void setContentView(View v) {
        ensureSubDecor();
        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        contentParent.addView(v);
        mOriginalWindowCallback.onContentChanged();
    }

    @Override
    public void setContentView(int resId) {
        ensureSubDecor();
        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        LayoutInflater.from(mContext).inflate(resId, contentParent);
        mOriginalWindowCallback.onContentChanged();
    }

    @Override
    public void setContentView(View v, ViewGroup.LayoutParams lp) {
        ensureSubDecor();
        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        contentParent.addView(v, lp);
        mOriginalWindowCallback.onContentChanged();
    }

其实也就是把得到的view添加到contentParent里面。 比如说,在android21以前一般是使用控件TextView等控件,在21以后出了相关的AppCompat控件,这个时候怎么让开发者写的TextView自动转换为AppCompatTextView呢?所以在AppCompatDelegateImplV7重写了这样一个函数函数:

@Override
   public void installViewFactory() {
       LayoutInflater layoutInflater = LayoutInflater.from(mContext);
       if (layoutInflater.getFactory() == null) {
           LayoutInflaterCompat.setFactory(layoutInflater, this);
       } else {
           if (!(LayoutInflaterCompat.getFactory(layoutInflater)
                   instanceof AppCompatDelegateImplV7)) {
               Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed"
                       + " so we can not install AppCompat's");
           }
       }
   }

我们查找abstract类,可以查看着方法注释:

/**
     * Installs AppCompat's {@link android.view.LayoutInflater} Factory so that it can replace
     * the framework widgets with compatible tinted versions. This should be called before
     * {@code super.onCreate()} as so:
     * <pre class="prettyprint">
     * protected void onCreate(Bundle savedInstanceState) {
     *     getDelegate().installViewFactory();
     *     getDelegate().onCreate(savedInstanceState);
     *     super.onCreate(savedInstanceState);
     *
     *     // ...
     * }
     * </pre>
     * If you are using your own {@link android.view.LayoutInflater.Factory Factory} or
     * {@link android.view.LayoutInflater.Factory2 Factory2} then you can omit this call, and instead call
     * {@link #createView(android.view.View, String, android.content.Context, android.util.AttributeSet)}
     * from your factory to return any compatible widgets.
     */
    public abstract void installViewFactory();

从意思可以看出,就是说我们可以通过这个方法然后给LayoutInflater设置一个Factory,这个Factory是干嘛的呢?从我的上篇文章就知道,这个Factory是在LayoutInflater执行inflate函数生成View的时候用的,这个Factory可以拦截View的生成,通过这个Factory我们可以自己给inflate写一套解析layout.xml的规则,在换肤的时候就可以用到这个。我们实现LayoutInflaterFactory接口,重写onCreateView方法,就可以拦截相应的信息进行解析。比如在AppCompatDelegateImplV7类中:

 /**
     * From {@link android.support.v4.view.LayoutInflaterFactory}
     */
    @Override
    public final View onCreateView(View parent, String name,
            Context context, AttributeSet attrs) {
        // First let the Activity's Factory try and inflate the view
        final View view = callActivityOnCreateView(parent, name, context, attrs);
        if (view != null) {
            return view;
        }

        // If the Factory didn't handle it, let our createView() method try
        return createView(parent, name, context, attrs);
    }


      View callActivityOnCreateView(View parent, String name, Context context, AttributeSet attrs) {
        // Let the Activity's LayoutInflater.Factory try and handle it
        if (mOriginalWindowCallback instanceof LayoutInflater.Factory) {
            final View result = ((LayoutInflater.Factory) mOriginalWindowCallback)
                    .onCreateView(name, context, attrs);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

@Override
    public View createView(View parent, final String name, @NonNull Context context,
            @NonNull AttributeSet attrs) {
        final boolean isPre21 = Build.VERSION.SDK_INT < 21;

        if (mAppCompatViewInflater == null) {
            mAppCompatViewInflater = new AppCompatViewInflater();
        }

        // We only want the View to inherit its context if we're running pre-v21
        final boolean inheritContext = isPre21 && shouldInheritContext((ViewParent) parent);

        return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext,
                isPre21, /* Only read android:theme pre-L (L+ handles this anyway) */
                true /* Read read app:theme as a fallback at all times for legacy reasons */
        );
    }

它拦截下了layoutt.xml的解析,自己写了一个解析类AppCompatViewInflater,来解析View

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.support.v7.app;

import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.TypedArray;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.ArrayMap;
import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
import android.support.v7.view.ContextThemeWrapper;
import android.support.v7.widget.AppCompatAutoCompleteTextView;
import android.support.v7.widget.AppCompatButton;
import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.AppCompatCheckedTextView;
import android.support.v7.widget.AppCompatEditText;
import android.support.v7.widget.AppCompatImageButton;
import android.support.v7.widget.AppCompatImageView;
import android.support.v7.widget.AppCompatMultiAutoCompleteTextView;
import android.support.v7.widget.AppCompatRadioButton;
import android.support.v7.widget.AppCompatRatingBar;
import android.support.v7.widget.AppCompatSeekBar;
import android.support.v7.widget.AppCompatSpinner;
import android.support.v7.widget.AppCompatTextView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InflateException;
import android.view.View;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * This class is responsible for manually inflating our tinted widgets which are used on devices
 * running {@link android.os.Build.VERSION_CODES#KITKAT KITKAT} or below. As such, this class
 * should only be used when running on those devices.
 * <p>This class two main responsibilities: the first is to 'inject' our tinted views in place of
 * the framework versions in layout inflation; the second is backport the {@code android:theme}
 * functionality for any inflated widgets. This include theme inheritance from it's parent.
 */
class AppCompatViewInflater {

    private static final Class<?>[] sConstructorSignature = new Class[]{
            Context.class, AttributeSet.class};
    private static final int[] sOnClickAttrs = new int[]{android.R.attr.onClick};

    private static final String[] sClassPrefixList = {
            "android.widget.",
            "android.view.",
            "android.webkit."
    };

    private static final String LOG_TAG = "AppCompatViewInflater";

    private static final Map<String, Constructor<? extends View>> sConstructorMap
            = new ArrayMap<>();

    private final Object[] mConstructorArgs = new Object[2];

    public final View createView(View parent, final String name, @NonNull Context context,
            @NonNull AttributeSet attrs, boolean inheritContext,
            boolean readAndroidTheme, boolean readAppTheme) {
        final Context originalContext = context;

        // We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
        // by using the parent's context
        if (inheritContext && parent != null) {
            context = parent.getContext();
        }
        if (readAndroidTheme || readAppTheme) {
            // We then apply the theme on the context, if specified
            context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
        }

        View view = null;

        // We need to 'inject' our tint aware Views in place of the standard framework versions
        switch (name) {
            case "TextView":
                view = new AppCompatTextView(context, attrs);
                break;
            case "ImageView":
                view = new AppCompatImageView(context, attrs);
                break;
            case "Button":
                view = new AppCompatButton(context, attrs);
                break;
            case "EditText":
                view = new AppCompatEditText(context, attrs);
                break;
            case "Spinner":
                view = new AppCompatSpinner(context, attrs);
                break;
            case "ImageButton":
                view = new AppCompatImageButton(context, attrs);
                break;
            case "CheckBox":
                view = new AppCompatCheckBox(context, attrs);
                break;
            case "RadioButton":
                view = new AppCompatRadioButton(context, attrs);
                break;
            case "CheckedTextView":
                view = new AppCompatCheckedTextView(context, attrs);
                break;
            case "AutoCompleteTextView":
                view = new AppCompatAutoCompleteTextView(context, attrs);
                break;
            case "MultiAutoCompleteTextView":
                view = new AppCompatMultiAutoCompleteTextView(context, attrs);
                break;
            case "RatingBar":
                view = new AppCompatRatingBar(context, attrs);
                break;
            case "SeekBar":
                view = new AppCompatSeekBar(context, attrs);
                break;
        }

        if (view == null && originalContext != context) {
            // If the original context does not equal our themed context, then we need to manually
            // inflate it using the name so that android:theme takes effect.
            view = createViewFromTag(context, name, attrs);
        }

        if (view != null) {
            // If we have created a view, check it's android:onClick
            checkOnClickListener(view, attrs);
        }

        return view;
    }

    private View createViewFromTag(Context context, String name, AttributeSet attrs) {
        if (name.equals("view")) {
            name = attrs.getAttributeValue(null, "class");
        }

        try {
            mConstructorArgs[0] = context;
            mConstructorArgs[1] = attrs;

            if (-1 == name.indexOf('.')) {
                for (int i = 0; i < sClassPrefixList.length; i++) {
                    final View view = createView(context, name, sClassPrefixList[i]);
                    if (view != null) {
                        return view;
                    }
                }
                return null;
            } else {
                return createView(context, name, null);
            }
        } catch (Exception e) {
            // We do not want to catch these, lets return null and let the actual LayoutInflater
            // try
            return null;
        } finally {
            // Don't retain references on context.
            mConstructorArgs[0] = null;
            mConstructorArgs[1] = null;
        }
    }

    /**
     * android:onClick doesn't handle views with a ContextWrapper context. This method
     * backports new framework functionality to traverse the Context wrappers to find a
     * suitable target.
     */
    private void checkOnClickListener(View view, AttributeSet attrs) {
        final Context context = view.getContext();

        if (!(context instanceof ContextWrapper) ||
                (Build.VERSION.SDK_INT >= 15 && !ViewCompat.hasOnClickListeners(view))) {
            // Skip our compat functionality if: the Context isn't a ContextWrapper, or
            // the view doesn't have an OnClickListener (we can only rely on this on API 15+ so
            // always use our compat code on older devices)
            return;
        }

        final TypedArray a = context.obtainStyledAttributes(attrs, sOnClickAttrs);
        final String handlerName = a.getString(0);
        if (handlerName != null) {
            view.setOnClickListener(new DeclaredOnClickListener(view, handlerName));
        }
        a.recycle();
    }

    private View createView(Context context, String name, String prefix)
            throws ClassNotFoundException, InflateException {
        Constructor<? extends View> constructor = sConstructorMap.get(name);

        try {
            if (constructor == null) {
                // Class not found in the cache, see if it's real, and try to add it
                Class<? extends View> clazz = context.getClassLoader().loadClass(
                        prefix != null ? (prefix + name) : name).asSubclass(View.class);

                constructor = clazz.getConstructor(sConstructorSignature);
                sConstructorMap.put(name, constructor);
            }
            constructor.setAccessible(true);
            return constructor.newInstance(mConstructorArgs);
        } catch (Exception e) {
            // We do not want to catch these, lets return null and let the actual LayoutInflater
            // try
            return null;
        }
    }

    /**
     * Allows us to emulate the {@code android:theme} attribute for devices before L.
     */
    private static Context themifyContext(Context context, AttributeSet attrs,
            boolean useAndroidTheme, boolean useAppTheme) {
        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.View, 0, 0);
        int themeId = 0;
        if (useAndroidTheme) {
            // First try reading android:theme if enabled
            themeId = a.getResourceId(R.styleable.View_android_theme, 0);
        }
        if (useAppTheme && themeId == 0) {
            // ...if that didn't work, try reading app:theme (for legacy reasons) if enabled
            themeId = a.getResourceId(R.styleable.View_theme, 0);

            if (themeId != 0) {
                Log.i(LOG_TAG, "app:theme is now deprecated. "
                        + "Please move to using android:theme instead.");
            }
        }
        a.recycle();

        if (themeId != 0 && (!(context instanceof ContextThemeWrapper)
                || ((ContextThemeWrapper) context).getThemeResId() != themeId)) {
            // If the context isn't a ContextThemeWrapper, or it is but does not have
            // the same theme as we need, wrap it in a new wrapper
            context = new ContextThemeWrapper(context, themeId);
        }
        return context;
    }

    /**
     * An implementation of OnClickListener that attempts to lazily load a
     * named click handling method from a parent or ancestor context.
     */
    private static class DeclaredOnClickListener implements View.OnClickListener {
        private final View mHostView;
        private final String mMethodName;

        private Method mResolvedMethod;
        private Context mResolvedContext;

        public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
            mHostView = hostView;
            mMethodName = methodName;
        }

        @Override
        public void onClick(@NonNull View v) {
            if (mResolvedMethod == null) {
                resolveMethod(mHostView.getContext(), mMethodName);
            }

            try {
                mResolvedMethod.invoke(mResolvedContext, v);
            } catch (IllegalAccessException e) {
                throw new IllegalStateException(
                        "Could not execute non-public method for android:onClick", e);
            } catch (InvocationTargetException e) {
                throw new IllegalStateException(
                        "Could not execute method for android:onClick", e);
            }
        }

        @NonNull
        private void resolveMethod(@Nullable Context context, @NonNull String name) {
            while (context != null) {
                try {
                    if (!context.isRestricted()) {
                        final Method method = context.getClass().getMethod(mMethodName, View.class);
                        if (method != null) {
                            mResolvedMethod = method;
                            mResolvedContext = context;
                            return;
                        }
                    }
                } catch (NoSuchMethodException e) {
                    // Failed to find method, keep searching up the hierarchy.
                }

                if (context instanceof ContextWrapper) {
                    context = ((ContextWrapper) context).getBaseContext();
                } else {
                    // Can't search up the hierarchy, null out and fail.
                    context = null;
                }
            }

            final int id = mHostView.getId();
            final String idText = id == View.NO_ID ? "" : " with id '"
                    + mHostView.getContext().getResources().getResourceEntryName(id) + "'";
            throw new IllegalStateException("Could not find method " + mMethodName
                    + "(View) in a parent or ancestor Context for android:onClick "
                    + "attribute defined on view " + mHostView.getClass() + idText);
        }
    }
}

这样就达到了将以前的TextView等转换为相关的AppCompat控件,达到兼容。

setContentView()源码流程就分析到这里,细看请自行查看源码。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android setContentView源码解析

    Android开发的同学们对setContentView肯定都不陌生,但凡写到Activity,都离不开这个函数,今天我们就来看看它内部的实现吧!

    用户2898788
  • View 源码分析——setContentView

    分析一下 android 中布局的加载流程,每次新建 activity 时都要在 onCreate 中调用 setContentView(R.layout.ac...

    CatEatFish
  • Android View 源码解析(一) - setContentView

    Activity中有Window成员 实例化为PhoneWindow PhoneWindow是抽象Window类的实现类

    Android架构
  • Activity加载view6.0源码分析---setContentView

    本篇博文介绍三个方面的知识 chapter One:认识Activity的布局 chapter Two:启动activity时的布局--从setContent...

    fanfan
  • Android LayoutInflater.inflate()源码流程分析

      我们在根据layout文件得到View的时候都会使用LayoutInflater.from(mContext).inflate().下面我们来分析这个获取V...

    曾大稳
  • Flutter Android 端 Activity/Fragment 流程源码分析

    前面文章我们分析了 flutter 在 android 端编译命令相关流程,我们接下来需要先分析一下 Flutter Android 端 framework 平...

    工匠若水
  • Android开发之漫漫长途 Ⅱ——Activity的显示之Window和View(1)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

    LoveWFan
  • Android开发之漫漫长途 Ⅲ——Activity的显示之Window和View(2)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索...

    LoveWFan
  • Android之View的诞生之谜

    hello,大家好,平时大家都说自定义view,这次给大家带来有关view的相关知识,希望你喜欢!

    陈宇明
  • Flutter Android 端 FlutterView 相关流程源码分析

    前面系列文章我们分析了 FlutterActivity 等相关流程,知道一个 Flutter Android App 的本质是通过 FlutterView 进行...

    工匠若水
  • nginx流程源码分析

    nginx作为一个web服务器肯定是要监听套接字的,监听套接字用于接收HTTP请求,其是根据配置文件的内容来创建的。

    xiaomei
  • Flutter Android 端 FlutterInjector 及依赖流程源码分析

    经过前面的系列分析,这一篇会比较简单。之所以独立一个篇幅是因为本篇内容对于这个系列来说处于承上启下的作用,即是对前面的一个补充,也是对后面的一个引导,包括后续对...

    工匠若水
  • Flutter Android 端 FlutterEngine Java 相关流程源码分析

    我们在 Flutter Android 端的 Java 层代码中经常看到 FlutterEngine、FlutterEngineGroup、FlutterEng...

    工匠若水
  • Activity中的Window的setContentView

    这篇文章距离现在已经两年的时间了。当初自己刚毕业工作不久,才开始接触Android,有一天中午和同事一起吃饭的时候,一个大牛问我你思考过Activity的set...

    静默加载
  • Android View源码解读:浅谈DecorView与ViewRootImpl

    对于Android开发者来说,View无疑是开发中经常接触的,包括它的事件分发机制、测量、布局、绘制流程等,如果要自定义一个View,那么应该对以上流程有所了解...

    Android技术干货分享
  • shiro filter流程源码分析

    spring 在进行上下文初始化时会先进行 bean 和 filter 的注册操作,org.springframework.boot.web.servlet.S...

    开发架构二三事
  • 自定义View(七)-View的工作原理- Activity的布局加载

    前面几篇对动画可以说是做了非常全面的总结了(上篇文章最后的4种ViewGroup相关动画相信在了解基础后看些文章也不会太难理解)。在View的工作原理 这一部分...

    g小志
  • Android 绘制原理浅析【干货】

    对于Android开发,在面试的时候,经常会被问到,说一说View的绘制流程?我也经常问面试者,View的绘制流程.

    Rouse
  • Android M Launcher3主流程源码浅析

    关于Launcher是啥的问题我想这里就没必要再强调了。由于一些原因迫使最近开始需要研究一下Launcher3源码,为了不再像以前那么傻逼(研究Settings...

    AWeiLoveAndroid

扫码关注云+社区

领取腾讯云代金券