Android使用Callback做為傳遞資料/通知的方法
在一個常見的實作上的情境:當使用者在執行某個行為之後,就執行某些行為。例如當API接收成功之後就跳轉到某個頁面,API接收失敗的時候顯示錯誤訊息,除了可以使用BroadcastReceiver,另外也可以使用Callback的方式達成。
以App常見的實作功能-接收API為例,實作的方式如下:
1.先建立一個Interface。
首先在interface裡面製作兩個function,一個是執行結束要執行的行為:loadComplete(),另一個是顯示訊息:showMsg(String msg)
2.在觸發行為的class裡產生Callback實體。
舉例來說,如果是在API執行之後一定會有該API自己所屬的成功/失敗callback function(或稱method),也就是如果API接收成功了就執行某個function(以Volley來看是onResponse()),而失敗了就執行某個function(以Volley來看是onError())。
於是就可以在Volley的onResponse()加入interface裡的loadComplete(),而在onError()加入showMsg(String msg)
3.在等待結果發生的class加入實作Callback
假設有個用來讀取API的Class(可能是使用者可以看得到的前景Activtiy/Fragment,也有可能是背景執行的程式),在API讀取結束之前都會一直等待結果,而這個Class就要實作想執行的Callback。
在此先以一個做為等待API的Activity為例, 在等待API的過程中加入了等待中的ProgressDialog,實作的方式是在Activity加上implements ApiCallback即可。而加入implements ApiCallback之後,Android Studio也會自動提醒我們有兩個未實作的callback method,可以直接在這個Class裡面直接按右鍵,選擇"Generate"→"Implement Methods"(快速鍵: ctrl+ i),就可以自動產生callback method了,然後就在所屬的callback method裡加入自己想要執行的內容。
此外,在Callback的實作過程有可能會遇到觸發的Class沒有產生Callback實體的情況,而導致下列的錯誤訊息,
所以在產生callback實體時,有可能會有需要下列幾種情境去解決:
如果Fragmenet是觸發行為的class,而Activity為實作callback method的class
因為Fragment是依附在Activity裡面,所以將Fragment的生命週期在onAttach()時傳入的context,強制轉型為自訂的interface的方式來做為reference。其自訂的interface一樣先以本篇中的ApiCallback為例。
如果Activity是觸發行為的class,而其他的某一個Activity為實作callback method的class
如果Activity是觸發行為的class,而其所屬的Fragment為實作callback method的class
以App常見的實作功能-接收API為例,實作的方式如下:
1.先建立一個Interface。
首先在interface裡面製作兩個function,一個是執行結束要執行的行為:loadComplete(),另一個是顯示訊息:showMsg(String msg)
/** * Api執行完之後的callback */ public interface ApiCallback { void showMsg(String msg); //要顯示的訊息 void loadComplete(); //api執行完成 }
2.在觸發行為的class裡產生Callback實體。
舉例來說,如果是在API執行之後一定會有該API自己所屬的成功/失敗callback function(或稱method),也就是如果API接收成功了就執行某個function(以Volley來看是onResponse()),而失敗了就執行某個function(以Volley來看是onError())。
於是就可以在Volley的onResponse()加入interface裡的loadComplete(),而在onError()加入showMsg(String msg)
public class MyApi{ public ApiCallback mCallback; public DailyNewsApi(Context context) { this.mContext = context; mCallback = (ApiCallback) mContext; } @Override public void onError(VolleyError error) { super.onError(error); mCallback.showMsg("登入失敗"); //傳送失敗訊息內容 } @Override public void onResponse(String response) { onResponse(response); mCallback.loadComplete(); //傳送讀取結束之後要呼叫執行的method } }
3.在等待結果發生的class加入實作Callback
假設有個用來讀取API的Class(可能是使用者可以看得到的前景Activtiy/Fragment,也有可能是背景執行的程式),在API讀取結束之前都會一直等待結果,而這個Class就要實作想執行的Callback。
在此先以一個做為等待API的Activity為例, 在等待API的過程中加入了等待中的ProgressDialog,實作的方式是在Activity加上implements ApiCallback即可。而加入implements ApiCallback之後,Android Studio也會自動提醒我們有兩個未實作的callback method,可以直接在這個Class裡面直接按右鍵,選擇"Generate"→"Implement Methods"(快速鍵: ctrl+ i),就可以自動產生callback method了,然後就在所屬的callback method裡加入自己想要執行的內容。
public class LoadingActivity extends Activity implements ApiCallback { private ProgressDialog progressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.loading); progressDialogInit(); //Loading對話框初始化 progressDialog.show(); //顯示Loading對話框 } @Override public void showMsg(String msg) { progressDialog.dismiss(); //關閉Loading對話框 Toast.makeText(LoadingActivity.this, msg, Toast.LENGTH_SHORT).show(); //利用收到的訊息String直接產生在Toast上 } @Override public void loadComplete() { progressDialog.dismiss(); //關閉Loading對話框 gotoNextPage(); //執行完之後到下一個頁面 } /** * 進度對話框初始化 */ private void progressDialogInit() { progressDialog = new ProgressDialog(LoadingActivity.this); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressDialog.setMessage("請稍候..."); progressDialog.setCanceledOnTouchOutside(false); } }
此外,在Callback的實作過程有可能會遇到觸發的Class沒有產生Callback實體的情況,而導致下列的錯誤訊息,
java.lang.NullPointerException: Attempt to invoke interface method 'void tw.com.ukyo.ApiCallback.loadComplete()' on a null object reference
所以在產生callback實體時,有可能會有需要下列幾種情境去解決:
如果Fragmenet是觸發行為的class,而Activity為實作callback method的class
因為Fragment是依附在Activity裡面,所以將Fragment的生命週期在onAttach()時傳入的context,強制轉型為自訂的interface的方式來做為reference。其自訂的interface一樣先以本篇中的ApiCallback為例。
public class MyFragment extends Fragment{ public ApiCallback callback; @Override public void onAttach(Context context) { super.onAttach(context); callback = (ApiCallback) context; //產生callback實體 } }
如果Activity是觸發行為的class,而其他的某一個Activity為實作callback method的class
/** * 觸發行為端的Activity */ public class MyActivity extends Activity{ public ApiCallback callback; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); callback = new ImplementActivty(); } }
/** * 實作callback端的Activity */ public class ImplementActivty extends Activity implements ApiCallback{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.implement_activty); } @Override public void showMsg(String msg) { //Do something in this method... } @Override public void loadComplete() { //Do something in this method... } }
如果Activity是觸發行為的class,而其所屬的Fragment為實作callback method的class
/** * 觸發行為端的Activity */ public class MyActivity extends Activity{ public ApiCallback callback; public MyFragment fragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); callback = (ApiCallback)fragment;//產生callback實體 } }
public class MyFragment extends Fragment implements ApiCallback{ @Override public void showMsg(String msg) { //Do something in this method... } @Override public void loadComplete() { //Do something in this method... } }
留言
張貼留言