说说 setOnClickListener 的几种方式

因为不是计算机专业,当时入门安卓的时候,看的 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();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章