Android零基礎入門第35節:Android中基於回調的事件處理

通過前面兩期掌握瞭Android中基於監聽的事件處理的五種形式,那麼本期一起來學習Android中基於回調的事件處理。

一、基於回調的事件處理概述

基於監聽的事件處理機制,簡單說就是為事件源(組件)添加一個監聽器,然後當用戶觸發瞭事件後交給監聽器去處理,根據不同的事件執行不同的操作。那麼基於回調的事件處理機制又是什麼樣的原理呢?

對於基於回調的事件處理模型來說,事件源與事件監聽器是統一的,或者說事件監聽器完全消失瞭。當用戶在GUI組件上激發某個事件時,組件自己特定的方法將會負責處理該事件。

為瞭實現回調機制的事件處理,Android為所有GUI組件都提供瞭一些事件處理的回調方法,以View為例,該類包含如下方法。

  • boolean onKeyDown(int keyCode, KeyEvent event):當用戶在該組件上按下某個按鍵時觸發該方法。

  • boolean onKeyLongPress(int keyCode, KeyEvent event):當用戶在該組件上長按某個按鍵時觸發該方法。

  • boolean onKeyShortcut(int keyCode, KeyEvent event):當一個鍵盤快捷鍵事件發生時觸發該方法。

  • boolean onKeyUp(int keyCode, KeyEvent event):當用戶在該組件上松開某個按鍵時觸發該方法。

  • boolean onTouchEvent(MotionEvent event):當用戶在該組件上觸發觸摸屏事件時觸發該方法。

  • boolean onTrackballEvent(MotionEvent event):當用戶在該組件上觸發軌跡球事件時觸發該方法。

  • void onFocusChanged(boolean gainFocus, int direction, Rect previously FocusedRect):當組件的焦點發生改變時觸發該方法。和前面的6個方法不同,該方法隻能夠在View中重寫。

    二、示例1

    接下來通過一個簡單的示例程序來學習基於回調的事件處理。

    繼續使用WidgetSample工程,在src/main/java的包com.jinyu.cqkxzsxy.android.widgetsample.view下新建一個MyButton.java文件,其代碼如下:

    package com.jinyu.cqkxzsxy.android.widgetsample.view;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.widget.Button;
    import android.widget.Toast;
    
    /**
     * @創建者 鑫鱻
     * @描述 Android零基礎入門到精通系列教程,歡迎關註微信公眾號ShareExpert
     */
    public class MyButton extends Button {
        // 構造方法
        public MyButton(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        // 重寫 onTouchEvent觸碰事件的回調方法
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
            // 消息提示
            Toast.makeText(getContext(), "MyButton回調onTouchEvent方法", Toast.LENGTH_SHORT).show();
    
            // 返回true,表明該事件不會向外擴散
            return true;
        }
    }

    關於裡面的代碼不懂也沒有關系,後續會詳細進行學習的。到res/layout/目錄下創建一個mybutton_layout.xml文件,用戶界面非常簡單,引用自定義的按鈕文件,代碼如下:

    
    
        
    
    

    上面程序中的代碼在XML界面佈局文件中使用MyButton組件,接下來Java程序無須為該按鈕綁定事件監聽器——因為該按鈕自己重寫瞭 onTouchEvent方法,這意味著該按鈕將會自己處理相應的事件。

    然後在java包下創建EventCallbackActivity.java文件,加載上面新建的佈局文件,,具體代碼如下:

    package com.jinyu.cqkxzsxy.android.widgetsample;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    
    
    public class EventCallbackActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.mybutton_layout);
        }
    }

    修改啟動的Activity,然後運行程序,點擊按鈕,可以看到下圖所示界面提示效果。

    三、示例2

    通過上面的學習不難發現,對於基於監聽的事件處理模型來說,事件源和事件監聽器是分離的,當事件源上發生特定事件時,該事件交給事件監聽器負責處理;對於基於回調的事件處理模型來說,事件源和事件監聽器是統一的,當事件源發生特定事件時,該事件還是由事件源本身負責處理。

    幾乎所有基於回調的事件處理方法都有一個boolean類型的返回值,該返回值用於標識該處理方法是否能完全處理該事件。

    • 如果處理事件的回調方法返回true,表明該處理方法己完全處理該事件,該事件不會傳播出去。

    • 如果處理事件的回調方法返回false,表明該處理方法並未完全處理該事件,該事件會傳播出去。

      對於基於回調的事件傳播而言,某組件上所發生的事件不僅會激發該組件上的回調方法, 也會觸發該組件所在Activity的回調方法——隻要事件能傳播到該Activity。

      接下來通過對上述示例程序進行適當修改,自定義的MyButton類的代碼文件如下:

      package com.jinyu.cqkxzsxy.android.widgetsample.view;
      
      import android.content.Context;
      import android.util.AttributeSet;
      import android.view.MotionEvent;
      import android.widget.Button;
      import android.widget.Toast;
      
      /**
       * @創建者 鑫鱻
       * @描述 Android零基礎入門到精通系列教程,歡迎關註微信公眾號ShareExpert
       */
      public class MyButton extends Button {
          // 構造方法
          public MyButton(Context context, AttributeSet attrs) {
              super(context, attrs);
          }
      
          // 重寫 onTouchEvent觸碰事件的回調方法
          @Override
          public boolean onTouchEvent(MotionEvent event) {
              super.onTouchEvent(event);
              // 消息提示
              Toast.makeText(getContext(), "MyButton回調onTouchEvent方法", Toast.LENGTH_SHORT).show();
      
              // 返回false,表明該事件會向外擴散
              return false;
          }
      }

      然後對EventCallbackActivity界面交互的代碼進行修改,如下所示:

      package com.jinyu.cqkxzsxy.android.widgetsample;
      
      import android.os.Bundle;
      import android.support.v7.app.AppCompatActivity;
      import android.view.MotionEvent;
      import android.view.View;
      import android.widget.Button;
      import android.widget.Toast;
      
      public class EventCallbackActivity extends AppCompatActivity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.mybutton_layout);
      
              // 獲取自定義按鈕的實例對象
              Button myButton = (Button) findViewById(R.id.mybutton);
      
              // 為自定義按鈕綁定事件監聽器
              myButton.setOnTouchListener(new View.OnTouchListener() {
                  @Override
                  public boolean onTouch(View view, MotionEvent motionEvent) {
                      // 消息提示
                      Toast.makeText(EventCallbackActivity.this,
                              "Activity收到onTouch事件監聽", Toast.LENGTH_SHORT).show();
                      // 返回false,表明該事件會繼續向外擴散
                      return false;
                  }
              });
          }
      
          // 重寫onTouchEvent觸碰事件的回調方法
          @Override
          public boolean onTouchEvent(MotionEvent event) {
              super.onTouchEvent(event);
              // 消息提示
              Toast.makeText(EventCallbackActivity.this,
                      "Activity回調onTouchEvent方法", Toast.LENGTH_SHORT).show();
              // 返回false,表明未完成處理該事件,該事件會繼續向外擴散
              return false;
          }
      }

      重新運行該程序,點擊按鈕後,可以看到界面先後彈出三條提示消息,分別如下圖所示。

      從上圖可以看出,當點擊按鈕時,Android系統最先觸發的應該是該按鈕上綁定的事件監聽器,然後才觸發該按鈕提供的事件回調方法,最後還會傳播到該按鈕所在的Activity。

      如果我們讓任何一個事件處理方法返回瞭 true,那麼該事件將不會繼續向外傳播。如將上述代碼中按鈕綁定的事件監聽器中返回true,運行程序發現隻能收到onTouch事件監聽。

      對比Android提供的兩種事件處理模型,可發現基於監聽的事件處理模型具有更大的優勢。

      • 基於監聽的事件處理模型分工更明確,事件源、事件監聽器由兩個類分幵實現,具有更好的可維護性。

      • Android的事件處理機制保證基於監聽的事件監聽器會被優先觸發。

You May Also Like