淺析回撥機制,這是一篇騷騷的文章

RobinGao發表於2017-11-01

序:

先給一個,我對回撥機制的認識:回撥就是我不知道你呼叫這個  具體  幹嘛,但是我知道你  大概  要幹嘛

比如點選,寫原始碼的人不知道點選按鈕之後登陸,還是彈出對話方塊,但是寫原始碼的人知道按鈕載入出來並且人的手觸控並抬起這個動作就是點選。

我們先不看android的點選事件,我們先自己做一個回撥。

第一章: 校長要去開會

想象一個場景(鄭重承諾,本例不針對任何一個人,只是舉例,如果引起不適,請關閉)

大家都上過學,學校的boss假設就是 校長 ,校長的工作是管理同學們好好學習,快樂成長。但是一個校長管理不過來好幾千名學生,所以要把工作分給 班主任教導處主任

一個學校總有那麼幾個調皮搗蛋的學生,那麼校長就得管管,管的方式假設有兩種說(talk)和打(fuck),但是校長沒時間,因為校長去開會了,就把任務交給班主任和教導處主任有可能還有別的老師。好了,校長在走之前先定義好了說和打的模組。

package TestCallBack;
/**
 * 校長類(關於類名我的英文水平就這樣,愛看不看)
 * @author Robin
 *
 */
public class XiaoZhang {

    //工作的引用
    DoJob mDoJob;

    //定義工作型別
    public interface DoJob {
        void talk(String teacherName);//說

        void fuck(String teacherName, String tool);//打
    }

    //對外暴露呼叫位置
    public void setmDoJobCallBack(String teacherName, String tool, DoJob doJob) {
        if (doJob != null) {
            doJob.talk(teacherName);//工作是-->說
            doJob.fuck(teacherName, tool);//工作是-->打
        }
    }

}
複製程式碼

第二章:校長走了,學生炸了,老師火了

校長走後,同學們為所欲為,班主任見狀不妙,馬上開始工作。

package TestCallBack;

import TestCallBack.XiaoZhang.DoJob;

/**
 * 班主任
 * 
 * @author Robin
 * 
 */
public class ClassTeacher implements DoJob {

    public void talk(String teacherName) {
        // 班主任開始跟學生交談
        System.out.println("班主任  "+teacherName + "  開始口頭教育學生");
    }

    public void fuck(String teacherName, String tool) {
        // 班主任開始幹學生
        System.out.println("班主任  "+teacherName + "  開始用  " + tool + "  打學生");
    }

}
複製程式碼

(宣告,我們不提倡打學生)

班主任:喂,校長嗎?我要管學生了
校長:好
於是校長就new 了一個物件,並把班主任傳進來,讓班主任管學生

XiaoZhang xz = new XiaoZhang();// 建立一個校長
xz.setmDoJobCallBack("李二狗", "教鞭", new ClassTeacher());
複製程式碼

log列印如下:(用eclipse怎麼了?誰不是從ec過來的。。。)
這裡寫圖片描述

教導主任管理學生同理:

package TestCallBack;

import TestCallBack.XiaoZhang.DoJob;

/**
 * 教導處主任
 * 
 * @author Robin
 * 
 */
public class JaoDaoChuTeacher implements DoJob {
    public void talk(String teacherName) {
        // 教導處主任開始跟學生聊天
        System.out.println("教導處主任  " + teacherName + "  開始口頭教育學生");
    }

    public void fuck(String teacherName, String tool) {
        // 教導處主任開始打學生
        System.out
                .println("教導處主任  " + teacherName + "  開始用  " + tool + "  打學生");
    }

}
複製程式碼

建立物件,並執行

XiaoZhang xz = new XiaoZhang();// 建立一個校長
xz.setmDoJobCallBack("蒙哥·卡恩", "斧頭", new JaoDaoChuTeacher());
複製程式碼

log列印如下:
這裡寫圖片描述

這個地方注意,如果我想改寫教導主任的talk,fuck方法,怎麼寫?

xz.setmDoJobCallBack("蒙哥·卡恩", "斧頭", new JaoDaoChuTeacher(){

            @Override
            public void talk(String teacherName) {
//              super.talk(teacherName);
                System.out.println(teacherName);//只列印教導主任的名字
            }

            @Override
            public void fuck(String teacherName, String tool) {
                super.fuck(teacherName, tool);//又想執行被教導主任打的方法
                System.out.println("被教導主任請去喝茶嗑瓜子");//打完之後又喝茶嗑瓜子
            }

        });
複製程式碼

注意super,呼叫父類的方法。
列印如下:
這裡寫圖片描述

第三章:校長回來了

校長髮現,效果並不好,學生還是很皮,於是,校長又另請高明,既不是教導處主任,也不是班主任,是一個新的角色,他叫robin,擅長用皮鞭,怎麼寫?
首先肯定是要有一個校長的同意,所以需要建立一個校長物件

