(源码阅读)我们经常用的setContentView(),到底做了什么。

    既然是源码阅读,那我们就果断上源码吧,首先就是Activity下的setContentView().嘿嘿,首先来看下一张比较经典的图,可能这里话的比较丑~~hhh


/**
 * 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();
}

   我们可以看到有用就只有,getWindow().setContentView(),这行代码了,点进去之后发现又是一个抽象方法。

   当我们看到的抽象发现确实比较的头疼,不知道从哪里去找。  不过,这里我window对象调用的setContentView(),所以我们通过mWindow找到mWindow = new PhoneWindow().这么一行代码,我们来到PhoneWindow这个类找到setContentView();

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();
    }
}
     先从上面来看,判断了是否为空,执行了installDecor();

private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor();     //方法一
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);    //方法二

              .............................


    }
}
   installDecore()方法太长了,这里也只是截了一部分的,中间的一部分省略了,这里只有重要的俩个方法了。

protected DecorView generateDecor() {
    return new DecorView(getContext(), -1);
}

   我们可以看到第一个方法,也只是new了一个DecorView()。那么我们来看第二个。%>_<%这也是一个巨长的方法。


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

    TypedArray a = getWindowStyle();

   ...................................
    
    
    // Inflate the window decor.

    int layoutResource;    //resId
    int features = getLocalFeatures();
    // System.out.println("Features: 0x" + Integer.toHexString(features));
    if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
        layoutResource = R.layout.screen_swipe_dismiss;
    } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogTitleIconsDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else {
            layoutResource = R.layout.screen_title_icons;
        }
        // XXX Remove this once action bar supports these features.
        removeFeature(FEATURE_ACTION_BAR);
        // System.out.println("Title Icons!");
    } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
            && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
        // Special case for a window with only a progress bar (and title).
        // XXX Need to have a no-title version of embedded windows.
        layoutResource = R.layout.screen_progress;
        // System.out.println("Progress!");
    } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
        // Special case for a window with a custom title.
        // If the window is floating, we need a dialog layout
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogCustomTitleDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else {
            layoutResource = R.layout.screen_custom_title;
        }
        // XXX Remove this once action bar supports these features.
        removeFeature(FEATURE_ACTION_BAR);
    } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
        // If no other features and not embedded, only need a title.
        // If the window is floating, we need a dialog layout
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                    R.attr.dialogTitleDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
            layoutResource = a.getResourceId(
                    R.styleable.Window_windowActionBarFullscreenDecorLayout,
                    R.layout.screen_action_bar);
        } else {
            layoutResource = R.layout.screen_title;
        }
        // System.out.println("Title!");
    } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
        layoutResource = R.layout.screen_simple_overlay_action_mode;
    } else {
        // Embedded, so no decoration is needed.
        layoutResource = R.layout.screen_simple;   //这个布局是Android自带的
        // System.out.println("Simple!");
    }

    mDecor.startChanging();

    View in = mLayoutInflater.inflate(layoutResource, null);   //o通过inflate去加载对应的一系列判断下来的resId
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    mContentRoot = (ViewGroup) in;

    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);    //去拿到Android自带的一个布局文件 ,里面只有一个LinearLayout
    if (contentParent == null) {
        throw new RuntimeException("Window couldn't find content container view");
    }

    mDecor.finishChanging();

    return contentParent;     //最终将拿到的布局文件返回回去。
}

/**
 * The ID that the main layout in the XML layout file should have.
 */
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

    这个时候我们再回来在phoneWindow里面看到的setContentView()方法,我们发现下面去.inflate(layoutResID,mContentParent);

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();
}
     这里其实也就是去把我们在setContentView()时,设置的resId的布局解析到我们在generateLayout方法所加载的R.id.content的布局上面。

     到这里,所看的源码也基本上结束了,中间还有很多的判断或许对大家有用,需要大家去阅读。

     看了一些源码之后,本人也get到一些技能了,当不会写的时候就根据Android的源码去写。

          






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的 Android 日历应用的源代码示例,你可以参考它来编写你自己的应用: 首先是布局文件 activity_main.xml,用来显示日历和日期选择器: ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 日历 --> <com.example.calendarview.CalendarView android:id="@+id/calendar_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" /> <!-- 日期选择器 --> <NumberPicker android:id="@+id/date_picker" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/calendar_view" android:layout_centerHorizontal="true" /> </RelativeLayout> ``` 接下来是 CalendarView.java 文件,实现了日历的显示和点击事件: ```java public class CalendarView extends GridView { private static final int DAYS_COUNT = 42; private Context mContext; private Calendar mCalendar; private CalendarAdapter mAdapter; public CalendarView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; mCalendar = Calendar.getInstance(); mAdapter = new CalendarAdapter(mContext, mCalendar); setAdapter(mAdapter); setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // 处理点击事件 mAdapter.setSelected(position); mAdapter.notifyDataSetChanged(); } }); } private class CalendarAdapter extends BaseAdapter { private LayoutInflater mInflater; private Calendar mCalendar; private int mSelectedPosition; public CalendarAdapter(Context context, Calendar calendar) { mInflater = LayoutInflater.from(context); mCalendar = calendar; mSelectedPosition = -1; } public void setSelected(int position) { mSelectedPosition = position; } @Override public int getCount() { return DAYS_COUNT; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.calendar_item, parent, false); } TextView textView = (TextView) convertView.findViewById(R.id.calendar_text); int day = position - mCalendar.get(Calendar.DAY_OF_WEEK) + 2; if (day < 1 || day > mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH)) { textView.setText(""); } else { textView.setText(String.valueOf(day)); } if (position == mSelectedPosition) { textView.setTextColor(Color.RED); } else { textView.setTextColor(Color.BLACK); } return convertView; } } } ``` 接下来是 calendar_item.xml 文件,用来显示日历中的每一天: ```xml <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/calendar_text" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="20sp" /> ``` 最后是 MainActivity.java 文件,实现了日期选择器的显示和选择事件: ```java public class MainActivity extends AppCompatActivity { private CalendarView mCalendarView; private NumberPicker mDatePicker; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mCalendarView = (CalendarView) findViewById(R.id.calendar_view); mDatePicker = (NumberPicker) findViewById(R.id.date_picker); mDatePicker.setMinValue(1); mDatePicker.setMaxValue(31); mDatePicker.setValue(1); mDatePicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { // 处理日期选择事件 mCalendarView.setSelection(newVal + mCalendarView.getFirstVisiblePosition() - 2); } }); } } ``` 这就是一个简单的 Android 日历应用的源代码示例,希望能对你有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值