【Android归纳】回调机制在Android中的应用与实战
回调这样的思想在程序中是比較普遍的。有时候可能我们并没有注意到。近期整理了一些对于回调的理解,分享给大家
先上概念......
什么是回调函数?
回调函数就是一个通过函数指针调用的函数。
假设你把函数的指针(地址)作为參数传递给还有一个函数,当这个指针被用来调用其所指向的函数时。我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
好吧,我们还是先讲一个小故事来缓解一下紧张的氛围:(事实上就是举个形象的小样例)
你到一个商店买东西。刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个样例里,你的电话号码就叫回调函数。你把电话留给店员就叫登记回调函数。店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数。你到店里去取货叫做响应回调事件。事实上这就是一种“异步+回调”的编程模式。
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:第一次比較像样的写了点东西,当中也參考了非常多资料。感觉写出一篇好博客也是挺费时费力的,有什么问题的话,希望大家轻拍。多多评论。多多交流
最新文章
- 在VisualStudio 编辑器文本替换中使用正则表达式
- BeanDefinitionStoreException
- C# POST Https请求的一些坑
- supersr--NSURLConnection iOS2.0苹果原生请求
- ios之VFL的补充(三)
- ext树表
- PHP判断用户所在国家并跳转对应的目录
- Android批量插入数据到SQLite数据库
- C# 面向对象编程的继承性-多继承
- protractor protractor.conf.js [launcher] Process exited with error code 1 undefined:1190
- Subway POJ 2502
- CSS 设计模式一 元素
- oracle中文支持
- 2025战略,中秋送福利!免费开源ERP Odoo Windows 一键傻瓜式安装版发布
- 大坑啊oracle的隐式转换
- qemu无界面启动,并重定向输出到终端
- 深入解析 composer 的自动加载原理 (转)
- HTML charset 网页编码设定
- spring boot将jar包转换成war包发布
- Mac Terminal终端光标的快捷键操作