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

先上概念......

什么是回调函数?

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

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

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

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

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


【Android归纳】回调机制在Android中的应用与实战的更多相关文章

  1. 弄明白Android 接口回调机制

    以前对于这个机制理解不够深刻,现在重新整理下思路. 一.建模 我理解的接口回调就是,我这个类实现了一个接口里的方法doSomething,然后注册到你这里,然后我就去做别的事情去了,你在某个触发的时机 ...

  2. JAVA和Android的回调机制

    本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273),请尊重他人的辛勤劳动成果,谢谢 以 前不理解什么叫回 ...

  3. Android接口回调机制

    开发中,接口回调是我们经常用到的. 接口回调的意思即,注册之后并不立马执行,而在某个时机触发执行. 举个例子: A有一个问题不会,他去问B,B暂时解决不出来,B说,等我(B)解决了再告诉你(A)此时A ...

  4. 关于android接口回调机制

    http://www.cnblogs.com/JohnTsai/p/3975022.html http://www.zhihu.com/question/19801131 In my previous ...

  5. android 利用反射机制获取drawable中所有的图片资源

    public List<Map<String,Object>> getGridData() { list=new ArrayList<Map<String,Obje ...

  6. MTK Android 回调机制[CallBack]

    具体步骤: 一.建模 回调函数的关键是:将一段代码作为参数传递,而这段代码将会在某个时刻被执行 我理解的接口回调就是,我这个类实现了一个接口里的方法doSomething,然后注册到你这里,然后我就去 ...

  7. Android的回调

    学了两三周的安卓了,最先开始是看mars老师的视频,看了一两天结合慕课网上的一些安卓视频,到现在算是有点入门了. 安卓立用得比较多的回调函数有点不明是怎么实现的,网上找了一些资料,结合自己的实践,总算 ...

  8. 【原创】源码角度分析Android的消息机制系列(一)——Android消息机制概述

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.为什么需要Android的消息机制 因为Android系统不允许在子线程中去访问UI,即Android系统不允许在子线程中更新UI. 为什 ...

  9. Android内存管理篇 - 从updateOomAdjLocked看lowmemorykiller之外的Android进程回收机制

    提起android的进程回收机制,大家所熟知的是Android的lowmemroykiller的机制.当系统可用内存低于某个阀值时,即会杀死这个阀值对应的Adj值的所有应用.但是本篇文章并为是要介绍L ...

随机推荐

  1. 深入理解java虚拟机---垃圾收集器和分配策略-1

    博文重点: 学习目标:哪些内存需要回收 什么时候回收    如何回收 在基于概念讨论的模型中,主要对Java堆和方法区进行讨论. why?:一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个 ...

  2. C/S模型:TCP,UDP构建客户端和服务器端(BIO实现

    Java中提供了socket编程来构建客户端和服务器端 TCP构建服务器端的步骤:(1)bind:绑定端口号(2)listen:监听客户端的连接请求(3)accept:返回和客户端连接的实例(4)re ...

  3. MySQL ORDER BY IF() 条件排序

    源 在做sqlzoo的时候,碰到一个SQL的排序问题,他把符合条件的单独几行,可以放在查询结果的开始,或者查询结果的尾部 通过的方法就是IN语句(也可以通过IF语句) 自己做了个测试,如下,这个是表的 ...

  4. 卸载钩子 UnhookWindowsHookEx

    The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindow ...

  5. anchor box聚类

    fast rcnn和rfcn中使用的都是默认的anchor box设置,都是9种,比例为0.5 .1. 2,大小为128.256.512.但我的数据集的gt框更小,需要找到适合我的数据集的anchor ...

  6. Drop和Truncate与Delete的区别

    1.Drop DROP TABLE test; 删除表test,并释放空间,将test删除的一干二净.(结构也被完全删除) 2.Truncate TRUNCATE test; 删除表test里的内容, ...

  7. [实现] 利用 Seq2Seq 预测句子后续字词 (Pytorch)2

    最近有个任务:利用 RNN 进行句子补全,即给定一个不完整的句子,预测其后续的字词.本文使用了 Seq2Seq 模型,输入为 5 个中文字词,输出为 1 个中文字词.目录 关于RNN 语料预处理 搭建 ...

  8. Android实战简易教程-第四十九枪(两种方式实现网络图片异步加载)

    加载图片属于比较耗时的工作,我们需要异步进行加载,异步加载有两种方式:1.通过AsyncTask类进行:2.通过Handler来实现,下面我们就来看一下如何通过这两种方式实现网络图片的异步加载. 一. ...

  9. BZOJ 2055 80人环游世界 有上下界最小费用可行流

    题意: 现在有这么一个m人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家.    因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为1...N.假若第 ...

  10. AC手动机 [原创]

    题目背景 Monster_Qi 又双叒叕拿到了rank1! 在开心之余他决定帮助蒟蒻floatiy拿到合适的排名. 题目描述 已知考试有n道题,每道题有num个测试点,有m个人 b[x,i,j](01 ...