XiaoZhang xz = new XiaoZhang();// 建立一個校長
xz.setmDoJobCallBack("robin", "皮鞭", new DoJob() {//注意這個地方是DoJob

            public void talk(String teacherName) {
                // TODO Auto-generated method stub
                System.out.println(teacherName + " 和我談話了");
            }

            public void fuck(String teacherName, String tool) {
                // TODO Auto-generated method stub
                System.out.println("艾媽,我被 " + teacherName + " 用 " + tool
                        + " 打了");
            }
        });
複製程式碼

log:
這裡寫圖片描述

完結。

最後讓我們再來審視一下,開頭我提出來的

回撥就是我不知道你呼叫這個 具體 幹嘛,但是我知道你 大概 要幹什麼。

校長讓座這個管理學生的工作,校長不知道具體是誰來做,怎麼做,但是校長知道管學生有說和打兩種方式。這個 就是所謂的 回撥函式

你以為結束了?看看右邊滾動條吧,孩子。這是開始,前面都是鋪墊。(Java程式設計師適當翻看下面內容。)
問題來了,回撥有個J8用?

最早開始,大家都知道我請求網路資料,一般都有兩個回撥方法
onSuccess
onFailed
沒錯,我就是用xUtils長大的。
上網查閱資料之後,這裡用到的網路回撥虛擬碼大概如下:

public static void sendHttpRequest(final String address,
            final HttpCallbackListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                ...//這裡用HttpUrlConnection取到資料
                    while ((line = reader.readLine()) != null) {//流轉換,得到字串
                        response.append(line);
                    }
                    if (listener != null) {
                        // 回撥onSuccess()方法,攜帶資料
                        listener.onSuccess(response.toString());
                    }
                } catch (Exception e) {
                    if (listener != null) {
                        // 回撥onFailed()方法,攜帶報錯資訊
                        listener.onFailed(e);
                    }
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
複製程式碼

我之前也是似懂非懂,現在感覺明白了不少。

你以為完了?
android用到了很多回撥機制,比如按鈕的點選事件、執行緒的run()方法
下面開始講Android裡面的回撥機制。 

這篇文章不錯,我引用一下,作者不要打我
juejin.im/entry/58c23…

裡面說到這兩個例子
1. 給RecyclerView的item新增點選事件

public class ClickAdapter extends RecyclerView.Adapter{
    //定義介面例項
    private OnClickItemListener mOnClickItemListener;

    //設定介面例項的setter方法
    public void setOnClickItemListener(OnClickItemListener onClickItemListener) {
        mOnClickItemListener = onClickItemListener;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { . . . }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) { . . . }

    @Override
    public int getItemCount() { . . . }

    public class ViewHolder extends RecyclerView.ViewHolder{
        // ...
        // 檢視控制元件初始化
        public ViewHolder(View itemView) { . . . }
        /*繫結檢視方法,在Adapter的onBindViewHolder中呼叫*/
        public void bindHolder(final String text) {
            mTextView.setText(text);
            if (null != mOnClickItemListener) {
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //在點選事件中進行回撥
                        mOnClickItemListener.onClick(text);
                    }
                });
            }
        }
    }
    //建立內部介面
    interface OnClickItemListener{
        void onClick(String text);
    }
}
複製程式碼

所以,介面回撥可以總結為以下4步:

  • 建立內部介面
  • 定義介面例項
  • 設定介面例項的setter方法
  • 在點選事件中進行回撥

2.用子執行緒載入網路圖片,並顯示在主執行緒中

public class ImageUtil {
    public static void loadeIamge(final String url, final LoadeImageListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                InputStream is = null;
                BufferedInputStream bis = null;
                try {
                    HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
                    connection.setConnectTimeout(5000);
                    connection.connect();
                    is = connection.getInputStream();
                    bis = new BufferedInputStream(is);
                    //拿到bitmap,通知(呼叫)onLoadeImageListener。
                    listener.onLoadeImageListener(BitmapFactory.decodeStream(bis));
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    CloseUtil.closeQuietly(is);
                    CloseUtil.closeQuietly(bis);
                }
            }
        }).start();
    }
    public interface LoadeImageListener {
         void onLoadeImageListener(Bitmap bitmap);
     }
}
複製程式碼

上面的程式碼就是一個載入網路圖片的工具類,可以發現在這裡,沒有定義介面例項,也沒有定義介面例項的setter方法,而是直接用呼叫者那裡傳來的介面例項進行操作。

下面來看看呼叫者的實現:

final ImageView imageView = (ImageView) findViewById(R.id.image_view);
       ImageUtil.loadeIamge(IMG_URL, new ImageUtil.LoadeImageListener() {
           @Override
           public void onLoadeImageListener(Bitmap bitmap) {
               imageView.setImageBitmap(bitmap);
           }
       });
複製程式碼

完。喜歡的點個贊,你的支援是我最大的動力。

相關文章