赞
踩
一般来说,模块之间都存在一定的调用关系,从调用方式上看,可以分为三类同步调用、异步调用和回调。同步调用是一种阻塞式调用,即在函数A的函数体里通过书写函数B的函数名来调用之,使内存中对应函数B的代码得以执行。异步调用是一种类似消息或事件的机制解决了同步阻塞的问题,例如A通知B后,他们各走各的路,互不影响,不用像同步调用那样,A通知B后,非得等到B走完后,A才继续走。回调是一种双向的调用模式,也就是说,被调用的接口被调用时也会调用对方的接口,例如A要调用B,B在执行完又要调用A。
回调的思想是:
类A的a()方法调用类B的b()方法
类B的b()方法执行完毕主动调用类A的callback()方法
通俗而言: 就是A类中调用B类中的某个方法C, 然后B类中反过来调用A类中的方法D, D这个方法就叫回调方法, 这样子说你是不是有点晕晕的, 其实我刚开始也是这样不理解, 看了人家说比较经典的回调方式:
1.class A实现接口CallBack callback——背景1
2.class A中包含一个class B的引用b ——背景2
3.class B有一个参数为callback的方法f(CallBack callback) ——背景3
4.A的对象a调用B的方法 f(CallBack callback) ——A类调用B类的某个方法 C
5.然后b就可以在f(CallBack callback)方法中调用A的方法 ——B类调用A类的某个方法D
在C/C++中,要实现回调函数,被调用函数要告诉调用者自己的指针地址。但是Java没有指针地址,不能传递方法的地址,一般采用接口回调的方法来实现:把实现某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被调用类实现的接口的方法。
原理:首先创建一个回调对象,然后再创建一个控制器对象,将回调对象需要被调用的方法告诉控制器对象,控制器对象负责检查某个场景是否出现或某个条件是否满足,当满足时,自动调用回调对象的方法。
package Demon; //创建回调接口实现类 public class Boss implements AcceptListener{ public void acceptEvent(String result){ if(result.equals("ok")){ System.out.println("接受到了工作结果,老板很满意"); }else { System.out.println("接受到了工作结果,老板很生气!"); } } } class Manager implements AcceptListener{ public void acceptEvent(String result){ if(result.equals("ok")){ System.out.println("接受到了工作结果,经理很满意"); }else { System.out.println("接受到了工作结果,经理很生气!"); } } } class Tester implements AcceptListener{ public void acceptEvent(String result){ if(result.equals("ok")){ System.out.println("接受到了工作结果,测试很满意"); }else { System.out.println("接受到了工作结果,测试很生气!"); } } } //创建回调接口 interface AcceptListener { public void acceptEvent(String result); } //创建控制类,要持有回调接口 class Employee{ AcceptListener listener; public void setListener(AcceptListener listener) { this.listener = listener; } public void doWork(){ System.out.println("玩命工作中..."); if(listener!=null){ listener.acceptEvent("ok"); } } public void haveRest(){ System.out.println("工作太累了,需要休息一天"); if(listener!=null){ listener.acceptEvent("休息"); } } } //测试类 class TestMain{ public static void main(String[] args) { Employee employee = new Employee(); //创建控制器对象,将提供给他的回调对象传入 employee.setListener(new Boss()); //启动控制器对象运行 employee.doWork(); } }
设置接口就相对于设置一个用途,相当于可以将这个用途抽取出来供多个人可以使用,比较灵活
package com.example.intenttest; import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import androidx.annotation.NonNull; public class MyDialog extends Dialog implements View.OnClickListener{ Button btn1,btn2; EditText et; TextView waimainTv; interface OnEnsureListener{ public void onEnsure(String msg); } OnEnsureListener onEnsureListener; public void setListener(OnEnsureListener listener) { this.onEnsureListener = listener; } public MyDialog(@NonNull Context context) { super(context); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mydialog); //只要是调用的本类的方法或变量加不加this都一样。因为findViewById是MyDialog继承的方法 btn1=findViewById(R.id.dg_btn1); btn2=findViewById(R.id.dg_btn2); btn1.setOnClickListener(this); btn2.setOnClickListener(this); et=findViewById(R.id.dg_et); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.dg_btn1: String msg = et.getText().toString(); if(!TextUtils.isEmpty(msg)){ if(onEnsureListener !=null){ onEnsureListener.onEnsure(msg); } } break; case R.id.dg_btn2: cancel(); break; } } public void setTextView(TextView tv) { waimainTv=tv; } }
OnEnsureListener就是android系统所约好的接口,然后在我们写的应用程序中传入回调对象,这样就可以达到接口统一,实现不同的效果。
package com.example.intenttest; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; public class MainActivity2 extends AppCompatActivity { TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); tv=findViewById(R.id.tv); } public void onClick(View view){ switch (view.getId()){ case R.id.tv: MyDialog dialog = new MyDialog(this); dialog.show(); dialog.setListener(new MyDialog.OnEnsureListener() { @Override public void onEnsure(String msg) { Log.i("=====", "onEnsure: "+msg); tv.setText(msg); } }); break; } } }
点击确定后,点一下会变成你输入的内容
package com.example.intenttest; import android.os.AsyncTask; public class MyTask extends AsyncTask<String,Void,byte[]> { public interface CallBack{ public void onSuccess(byte[] bytes); public void onError(); } CallBack mCallBack; public void setCallBack(CallBack callBack) { mCallBack = callBack; } @Override protected byte[] doInBackground(String... params) { //进行子线程操作的函数 byte[] content = HttpUtils.getByteContent(params[0]); return content; } @Override protected void onPostExecute(byte[] bytes) { super.onPostExecute(bytes); //将字节数组转换为位图 if(bytes!=null&&bytes.length!=0){ mCallBack.onSuccess(bytes); }else { mCallBack.onError(); } } }
package com.example.intenttest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class HttpUtils { public static byte[] getByteContent(String path){ ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { try { HttpURLConnection conn=(HttpURLConnection) new URL(path).openConnection(); InputStream is = conn.getInputStream(); int hasRead=0; byte[] buf = new byte[1024]; while (true){ hasRead=is.read(buf); if(hasRead==-1){ //读完了,跳出循环,不读了 break; }else { baos.write(buf,0,hasRead); } } } catch (IOException e) { e.printStackTrace(); } }catch (Exception e){ e.printStackTrace(); } return baos.toByteArray(); } }
package com.example.intenttest; import androidx.appcompat.app.AppCompatActivity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; public class MainActivity2 extends AppCompatActivity { TextView tv,tv2; ImageView iv; String url="https://img1.baidu.com/it/u=378860652&size=w500&n=0&g=0n&f=jpeg?sec=1646658692&t=cbeca35343cf07495a91f56c444974ff"; String url2="https://www.163.com/news/article/GVE6NVOQ0001899N.html?clickfrom=w_lb_1_big"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); tv=findViewById(R.id.tv); tv2=findViewById(R.id.tv2); iv=findViewById(R.id.iv); } public void onClick(View view){ switch (view.getId()){ case R.id.tv: showDialog(); break; case R.id.tv2: MyTask myTask = new MyTask(); myTask.setCallBack(new MyTask.CallBack() { @Override public void onSuccess(byte[] bytes) { try { String s = new String(bytes, 0, bytes.length, "UTF-8"); tv2.setText(s); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } @Override public void onError() { tv2.setText("加载不到啊"); } }); myTask.execute(url2); break; case R.id.iv: showImage(); break; } } private void showImage() { MyTask task = new MyTask(); task.setCallBack(new MyTask.CallBack() { @Override public void onSuccess(byte[] bytes) { Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); iv.setImageBitmap(bitmap); } @Override public void onError() { iv.setImageResource(R.drawable.pc1); } }); task.execute(url); } private void showDialog() { MyDialog dialog = new MyDialog(this); dialog.show(); dialog.setListener(new MyDialog.OnEnsureListener() { @Override public void onEnsure(String msg) { Log.i("=====", "onEnsure: "+msg); tv.setText(msg); } }); } }
上面通过接口回调很灵活,不仅通过该接口可以实现图片的加载也可以实现网页数据的加载。
因为在到点击事件的时候设置接口(是new的),当传入到Mytask类里的时候,通过传过来的对象给当前的接口赋值,然后通过当前接口调用的方法( mCallBack.onSuccess(bytes); mCallBack.onError();),从而去执行实现了的接口方法。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。