因为不是计算机专业,当时入门安卓的时候,看的 Mars 的视频学起来的,挺多知识很迷糊。
后面也是开始做了些项目才慢慢熟悉起来。
最近花了一些时间,把做的第一个 app 重构了下,以前的代码不能直视。
当然菜不要紧,要是菜还不勤快,那肯定就没法了。
说到初见安卓,肯定会用到一些交互控件,最常用的方式之一就是 Button 触发 OnClickListener。
当时因为 Java 懂的不太多,看到过几种写法,还有点被绕晕了。
现在看肯定是没啥问题,当时看感觉真是有点迷糊。
一:
public MainActivity extends Activity implements OnClickListener{
……
@Override
protected void onCreate(Bundle savedInstanceState) {
……
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
}
}
先来分析下这个,button.setOnClickListener() 需要传入的是 OnClickListener 类型的实例。
此时是把 MainActivity 作为 OnClickListener 类型传入,但是 MainActivity 是继承 Activity 的,也不是 OnClickListener 类型,此时让 MainActivity 实现了 OnClickListener 接口,将 OnClick 方法重写,那么此时就可以发挥作用了。
类似于:某个岗位需要一个程序员,然后只有一个电工的师傅,那怎么让电工的师傅去接手呢,当然就是让电工师傅去学习敲代码,然后就可以作为程序员在那个位置上工作了。
此处的 this 代表的是 MainActivity 的实例,如果调用方法外还有一个其他的类,那么久必须要使用 MainActivity.this 来指定是 MainActivity 这个实例,比如我们在一个新的线程当中使用。
class MainActivity{
……
@Override
protected void onCreate(Bundle savedInstanceState) {
……
final Button button = new Button(this);
new Thread(new Runnable() {
@Override
public void run() {
button.setOnClickListener(MainActivity.this);
// 思考题
//button.setOnClickListener(this);
}
}).start();
}
}
不过话说,如果在这个例子中是直接使用 this 的话,那么究竟是指的是哪个的实例呢,留个思考题。
二:
@Override
protected void onCreate(Bundle savedInstanceState) {
……
button.setOnClickListener(new MyOnClickListener());
}
class MyOnClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
}
}
再来说说这个,此处需要一个 OnClickListener 实例,我们去定义了一个新的类,然后实现了 OnClickListener 接口,然后直接 new 一个该类可以了。
类似于:此处需要一个程序员,我们去学校招了一个计算机专业的学生,默认计算机专业同学都会敲代码。
三:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
这种是匿名对象,不知道你类的名字,不知道你是谁,只知道你可以作为 OnClickListener 类型。这种无法获取到该对象的实例。
类似于:我们招了一小伙,不知道你的其他信息,就知道你会敲代码。然后突然想找下你的时候,发现叫不出来你的名字,只能说新来的那个敲代码的小伙。
后面随着对 Java 逐渐熟悉,知道这是类的转型。
主要分为 向上转型 和 向下转型 。
先说 向上转型:
举个简单地例子:一个学生是人,这个说法没错吧,因为人是大的范围,而学生算是人当中的一个小范围,如果按职业来分的话,就还有 老师、科学家、商人等。
//此处我们做一个方法,需要传入一个 Man 类型。
public static void cleanStreet(Man man){ …… }
//新建一个类为 Man
static class Man{ }
//新建一个类为 Student , Student 继承 Man
//那么 Man 类型就是父类(超类) Student 类型就是子类
static class Student extends Man{ }
//所以在传入参数的时候,默认不需要加任何符号,计算机都可以识别向上转型。
//从逻辑上也能说得过去,一个学生肯定可以作为一个人的类型
cleanStreet(new Student());
cleanStreet(new Man());
比如哪天我们需要扫大街,这个一般人都会吧,如果人够的时候呢,就找普通的人就行了,如果人不够的时候,或者是搞什么社会实践的时候,需要学生出力下,那么他就可以作为人这个类型去发挥作用。从逻辑上说,学生是人也是没有问题的,所以 向上转型是安全的。
向上转型就是把一个小的类型转化一个大的类型(更具体的类型转化为更通用的类型)子类 —> 父类。
那么 向下转型 呢,按照刚才的例子来说,把一个人变为学生,这个听起来不太 “安全” 。就像如果每个普通人都拿去变成学生,那么国家这教育水平,人均文化水平就提高了一个大的层次了,把美国老大的位置抢下来就指日可待了。开个玩笑,继续刚才话题。
那怎样才能保证一个人能比较安全的转型为学生呢,那么有一种可能的情况: 就是他之前就是学生这个类型,被转型为普通人,然后你再把他转型为学生,那么肯定没什么问题。
就拿刚才那个例子,你不是在写作业么,现在扫地人不够了,需要大家来出力,然后地扫完了。教室课本上的作业谁来做是把?嗯,又把你转型为学生回去做作业 ……
//新建一个方法,需要传入的类型为学生。
public static void doHomework(Student student){ …… }
//新建一个学生对象,先把他转型为普通人。
Man man = new Student();
//那么向下转型的时候,是需要加一些标记的。
//把 man 对象,加上 (需要转换的类型) ,此处为 (Student)
//就可以把 man 类型强制转换为 Student 类型进行传入。
doHomework((Student)man);
这样的话,其实有一种情况,就是如果你并不确定是不是一定能转换成功怎么办。或者故意是一个错误的类型怎么办。
//我们新建一个 Worker 类,也继承 Man 。
static class Worker extends Man{}
//先把 Worker 转为 Man 类型。
Man man2 = new Worker();
//再去把 man2 强制转换为 Student
//因为先转换为 Man 类型,此时编译器已经没法区别他之前是不是 Student 类型。
doHomework((Student)man2);
如果此时运行一下,肯定会弹出异常,类型转换错误。
Caused by: java.lang.ClassCastException:
xxx.MainActivity$Worker cannot be cast to xxx.MainActivity$Student
这样的话,可以使用 try catch 包裹住,捕获可能转换存在的异常。
Man man2 = new Worker();
try{
doHomework((Student)man2);
}catch (ClassCastException e){
e.printStackTrace();
}