回調就是A和B有合做關係,A的某一個環節須要B本身告訴A要怎麼作,這就是回調,回調必定有接口)android
咱們知道回調在安卓裏面隨處可見,好比,一個按鈕的點擊事件canvas
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 好比最簡單的Button或者TextView的點擊事件setOnClickListener,這個就是回調 findViewById(R.id.mTv).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); } }
.
.
接下來咱們看一下 setOnClickListener 的源碼,再看看備註
人家google說了,這個方法是一個回調,人家是 callback網絡
回調必定有接口ide
.
.
(基本上各類帶setOnClickListener都是回調,各類監聽都是回調)工具
看完這個,咱們來簡單做證一下咱們的結論。佈局
請出結論:this
回調就是A和B有合做關係,A的某一個環節須要B本身告訴A要怎麼作,這就是回調(回調必定有接口google
在上面說的小例子中,View就是咱們說的A,而咱們的MainActivity就是咱們說的B(TextView繼承自View這個咱們就都知道了),那麼咱們點擊了B以後咱們想作點什麼事這個只有B本身知道,A確定不知道B想幹嗎,,而後A裏面確定會有本身的邏輯來根據B的只是去幹活,因此啊,就是——「A的某一個環節須要B本身告訴A要怎麼作」
A裏面既然有一個有一個能夠被回調的方法,那麼A裏面必定有一個接口。url
只要寫過自定義控件的,就必定寫回調。這個是天然的,本文的意義是爲了簡單描述對回調的一個理解。設計
其實作回調很好,好比咱們作了一個自定義的進度條,按鈕,或者開關等等,咱們都須要作回調接口,有什麼好處呢?可讓使用咱們控件的人本身去選擇一些事情,而不是咱們寫接口的吧東西給寫死了,咱們能夠提供一些方法,讓別人本身選擇顏色,大小,數值等等。
咱們假設作了一個自定義的開關按鍵,而後按下以後就能夠改變一下另一個控件的文字。(只爲演示,不作開關,省得代碼偏長)
點擊以後調用者要執行一些邏輯,至於具體執行什麼邏輯,一點都不關咱們事,這是使用咱們控件的人本身想幹嗎就去幹嘛。
上代碼:
一個簡單自定義控件
/** * 一個自定義開關按鈕(假設),附帶set點擊的接口 * 第一步,定義接口,接口裏面有個 設置點擊的監聽 * 第二步,在當前類中定義一個接口的變量,以便接受其餘類實現接口後傳過來的接口 * 第三步,噹噹前類中寫一個 public的設置接口的方法,參數是咱們寫的接口 * 第四步,在咱們的須要的地方執行其餘類要求咱們作的事情 */ public class DiyToggle extends View { private Bitmap mBackground; // 第二步,在當前類中定義一個接口的變量,以便接受其餘類實現接口後傳過來的接口 private OnToggleClickListener onToggleClickListener; public DiyToggle(Context context) { super(context); } public DiyToggle(Context context, AttributeSet attrs) { super(context, attrs); } public DiyToggle(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setBackground(int resId) { mBackground = BitmapFactory.decodeResource(getResources(), resId); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int measuredWidth = mBackground.getWidth(); int measuredHeight = mBackground.getHeight(); setMeasuredDimension(measuredWidth, measuredHeight); } @Override protected void onDraw(Canvas canvas) { // 畫背景 if (mBackground != null) { canvas.drawBitmap(mBackground, 0, 0, null); } } // 第三步,噹噹前類中寫一個 public的設置接口的方法,參數是咱們寫的接口 // 這樣其餘類一旦調用了setToggleClickListener,就必須實現咱們寫的接口 public void setToggleClickListener(OnToggleClickListener onToggleClickListener){ if(onToggleClickListener != null){ this.onToggleClickListener = onToggleClickListener; } } // 第一步,定義接口,接口裏面有個 設置點擊的監聽 interface OnToggleClickListener{ void onDoClick(); } // 第四步,在咱們的須要的地方執行其餘類要求咱們作的事情 // 這裏咱們複寫了系統自帶的onTouchEvent的up方法,也就是當點擊後鬆開手指時執行 // 咱們在鬆開手指後,就調用咱們本身接口的 onDoClick方法,具體作什麼,咱們不知道,也不用知道 // 其餘人說,咱們作就好。 @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if(action==MotionEvent.ACTION_UP){ onToggleClickListener.onDoClick(); } return true; } }
.
.
佈局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.amqr.callbackdemo.MainActivity"> <com.amqr.callbackdemo.DiyToggle android:id="@+id/mTog" android:layout_width="wrap_content" android:layout_height="wrap_content" > </com.amqr.callbackdemo.DiyToggle> <TextView android:id="@+id/mTvCenter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello" android:textSize="30dp" android:layout_centerInParent="true" /> </RelativeLayout>
.
.
MainActivity
public class MainActivity extends Activity { private DiyToggle mTog; private TextView mTvCenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTog = (DiyToggle) findViewById(R.id.mTog); mTvCenter = (TextView) findViewById(R.id.mTvCenter); mTog.setBackground(R.mipmap.tog); // 調用了DiyToggle的 setToggleClickListener 方法,就得實現 接口 mTog.setToggleClickListener(new DiyToggle.OnToggleClickListener() { @Override public void onDoClick() { Log.d("Tog","...================="); mTvCenter.setText("世界"); } }); } }
.
.
gif圖
.
.
像上面這樣子,就完成了 一個 回調 應用演示。
固然,你也能夠說我直接用你的在MainActivity裏面用mTog調用setOnClickListener方法不是同樣能夠上面的功能嗎!是的,沒錯,可是咱們這裏不是爲了實現功能,而是爲了簡單描述一下若是定義接口實現回調。
另外,像上面這樣是調單的演示,再往上一點點,咱們固然還能夠在寫接口時在onDoClick裏面添加參數,好比寫成 void onDoClick(DiyToggle diyToggle,Boolean toggleState); 這樣咱們就能夠在指定哪個 DiyToggle 變成 哪種開關狀態。
.
.
注意
最後幹活的仍是DiyToggle,至於爲何A最後爲何能讓文本改變,這就是系統自帶onTouchEvent裏面有一套複雜的安卓設計在裏面,有了它DiyToggle才能作這麼多事情。
代碼通常都是按照順序執行的,咱們要要作的,就是把MainActivity的裏面實現了接口的mTog交代的事情的,也就是onDoClick這個方法放在DiyToggle合適的位置,這樣一旦mTog調用了setToggleClickListener方法,那麼mTog交代事情就會被執行。
.
.
咱們如今使用Volley來訪問百度,而且把放回的網頁代碼顯示出來。
大概代碼是這樣子的:
MainAvtivity
public class MainActivity extends Activity { private TextView mTvRequest; private TextView mTvCode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTvRequest = (TextView) findViewById(R.id.mTvRequest); mTvCode = (TextView) findViewById(R.id.mTvCode); mTvRequest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 第一步,利用Volleynew出來一個請求隊列 RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this); // 第二步,建立一個請求 // 在這裏,咱們須要關心的就是請求究竟是成功仍是失敗。就這兩點。 // 能夠利用接口封裝起來。 StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @Override public void onResponse(String response) { Toast.makeText(MainActivity.this,"訪問成功",Toast.LENGTH_SHORT).show(); mTvCode.setText(response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(MainActivity.this,"訪問失敗",Toast.LENGTH_SHORT).show(); } }); // 第三步,把請求放進隊列 mQueue.add(stringRequest); } }); } }
.
.
佈局文件
效果實現了。根據上面的代碼,咱們使用了Volley作了一個請求網絡的簡單示例。在上面的代碼中,咱們看得出來,咱們須要關心的只是請求的成功或者失敗的結果,就這兩點,那麼,這個東西徹底能夠封裝起來。寫一個接口,進行回調。這就是咱們寫例子2的目的。
咱們來寫一個工具類,叫作VolleyHttpUtils,而後提供一個方法requestNet,這個requestNet方法除了傳入必要的url和context以外,還有一個參數是咱們本身定義的接口。
這樣外界一旦調用了這個方法就必須實現接口,實現接口以後外界想作什麼操做外界本身去決定,最後,在requestNet方法裏面真正去執行外界交待給咱們的任務。
逼逼了這麼多,仍是直接看代碼吧。
public class VolleyHttpUtils { // 外界除了傳入必要的url和上下文以外,最關鍵的就是要實現咱們的接口,這樣外界就能方便地交待工做給咱們 // 咱們不能把東西寫死,須要讓調用者有必定的自由,他具體想幹嗎讓他本身去具體發揮,而後真正工做的仍是咱們本身 public static void requestNet(String url,Context context , final OnHttpListener onHttpListener){ RequestQueue mQueue = Volley.newRequestQueue(context); StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() { @Override public void onResponse(String response) { // 外界實現接口交待的關於請求的成功的代碼在此處被真正執行 onHttpListener.onResponse(response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // 外界實現接口交待的關於請求的失敗的代碼在此處被真正執行 onHttpListener.onErrorResponse(error); } }); mQueue.add(stringRequest); } interface OnHttpListener{ void onResponse(String response); void onErrorResponse(VolleyError error); } }
.
.
MainActivity調用方式以下
public class MainActivity extends Activity { private TextView mTvRequest; private TextView mTvCode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTvRequest = (TextView) findViewById(R.id.mTvRequest); mTvCode = (TextView) findViewById(R.id.mTvCode); mTvRequest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String url = "https://www.baidu.com"; // requestNet方法須要傳入3個參數,這裏關鍵是實現接口,而後用戶就能夠只關心成功和失敗的部分 // 最後把工做扔給requestNet本身去作 VolleyHttpUtils.requestNet(url, MainActivity.this, new VolleyHttpUtils.OnHttpListener() { @Override public void onResponse(String response) { Toast.makeText(MainActivity.this,"訪問成功,使用回調",Toast.LENGTH_SHORT).show(); mTvCode.setText(response); } @Override public void onErrorResponse(VolleyError error) { Toast.makeText(MainActivity.this,"訪問失敗,使用回調",Toast.LENGTH_SHORT).show(); } }); } }); } }
看一下gif圖片,同樣能夠實現效果,利用這個簡單的demo咱們能夠更加理解接口和回調的工做關係了。
例子2的演示至此完成。
回調就是A和B有合做關係,A的某一個環節須要B本身告訴A要怎麼作,這就是回調(回調必定有接口)
其實最後的作事情的仍是A,只不過,A不能把事情給說死了,有一些東西,仍是要B說一說。
就好像,A是賣鞋子的,能夠整個一條龍生產,B是客戶,客戶老是有本身的個性的,A就弄了一個接口,(一張設計設計搭配圖),B拿了這個設計搭配圖,指定了鞋帶什麼顏色,鞋帽上什麼布料,最後工做仍是交給A來作。
本文完。