顯示廣告
隱藏 ✕
※ 本文為 kewang 轉寄自 ptt.cc 更新時間: 2012-01-30 09:54:08
看板 AndroidDev
作者 givemepass (〆)
標題 Re: [問題] onClickListener的事件處理?
時間 Tue Jan 10 10:38:24 2012


※ 引述《sweet00914 (別理我)》之銘言:
: MyListener ml=new MyListener();
: F1 = (Button) findViewById(R.id.bottomBtnF1);
: F1.setOnClickListener(ml);
: private class MyListener implements OnClickListener{
:         public void onClick(View v) {
:         }
: }
: ==========================================================
: F1 = (Button) findViewById(R.id.bottomBtnF1);
: F1.setOnClickListener(btnclick);
: private OnClickListener btnclick=new OnClickListener(){
:                 public void onClick(View v) {
:         }
: }
: 上述兩種寫法均可執行,第一種方式是將onClick的事件以Class來表示,
: 第二種方式是以function來表示。
: 請問大家此兩種寫法在android上還有其他涵義嗎?謝謝

假設你有兩個元件要建立事件
也許你會這樣做

button1 = (Button)findViewById(R.id.btn1);
button2 = (Button)findViewById(R.id.btn2);
textView1 = (TextView)findViewById(R.id.text_view1);
textView2 = (TextView)findViewById(R.id.text_view2);

class MyOnClickListener implements OnClickListener{
    public void onClick(View v){
        textView1.setText("textview1");
    }
    public void onClick(View v){
        textView2.setText("textview2");
    }
}
private MyOnClickListener myOnClickListener = new MyOnClickListener();
button1.setOnClickListener(myOnClickListener);
button2.setOnClickListener(myOnClickListener);

不! 你不能這樣做, 因為你不能在同一個類別內實作同一個方法兩次,
而且你會被編譯器擋下, 那怎麼辦呢?
也許可以這樣做

class MyOnClickListener implements OnClickListener{
    public void onClick(View v){
        if(v.getId()==R.id.btn1){
            textView1.setText("textview1");
        }
        else if(v.getId()==R.id.btn2){
            textView2.setText("textview2");
        }
    }
}

甚至比較乾淨的做法是
class MyOnClickListener implements OnClickListener{
    public void onClick(View v){
        switch(v.getId()){
        case R.id.btn1:
            textView1.setText("textview1");
            break;
        case R.id.btn2:
            textView2.setText("textview2");
            break;
        }
    }
}

最後在補上
private MyOnClickListener myOnClickListener = new MyOnClickListener();
button1.setOnClickListener(myOnClickListener);
button2.setOnClickListener(myOnClickListener);

看起來似乎不錯, 但是萬一某一天我想要改變某個動作,
那又等重新修改整段程式碼的事件, 也許手殘會把其他的事件弄亂,
這樣一點也不好。

那如果這樣呢? 分別寫在不同的類別
public class MyActivity extends Activity{
    public void onCreate(){
        button1 = (Button)findViewById(R.id.btn1);
        button2 = (Button)findViewById(R.id.btn2);
        textView1 = (TextView)findViewById(R.id.text_view1);
        textView2 = (TextView)findViewById(R.id.text_view2);
        myOnClickListener1 = new MyOnClickListener1();
        myOnClickListener2 = new MyOnClickListener2();
        button1.setOnClickListener(myOnClickListener1);
        button2.setOnClickListener(myOnClickListener2);
    }
    private MyOnClickListener1 myOnClickListener1;
    private MyOnClickListener2 myOnClickListener2;
}
class MyOnClickListener1 implements OnClickListener{
    public void onClick(View v){
        textView1.setText("textview1");
    }

}
class MyOnClickListener2 implements OnClickListener{
    public void onClick(View v){
        textView2.setText("textview2");
    }
}
你會被編譯器擋下來, 因為在MyOnClickListener1和MyOnClickListener2並不存在
textView1跟textView2這兩個類別成員。

所以我們又想到一個好辦法, 那就是把事件類別寫在我們要處理事件的類別內,
改成這樣就沒問題了! 內部類別

