通过对inflate与 findViewById 方法的探究深度了解一下Android

来源:互联网 发布:租房月付软件 编辑:程序博客网 时间:2024/05/16 08:38
目前为止,很多大牛已经纷纷发表了对inflater.inflate方法与findViewById方法的见解。从概要上,小编总结了一下讲得比较靠谱的说法,之后会针对这方面进一步做一下测试探究,帮助Android新手更进一步了解一下我们正在一个什么样的平台上怎样便利地开发着一款软件。

===================================================================

在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById()。不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;而findViewById()是找xml布局文件下的具体widget控件(如Button、TextView等)。

具体作用:

1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;

2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。

LayoutInflater作用是将layoutxml布局文件实例化为View类对象。

注意:

·inflate方法与 findViewById 方法不同;

·inflater 是用来找 res/layout下的 xml 布局文件,并且实例化;

·findViewById() 是找具体 xml 布局文件中的具体 widget控件(如:Button、TextView 等)。

====================================================================

上述就是目前小编找到的最靠谱的说法了,但是讲的依然有一些小瑕疵,不够深入。

首先,小编认为.inflate方法与findViewById方法不是类似的,而是完全两个领域的方法,根本没有可比性。

其次,也是非常重要的一点是上述的最后一句话理解有误,暴露了对底层原理理解的偏差。


小编是这样理解的:我们可以把*.xml布局文件理解为“模板”,就像在学习Java时我们知道的,类是对象的“模板”一样。所以,就像Java的虚拟机会根据我们写的类实例化成一个个的对象一样,Android也会根据我们写的.xml文件实例化出View对象。而Android应用就是靠这一个个的View对象构建起庞大而复杂的APP的。所以,在Android的UI开发中,应时刻记得我们是在操作着一个个的View对象,而不是.xml文件,把对那些方法的理解联系到对象上。

inflate方法的作用就是根据.xml文件,实例化出一个对象来。如:

<LinearLayout android:id="@+id/test_linear"       android:layout_width="match_parent"       android:layout_height="wrap_content"       android:orientation="vertical" >             <Button android:layout_width="wrap_content"             android:layout_height="wrap_content"/>             <Button android:layout_width="wrap_content"             android:layout_height="wrap_content"/>       </LinearLayout>

      根据这个“模板”,系统会为我们实例化出一个包含了两个Button形子View对象的LinearLayout形的ViewGroup父对象,所以不知不觉之间,其实我们创建了起码3个对象。而这就是inflate方法的实际意义——生成对象。

再来看看findViewById,这个方法其实是基于父View对象进行的。比如说上面被实例化出来的LinearLayout对象,我们如果想找到它所包含的某个Button对象,就有可能用到findViewById方法。以识别Id的方式来查找子对象。所以findViewById的实际意义是——查找对象(不生成对象,而是找到它并返回它)。


下面小编就通过测试代码带大家理解一下Android这个平台的局部原理。

main_activity.xml:

<LinearLayout   xmlns:tools="http://schemas.android.com/tools"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:orientation="vertical"   android:paddingBottom="@dimen/activity_vertical_margin"   android:paddingLeft="@dimen/activity_horizontal_margin"   android:paddingRight="@dimen/activity_horizontal_margin"   android:paddingTop="@dimen/activity_vertical_margin"   tools:context="com.example.testandroidview.MainActivity"><Button       android:id="@+id/btn1"       android:layout_width="wrap_content"       android:layout_height="wrap_content"       android:text="按钮1"/> <Button       android:id="@+id/btn2"       android:layout_width="wrap_content"       android:layout_height="wrap_content"       android:text="按钮2"/></LinearLayout>  



activity_sub.xml:

<LinearLayout>   xmlns:tools="http://schemas.android.com/tools"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:orientation="vertical"   android:paddingBottom="@dimen/activity_vertical_margin"   android:paddingLeft="@dimen/activity_horizontal_margin"   android:paddingRight="@dimen/activity_horizontal_margin"   android:paddingTop="@dimen/activity_vertical_margin"   tools:context="com.example.testcontentprovider2.MainActivity"><LinearLayout      android:id="@+id/test_linear"       android:layout_width="match_parent"       android:layout_height="wrap_content"       android:orientation="vertical" >       <Button              android:id="@+id/sub_add"             android:layout_width="wrap_content"             android:layout_height="wrap_content"/></LinearLayout>       </LinearLayout>



下面给出两个Activity代码,会在代码中伴随讲解原理

MainActivity.java

