setContentView()源码的理解

setContentView()源码的理解

通俗的解释

使用场景

在Activity中的onCreate()方法中,我们会使用setContentView()给Activity加载布局。但实际情况却不是我们通常使用时理解的那样。正如setContentView()方法名那样,是将layout设置给content,而不是设置给Activity。

先放结论

Activity的布局是有特定的模板,我们通常只是给Content区域填充View
以screen_custom_title.xml模板为例(查看源码请按这里),会得到下图

这里写图片描述
简单梳理一下执行流程:

Created with Raphaël 2.1.0 setContentView(layout) 初始化DecorView(FrameLayout) 根据情况初始化相应的ViewGroup 将ViewGroup添加到DecorView中 在ViewGroup中找到Content(FrameLayout)对象 将Layout填充到Content中 其他操作

以findViewById()为例,来进一步理解

在Activity中,我们使用findViewById()都很熟练,感觉没什么特别的。但是在Framework中,想要找到特定的控件对象,会使用

view.findViewById(id);

来获取相应的控件。实际上,findViewById()是View当中的方法在Activity中,findViewById()实际上是调用DecorView.findViewById(),只是不给使用者展示。也就是说,DecorView是外层的布局,也从侧面验证了上图。

RTFSC解释

为了把握整体思路,这里并没有详细地说明每一行代码

Activity中的相关代码

public void setContentView(@LayoutRes int layoutResID) {
    //会调用PhoneWindow中的代码
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

PhoneWindow中setContentView()相关代码

public void setContentView(int layoutResID) {
    //mContentParent,也就是Content(上图浅紫色,与Title平级的部分)
    if (mContentParent == null) {
        //DecorView会在这里初始化,ViewGroup也在该方法中添加到DecorView中了,同时找打了mContentParent对象
        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 {
        //将我们的Layout填充到mContentParent中
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

installDecor()中相关的代码,有省略代码

private void installDecor() {
    if (mDecor == null) {
        //初始化DecorView
        mDecor = generateDecor();
        //一些相关的配置
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    if (mContentParent == null) {
        //将ViewGroup添加到DecorView中,并将Content找到,返回
        mContentParent = generateLayout(mDecor);

        mDecor.makeOptionalFitsSystemWindows();

        //自带装饰的Content
        //DecorContentParent名字起的也很生动,带装饰的
        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);

        if (decorContentParent != null) {
            //对decorContentParent的操作
            //设置logo,title,icon,options...
        } else {
            //对Title的一些操作
            //...
        }

        if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
            mDecor.setBackgroundFallback(mBackgroundFallbackResource);
        }

        // Only inflate or create a new TransitionManager if the caller hasn't
        // already set a custom one.
        if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
            //一些过渡的操作
            //...
        }
    }
}

generateLayout中相关的代码,有省略

protected ViewGroup generateLayout(DecorView decor) {
    //获取相关属性
    TypedArray a = getWindowStyle();

    if (false) {
        //估计是调试用的代码
        //...
    }

    //各种属性的设置
    //...

    //ViewGroup的Layout用的id
    int layoutResource;
    int features = getLocalFeatures();
    //根据设置来确定layoutResource是哪个layout
    //...

    //做个开始标记
    mDecor.startChanging();

    //填充ViewGroup
    View in = mLayoutInflater.inflate(layoutResource, null);
    //将ViewGroup添加到DecorView中
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    mContentRoot = (ViewGroup) in;

    //获取Content对象
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

    //一些操作
    //...

    //做个结束标记
    mDecor.finishChanging();

    //返回ViewGroup
    return contentParent;
}

结语

setContentView()相关的代码还是很多的,需要抓住重点,这样才不会影响整体的思维。
如果看完了还是感觉云里雾里,那就先把图片记住,剩下的以后再说

转载请标明出处:http://blog.csdn.net/qq_26411333/article/details/51541129

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.czl.struct.activity; import java.util.ArrayList; import java.util.HashMap; import android.os.Bundle; import android.view.Menu; import com.czl.struct.R; import com.czl.struct.adapter.DemoAdapter; import com.czl.struct.interfaces.DragItemChangeListener; import com.czl.struct.widget.DragListView; public class MainActivity extends BaseActivity implements DragItemChangeListener{ private DragListView dragListView; private ArrayList<HashMap<String, Object>> list; private DemoAdapter demoAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); findViewById(); } @Override public void init() { list = new ArrayList<HashMap<String, Object>>(); for (int i = 0; i < 20; i++) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("numbTV", "D138026594664912200" + i); map.put("adrTv", "浙江省杭州市西湖区小和山"); map.put("timeTv", "2013-09-27 15:23"); map.put("callTv", "18778900578"); list.add(map); } } @Override public void findViewById() { dragListView = (DragListView) findViewById(R.id.dragLvi); demoAdapter = new DemoAdapter(MainActivity.this, list); dragListView.setAdapter(demoAdapter); dragListView.setDragImageSourceId(R.id.imageView1); dragListView.setDragItemChangeListener(this); } @Override public void Message(android.os.Message msg) { } @Override public void onDragItemChange(int dragSrcPosition, int dragPosition) { HashMap<String, Object> map = list.get(dragSrcPosition); list.remove(dragSrcPosition); list.add(dragPosition, map); demoAdapter.notifyDataSetChanged(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值