摘自:http://baibig.me/2015/04/15/Android-java%E5%9B%9E%E8%B0%83%E6%9C%BA%E5%88%B6%E4%B8%8E%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95/
编程分为两类:系统编程(system programming)和应用编程(application programming)。所谓系统编程,简单来说,就是编写库;而应用编程就是利用写好的各种库来编写具某种功用的程序,也就是应用。系统程序员会给自己写的库留下一些接口,即API(application programming interface,应用编程接口),以供应用程序员使用。所以在抽象层的图示里,库位于应用的底下。
当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。
打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为登记回调函数(to register a callback function)。
如下图所示(图片来源:维基百科):
可以看到,回调函数通常和应用处于同一抽象层(因为传入什么样的回调函数是在应用级别决定的)。而回调就成了一个高层调用底层,底层再回过头来调用高层的过程。(我认为)这应该是回调最早的应用之处,也是其得名如此的原因。
在Java中,是通过接口和内部类实现回调功能的。android中经常会用到内部类方式的监听接口,如按钮中的onClickListener等,内部类接口中会用到回调方法;同时在多线程操作中,子线程进行耗时操作时,如向服务器发送请求,服务器的数据响应是无法进行的,这时候需要利用java的回调机制解决问题,通过重写回调方法获取请求结果。
这里以网络下载为例,封装一个网络下载类,并且实现自定义接口回调方法。
先建立一个接口:
1 2 3 4 | public interface HttpCallBackListener{ void onFinish(String respose); void onError(Exception e); } |
建立封装的网络操作类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | public class HttpUtil{ public static void sentHttpRequest(final String address,final HttpCallBackListener listener){ new Thread(new Runable(){ public void run(){ HttpConnection connection=null; try{ URL url=new URL(address); connection=(HttpConnection)url.openConnection(); connection.setRequestMode("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setDonInput(true); connection.setDoOutput(true); InputStream in=connection.getInputStream(); BufferReader br=new BufferReader(new InputStreamReader(in)); StringBuilder sb=new StringBuilder(); String line; while((line=br.readLine())!=null){ sb.append(line); } if(listener!=null){ //回调onFinish方法 listener.onFinish(response); } catch(Exception e){ if(listenen!=null){ listener.onError(); } final{ if(connection!=null){ connection.disconnect(); } } } } } }).start(); } } |
在mainActivity活动中使用工具类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); final Handler handler =new Handler(){ @Override public void handleMessage(Message msg) { if(msg.what==1){ String info =(String) msg.obj; Toast.makeText(getApplicationContext(), ""+info, Toast.LENGTH_SHORT).show(); } } }; HttpUtil.sendHttpRequest("http://www.baidu.com",new HttpCallbackListener(){ public void onFinish(String response) { System.out.println(response); Message msg =handler.obtainMessage(); msg.what=1; msg.obj=response; handler.sendMessage(msg); }; public void onError(Exception e) { System.out.println("系统出错:"+e.toString()); }; }); } |
上面代码中通过HttpUtils工具类的sendHttpRequest()方法,传递一个网址参数,通过子线程操作执行数据下载,然后通过重写接口实例,重写接口方法,获取了之前操作的结果;然后将结果通过Handler发送消息,当handler触发handMessage回到方法的时候,就可以获取最终的效果!整个过程用到了接口回调机制和之前常用的监听器效果大同小异,非常有助于理解android的事件回调机制和匿名内部类的使用。