public MyActivity extends Activity{
    private TextView textView1;
    private TextView textView2;

    private MyOnClickListener1 myOnClickListener1;
    private MyOnClickListener2 myOnClickListener2;
    public void onCreate(){
       button1 = (Button)findViewById(R.id.btn1);
       button2 = (Button)findViewById(R.id.btn2);
       textView1 = (TextView)findViewById(R.id.text_view1);
       textView2 = (TextView)findViewById(R.id.text_view2);
       myOnClickListener1 = new MyOnClickListener1();
       myOnClickListener2 = new MyOnClickListener2();
       button1.setOnClickListener(myOnClickListener1);
       button2.setOnClickListener(myOnClickListener2);
    }

    class MyOnClickListener1 implements OnClickListener{
       public void onClick(View v){
          textView1.setText("textview1");
       }
    }
    class MyOnClickListener2 implements OnClickListener{
       public void onClick(View v){
          textView2.setText("textview2");
       }
    }
}
類別內的類別稱作inner class, 那inner class稱呼包著它的類別就叫做outer class,
inner class可以使用outer class的任何成員,就算是private的也是可行,
如上面的例子, 內部類別可以取用textView1,textView2。

但是!
寫程式總是會想要偷懶, 少寫幾行又能完成相同的功能,
那我們就會開始想辦法偷懶,
你有沒有發現每次都要宣告類別, 定義要處理的事件,
然後在宣告實體, 最後將實體配置給某個元件的監聽器,
有夠麻煩的,
因此我們就會想,
不如把定義事件跟宣告該事件類別的物件一起寫,
這樣不就方便多了?
所以改成這樣, 也許會好一點!

public MyActivity extends Activity{
    private TextView textView1;
    private TextView textView2;
    //private MyOnClickListener1 myOnClickListener1;
    //private MyOnClickListener2 myOnClickListener2;
    public void onCreate(){
        button1 = (Button)findViewById(R.id.btn1);
        button2 = (Button)findViewById(R.id.btn2);
        textView1 = (TextView)findViewById(R.id.text_view1);
        textView2 = (TextView)findViewById(R.id.text_view2);
        //myOnClickListener1 = new MyOnClickListener1();
        //myOnClickListener2 = new MyOnClickListener2();
        button1.setOnClickListener(mOnClickListener1);
        button2.setOnClickListener(mOnClickListener2);
    }

    private OnClickListener mOnClickListener1
                                 = new OnClickListener(){
        public void onClick(View v){
            textView1.setText("textview1");
        }
    };
    private OnClickListener mOnClickListener2
                                 = new OnClickListener(){
        public void onClick(View v){
            textView2.setText("textview2");
        }
    };
}

嗯...少寫幾行的感覺真爽!
但是全聯先生說:省還可以更省。
如果我們再將定義事件類別宣告的變數省起來,
直接寫進setOnClickListener, 不是更好嗎?
因此終極省法出現了! 匿名類別物件

public MyActivity extends Activity{
    private TextView textView1;
    private TextView textView2;

    public void onCreate(){
        button1 = (Button)findViewById(R.id.btn1);
        button2 = (Button)findViewById(R.id.btn2);
        textView1 = (TextView)findViewById(R.id.text_view1);
        textView2 = (TextView)findViewById(R.id.text_view2);
        button1.setOnClickListener(new OnClickListener(){
            public void onClick(View v){
                textView1.setText("textview1");
            }
        });
        button2.setOnClickListener(new OnClickListener(){
           public void onClick(View v){
               textView2.setText("textview2");
           }
        });
    }
}

整個世界乾淨多了!
現在你知道為什麼要這樣寫了嗎?

diousk:推~我想重點應該是:在不同情況該用什麼方法讓程式更簡潔~01/10 15:55
我想推樓上這句話
的確我們有時候必須考慮到很多種情況
來挑是否使用匿名類別物件
今天假設你有一百個Button 且 事件內容都相同 這種情況下
就不可能使用匿名類別物件了
因為你會寫到瘋掉