public class MainActivity extends Activity {    Buttonbtn1;    Buttonbtn2;    Buttonbtn3;   @Override    protectedvoid onCreate(Bundle savedInstanceState) {       super.onCreate(savedInstanceState);       setContentView(R.layout.activity_main);       btn1 = (Button)findViewById(R.id.btn1);       btn2 = (Button)findViewById(R.id.btn2);       btn3 = (Button)findViewById(R.id.btn3);       btn1.setOnClickListener(new View.OnClickListener() {                  @Override          public voidonClick(View v) {             // TODOAuto-generated method stub            System.out.println("MainActivity's btn1 pressed!");          }       });       btn2.setOnClickListener(new View.OnClickListener() {                  @Override          public voidonClick(View v) {             // TODOAuto-generated method stub            System.out.println("MainActivity's btn2 pressed!");          }       });       btn3.setOnClickListener(new View.OnClickListener() {                  @Override          public voidonClick(View v) {             // TODOAuto-generated method stub             Intentintent = new Intent(MainActivity.this, SubActivity.class);            startActivity(intent);          }       });    }}


SubActivity.java 这个Activity是测试的关键

public class SubActivity extends Activity {    Buttonbtn;   @Override    protectedvoid onCreate(Bundle savedInstanceState) {       // TODOAuto-generated method stub      super.onCreate(savedInstanceState);      setContentView(R.layout.activity_sub);       btn =(Button) findViewById(R.id.sub_add);      btn.setOnClickListener(new View.OnClickListener() {         @Override          public voidonClick(View v) {             // TODOAuto-generated method stub            addTestView();          }       });    }    private voidaddTestView() {       //找到当前Activity下的一个View容器,准备用这个容器去addView       finalLinearLayout ll = (LinearLayout)findViewById(R.id.test_linear);      //这里的动作就是寻找,因为整个布局的对象已经在setContentView(R.layout.activity_sub);代码执行完成后就已经实例化出来了,我们要找的LinearLayout就在这个大对象里,是它的一个子对象。       //渲染出即将被添加的View(下面就是另一个实例化操作)      LayoutInflater li = LayoutInflater.from(this);       finalLinearLayout view = (LinearLayout) li.inflate(            R.layout.activity_main, null);       //可见,即将被添加的View就是用的MainActivity的xml模板实例化出来的,这样就是为了测试该View下的按钮btn1btn2是否会与MainActivity中的按钮混淆(当然,我们可以预测到,如果混淆,那就说明我们的组件是"模板化"的,否则,我们的组件则是"对象化"的)      ll.addView(view);       //分别用两种不同的方法给即将被添加的View中的btn1和btn2添加点击事件       // 方法1       Button btn1= (Button) view.findViewById(R.id.btn1);      btn1.setOnClickListener(new View.OnClickListener() {         @Override          public voidonClick(View v) {             // TODOAuto-generated method stub            System.out.println("SubActivity's btn1 pressed!");          }       });       // 方法2       Button btn2= null;       for (int i =0; i < view.getChildCount(); i++) {          int id =view.getChildAt(i).getId();          if (id ==R.id.btn2) {             btn2 =(Button) view.getChildAt(i);          }       }       if (!(btn2== null)) {         btn2.setOnClickListener(new View.OnClickListener() {            @Override             public voidonClick(View v) {                // TODOAuto-generated method stub               System.out.println("SubActivity's btn2 pressed!");             }          });       }          }}

之所以可以用方法2,是因为这里的父View即变量view是LinearLayout,而不仅仅是View,LinearLayout是继承自ViewGroup的,所以它可以getChild,如果是直接继承自View的子类是没有Child可言的

以上均测试完毕后不难总结出来:R.id.btn1这个int值(存在于R.java文件中)不是某个按钮的唯一标识,而是btn1按钮的"模板"的唯一标识,而我们可以通过xml模板在不同的地方产生不同的btn1对象,这些对象都是相互独立存在的,而我们用到R.id.btn1这个int值仅仅是在某地"寻找"btn1对象的时候用到的一个匹配工具

通过上述测试,可以看出Android平台的博大精深。她为了方便开发者开发,不用开发者做每个视图都自己敲冗杂的代码,于是采用了.xml的方式帮助开发者快速建立视图对象。但是方便的同时也带来了一定的问题,就是造就了很多像小编这样的“傻瓜”。我们无脑地运用.xml文件,却没了机会去了解背后的本质。
有哪里讲的不对的地方麻烦看客老爷们多多纠正,感激涕零。

还是那句话,每在某个角度了解了一些后,都会突然对Android感到陌生,感觉又重新认识了她一样。


附上源码:http://pan.baidu.com/s/1i31NK0l

0 0