目前在做项目时候有这样的需求:布局文件的控件类型大致相同,例如某布局文件由GridView、ScrollView、TextView、Button四个控件组成,但是控件的摆放位置不同。因为摆放的方式很多,不可能把所有摆放方式都写一个布局文件,因为这样不利于迭代开发。这时候就想出能不能把布局文件放在服务器上,当需要某布局的时候,从服务器下载布局文件保存到存储卡上,然后读取存储卡上的布局文件。
思路大致清除了,那么现在开始进行可行性分析。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
上面的代码太熟悉不过了,创建一个新Android工程,这玩意就已经写好了!通过setContentView()方法,我们可以设置布局文件,但是这里的参数是R文件的布局ID,如果是布局文件的路径就好了,这样就可以直接读取SD卡的XML布局文件了!按住Ctrl+鼠标左键,点击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(int layoutResID) {
getWindow().setContentView(layoutResID);
initActionBar();
}
从这里我们可以看到,setContentView()方法调用了Window类里的setContentView()方法,调来调去啊!继续按住Ctrl+鼠标左键,点击setContentView()进入:
/**
* Convenience for
* {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}
* to set the screen content from a layout resource. The resource will be
* inflated, adding all top-level views to the screen.
*
* @param layoutResID Resource ID to be inflated.
* @see #setContentView(View, android.view.ViewGroup.LayoutParams)
*/
public abstract void setContentView(int layoutResID);
花擦,这里变成了抽象函数,在哪里实现啊!不要惊慌,通过源码可以得知,Window类是一个抽象类,那么它的实现应该是在子类中。那么Window类有哪些子类?
/**
* Abstract base class for a top-level window look and behavior policy. An
* instance of this class should be used as the top-level view added to the
* window manager. It provides standard UI policies such as a background, title
* area, default key processing, etc.
*
* <p>The only existing implementation of this abstract class is
* android.policy.PhoneWindow, which you should instantiate when needing a
* Window. Eventually that class will be refactored and a factory method
* added for creating Window instances without knowing about a particular
* implementation.
*/
这是Window类源码的开头说明,从中可以立马看到PhoneWindow,对!没错就是它!在PhoneWindow中终于找到了它的具体实现!
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
<span style="color:#ff0000;"> mLayoutInflater.inflate(layoutResID, mContentParent);
</span> final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
从标红的代码,我们可以看到,布局的ID是用在了该段代码,看到了inflate方法,我想大家应该不陌生,在BaseAdpter中经常会用到,用来填充布局的!继续按住Ctrl+鼠标左键,点击inflate(....)进入:
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
*
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy.
* @return The root View of the inflated hierarchy. If root was supplied,
* this is the root View; otherwise it is the root of the inflated
* XML file.
*/
public View inflate(int resource, ViewGroup root) {
return inflate(resource, root, root != null);
}