Button[] button = new Button[100];
buttton[0].setOnClickListener(new OnClickListener(){
    public void onClick(View v){
       textView.setText("hello");
    }
});
buttton[1].setOnClickListener(new OnClickListener(){
    public void onClick(View v){
       textView.setText("hello");
    }
});
...100次
你會說 反正複製貼上而已 很快!
那萬一今天你想修改事件內容呢? 你會改到瘋掉

所以比較好的做法反而是之前的宣告一個事件物件
然後用for迴圈去註冊事件

private OnClickListener mOnClickListener = new OnClickListener(){
    public void onClick(View v){
         textView.setText("ya");
    }
};
for(int i=0;i<button.length;i++){
    button[i].setOnClickListener(mOnClickListener);
}

如果你想改事件, 那麼就直接改裡面的事件囉,
所以看情況來決定使用的方法才是一個重點!


PS 程式碼沒編譯過 我只是憑印象打出來的
因此如果有小錯誤出現 請看錯誤訊息作修正或者提醒我一下吧 感謝:)


--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.221.115.4
terrybob:這篇很值得m的…對於新手的我來說,受教不少…1F 01/10 11:20
Eior:推一個2F 01/10 11:48
jain00:請m一下,筆記中3F 01/10 12:36
mamaya3:寫得真清楚..我也是用了好一陣子才悟懂其中的意義XD4F 01/10 14:21
diousk:推~我想重點應該是:在不同情況該用什麼方法讓程式更簡潔~5F 01/10 15:55
※ 編輯: givemepass      來自: 61.221.115.4         (01/11 10:23)
kenliner:寫的好棒、只能說 這就是經驗。6F 01/12 16:35
godpro:抄筆記中...7F 01/13 22:36

--
※ 看板: FW 文章推薦值: 0 目前人氣: 0 累積人氣: 1125 
※ 本文也出現在看板: BadApple
作者 givemepass 的最新發文:
  • +37 [新聞] 部落少女深夜遭父強姦 隔天一早...拿刀 - Gossiping 板
    作者: 61.224.86.33 (台灣) 2013-06-18 14:24:33
    1.媒體來源: ETtoday國際新聞| ETtoday 新聞雲 2.完整新聞標題/內文: 部落少女深夜遭父強姦 隔天一早...拿刀割下爸爸人頭 國際中心/綜合報導 文明?野蠻?巴布亞新幾內亞一名18 …
    60F 37推
  • +40 [新聞] 台灣網友,一個月上線23.5小時 - Gossiping 板
    作者: 1.170.124.32 (台灣) 2013-05-23 14:25:35
    1.媒體來源: 時報資訊 2.完整新聞標題/內文: 台灣網友,一個月上線23.5小時 時報記者莊丙農台北報導 創市際ARO公佈comScore Media Metrix台灣2013年4月網路流量報告, …
    81F 44推 4噓
  • +5 Re: [問題] onClickListener的事件處理? - AndroidDev 板
    作者: 61.221.115.4 (台灣) 2012-01-10 16:41:50
    我也來提供一些本身研究過的經驗好了, 有時候不知道你會不會出現一些疑問? 當你為一些元件加入事件以後, 而這些元件產生變化的時候, 為什麼系統會知道是哪一個元件產生變化的呢? 其實他是由一種設計模式產 …
    6F 5推
  • +5 Re: [問題] onClickListener的事件處理? - AndroidDev 板
    作者: 61.221.115.4 (台灣) 2012-01-10 10:38:24
    假設你有兩個元件要建立事件 也許你會這樣做 button1 = (Button)findViewById(R.id.btn1); button2 = (Button)findViewById(R.id …
    7F 5推
  • +38 [好雷] 啟動原始碼-用source code看Source Code - movie 板
    作者: 61.221.115.4 (台灣) 2011-04-25 10:31:46
    class Task extends TimerTask { public void run() { //計時八分鐘 } } public class SourceCode { //建立一個Sean …
    56F 38推
點此顯示更多發文記錄
分享網址: 複製 已複製
qwan 轉錄至看板 BadApple (使用連結) 時間:2012-01-28 01:54:47
r)回覆 e)編輯 d)刪除 M)收藏 ^x)轉錄 同主題: =)首篇 [)上篇 ])下篇