经常看到这样的代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
尽管 findViewById 方法在这个MainActivity类中没有声明,但其实在父类 AppCompatActivity 声明过了,setContentView 也是这样,它也是在 AppCompatActivity 类中声明的。
但是在这个findViewById方法中到底发生了什么?
为什么要传入一个资源 id? 为什么会有另外一个括号强制转换呢?
当你点击设备上的应用图标 就打开了 MainActivity,在我们的代码中 MainActivity 的 onCreate 方法被系统调用,在这个方法中有一个 setContentView 方法,它是资源布局 id,比如我们可以给 setContentView 只传一个 TextView,但是我们想要更多的 View,所以我们传入一个布局资源 id,这个对应的是一个 XML 文件,一旦调用 setContentView,activity就会找到 XML 布局文件,并且读取它的每行代码,它会为每一个 View 填充或者创建一个 Java 对象,它遍历整个 XML 文件,并且建立 Java 对象间的层次关系,当它填充每一个 View 的时候,它会调用构造函数,也就是 NewTextView(setContentView只传入TextView的时候) 或者 NewLinearLayout(setContentView传入LinearLayout布局资源的时候) 方法,然后把这些属性传给 Java 对象,这样它就被设置好了。注意,我们不用给 NewTextView 和 NewLinearLayout写任何代码,也不用设置字体大小,所有的这些都是由 activity 填充过程完成的。
为了在应用运行时能与这些视图进行交互并且修改它们,例如修改文本或者修改按钮,那么我们需要找到 Java 对象,一旦我们找到它们,我们可以在 MainActivity 中用引用指向它们,记住,我们没有创建新的 TextView对象,我们只是在视图树中找到了现有的 TextView,为了与这个视图树中的 View 进行交互,我们应该创建变量,用来引用这些具体的 View,例如,我们可以创建一个 quantity TextView 变量,它指向这个 TextView,如果你点击 UI 中的加、减按钮,你就可以改变 TextView 的文本使它显示不同的数字,又如何把 quantity引用变量与这个 TextView 联系起来呢?我们回到布局 XML 文件,还记得我们给 View 指定了 id 吗?对于这个 TextView 我们给它指定一个id 为 quantity_textview,给 View 指定 id 是可选择的,你只需要给你要引用的 View 指定 id,例如,你可以给任何 View 指定 id,但是我们通常只是给我们需要的View加上id。之后我们可以在 Java 代码中引用它们了。
但是我们还是不知道如何建立变量和具体的 Java 对象之间的联系,对于这个变量和 Java 对象 情况也是如此,在AppCompatActivity 类中,有一个具体的方法就是调用 findViewById,并且传入一个资源 id,findViewById 方法会找到与传入的 id 相对应的 View,Activity 在 XML 的视图层次结构中搜索这个视图,再在 onCreate 方法中处理它,这个 activity 的 onCreate 方法建立了一个视图层次结构。然后 findViewById 方法遍历它,找到那个视图层次结构中的某个 View,这个方法的返回值是 View 类型的对象。这就意味着在 activity 代码中 我们可以调用 findViewById传入我们所需 View 的资源 id,然后它就会返回一个 View 对象,我们就可以把它当做变量存在 activity 中(引用指向这个对象)。
如果我们这么写
View textView = findViewById(R.id.textview);
textView.setText("设置文本");
结果显示不能解析 setText 方法,这是为什么呢?
setText 是一个 TextView 方法!!也就意味着你只能用 TextView 对象调用这个方法,在这里是用 textView 调用的,而textView 声明为一个 View对象,我们需要把它变成 TextView 对象
TextView textView = findViewById(R.id.textview);
又报错了,说类型不兼容,我们需要一个 TextView 类型,但这是一个 View 的对象,因为 findViewById 的返回值是 View 类型,而左边需要一个 TextView 类型,意味着我们必须强制转换类型。
TextView textView = (TextView) findViewById(R.id.textview);
不报错了!
来看第二个
View textView2 = findViewById(R.id.textview2);
textView2.setVisibility(View.GONE);
这有一个对象是 View 类型,正在调用一个 setVisibility 方法,方法有一个输入参数 View.GONE,查阅一下文档,在 View 类的文档里搜索一下setVisibility 方法,可以看到 setVisibility 是 View 类中的一个方法,所以这是一个有效的调用,没有必要转化成 TextView 格式,因为我们调用的方法是 View 类的,如果我们想要调用 TextView 类的方法就需要类型转换了。