說說 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();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章