回调这样的思想在程序中是比較普遍的。有时候可能我们并没有注意到。近期整理了一些对于回调的理解,分享给大家

先上概念......

什么是回调函数?

回调函数就是一个通过函数指针调用的函数。

假设你把函数的指针(地址)作为參数传递给还有一个函数,当这个指针被用来调用其所指向的函数时。我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

好吧,我们还是先讲一个小故事来缓解一下紧张的氛围:(事实上就是举个形象的小样例)

你到一个商店买东西。刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个样例里,你的电话号码就叫回调函数。你把电话留给店员就叫登记回调函数。店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数。你到店里去取货叫做响应回调事件。事实上这就是一种“异步+回调”的编程模式。

java中是不同意对指针进行直接操作的。那我们怎样实现回调?

通过接口或者内部类来实现。

我们先看一个小样例吧。就是Android中随处可见的UI事件点击处理,我会从源代码角度来分析它是怎么实现接口回调的。

一般在代码中,我们会这样处理Button的点击事件:

能够这样

public class MainActivity extends Activity implements android.view.View.OnClickListener{

    private Button btn;

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(this);
} @Override
public void onClick(View v) {
ToastUtils.toast(this, "perform onclick"); }

能够这样

public class MainActivity extends Activity {

    private Button btn;

    private OnClickListener clickListener = new OnClickListener() {

        @Override
public void onClick(View v) {
ToastUtils.toast(getApplication(), "perform onclick"); } }; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(clickListener); }
}

也能够这样

public class MainActivity extends Activity {

    private Button btn;

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
ToastUtils.toast(getApplication(), "perform onclick"); }
} }

大家能够细致看看这三种方式的实现差别。

这里面的OnClickListener即为点击事件的回调接口。

我们能够看到View$OnClickListener.class中是这么定义OnClickListener接口的

 /**
* Interface definition for a callback to be invoked when a view is clicked.
*/
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}

然后,我们会继续查看View中与接口回调相关的方法,原因是

1、Button继承TextView

public class Button extends TextView {
public Button(Context context) {
this(context, null);
} ......
}

2、TextView继承View

public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
......
}

在View里面处理了回调

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {

    /**
* Interface definition for a callback to be invoked when a view is clicked.
*/
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
} /**
* Listener used to dispatch click events. This field should be made
* private, so it is hidden from the SDK. {@hide}
*/
protected OnClickListener mOnClickListener; /**
* Register a callback to be invoked when this view is clicked. If this view
* is not clickable, it becomes clickable.
*
* @param l The callback that will run
* @see #setClickable(boolean)
*/ public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
mOnClickListener = l;
} /**
* Call this view's OnClickListener, if it is defined.
*
* @return True there was an assigned OnClickListener that was called, false
* otherwise is returned.
*/
public boolean performClick() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK); mOnClickListener.onClick(this);
return true;
} return false;
}
}

通过类比我们能够这么理解

1、你到一个商店买东西,刚好你要的东西没有货(尚未触发点击事件,就是你还没有点击buttonbtn)。

2、于是你在店员那里留下了你的电话

电话号码就是回调接口。即上面的interface OnClickListener

你把电话留给店员就叫登记回调函数,即代码中的btn.setOnClickListener(..)

3、过了几天店里有货了(你点击了button,触发了回调关联的事件performClick),店员就打了你的电话,店员给你打电话叫做调用回调函数(mOnClickListener.onClick(this);)。前提是你的电话能够打通(if (mOnClickListener != null))

4、然后你接到电话后就到店里去取了货。你到店里去取货叫做响应回调事件,即在Activity中实现了onClick方法

接下来我们能够自己写个小样例总结一下主要的回调过程怎样实现:(能够忽视掉代码中跟本章内容无关的东西)

需求:从网络上获取数据,并将数据显示在listview上,这里我们使用AsyncTask完毕异步载入数据(通过线程休眠模拟数据载入延迟)

1、首先须要定义一个回调接口,这个回调接口中的方法会在特定的情况下触发,样例其中就是设置了数据获取成功或者失败的回调

public class MyAsyncTask extends AsyncTask<String, Integer, ArrayList<String>> {

    private QueryResultListener queryResultListener;

    private ArrayList<String> items;

    private ListActivity activity;

    private LoadingDialog mLoadingDialog;

    private boolean isCompleted;

    public MyAsyncTask(ListActivity activity) {
this.activity = activity;
} public void setQueryResultListener(QueryResultListener queryResultListener) {
this.queryResultListener = queryResultListener;
} @Override
protected void onPreExecute() {
mLoadingDialog = new LoadingDialog();
mLoadingDialog.show(activity.getFragmentManager(), "LOADING");
super.onPreExecute();
} @Override
protected ArrayList<String> doInBackground(String... params) {
items = loadData();
return items;
} @Override
protected void onPostExecute(ArrayList<String> result) {
isCompleted = true; if (mLoadingDialog != null) {
mLoadingDialog.dismiss();
}
if (activity != null) {
if (queryResultListener != null) {
if (result == null) {
queryResultListener.onQueryResultFailed();
} else {
queryResultListener.onQueryResultSuccess(result);
}
}
}
super.onPostExecute(result);
} public ArrayList<String> getItems(){
return items;
} private ArrayList<String> loadData() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
return new ArrayList<String>(Arrays.asList("接", "口", "回", "调", "详", "解"));
} private void notifyActivityTaskCompleted()
{
if (null != activity)
{
activity.onTaskCompleted();
}
} public interface QueryResultListener {
public void onQueryResultFailed(); public void onQueryResultSuccess(ArrayList<String> result);
} }

2、在ListActivity中实现回调接口的注冊与响应,即成功的话,刷新listview,失败的话,有一些提示等等

   MyAsyncTask myAsyncTask = new MyAsyncTask(this);
myAsyncTask.execute(); myAsyncTask.setQueryResultListener(new QueryResultListener() { @Override
public void onQueryResultSuccess(ArrayList<String> result) {
adapter.setItems(result);
} @Override
public void onQueryResultFailed() { }
});

今天的博客就到这里吧!

PS:第一次比較像样的写了点东西,当中也參考了非常多资料。感觉写出一篇好博客也是挺费时费力的,有什么问题的话,希望大家轻拍。多多评论。多多交流

demo源代码地址:https://github.com/feifei003603/CallBackDemo.git


最新文章

  1. 在VisualStudio 编辑器文本替换中使用正则表达式
  2. BeanDefinitionStoreException
  3. C# POST Https请求的一些坑
  4. supersr--NSURLConnection iOS2.0苹果原生请求
  5. ios之VFL的补充(三)
  6. ext树表
  7. PHP判断用户所在国家并跳转对应的目录
  8. Android批量插入数据到SQLite数据库
  9. C# 面向对象编程的继承性-多继承
  10. protractor protractor.conf.js [launcher] Process exited with error code 1 undefined:1190
  11. Subway POJ 2502
  12. CSS 设计模式一 元素
  13. oracle中文支持
  14. 2025战略,中秋送福利!免费开源ERP Odoo Windows 一键傻瓜式安装版发布
  15. 大坑啊oracle的隐式转换
  16. qemu无界面启动,并重定向输出到终端
  17. 深入解析 composer 的自动加载原理 (转)
  18. HTML charset 网页编码设定
  19. spring boot将jar包转换成war包发布
  20. Mac Terminal终端光标的快捷键操作

热门文章

  1. SQL条件语句(IF, CASE WHEN, IF NULL)
  2. CREATE TABLE - 定义一个新表
  3. js里的稀疏数组
  4. vue之package.json文件解析
  5. 00C#
  6. PHP 下基于 php-amqp 扩展的 RabbitMQ 简单用例 (四) -- Push API 和 Pull API
  7. left_v2.js
  8. 笔试算法题(19):判断两条单向链表的公共节点 &amp; 字符集删除函数
  9. 查看用户的信息文件-passwd
  10. Python学习-range的用法