> 文章列表 > Android中的接口回调机制

Android中的接口回调机制

Android中的接口回调机制

文章目录

      • 1.回调的含义和用途
      • 2.java实现接口回调
      • 3.Android中接口回调的体现
      • 4.接口回调在异步任务中的体现

1.回调的含义和用途

一般来说,模块之间都存在一定的调用关系,从调用方式上看,可以分为三类同步调用、异步调用和回调。同步调用是一种阻塞式调用,即在函数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

2.java实现接口回调

在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();}
}

在这里插入图片描述
设置接口就相对于设置一个用途,相当于可以将这个用途抽取出来供多个人可以使用,比较灵活

3.Android中接口回调的体现

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);}@Overrideprotected 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);}@Overridepublic 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;@Overrideprotected 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() {@Overridepublic void onEnsure(String msg) {Log.i("=====", "onEnsure: "+msg);tv.setText(msg);}});break;}}
}

在这里插入图片描述
点击确定后,点一下会变成你输入的内容

4.接口回调在异步任务中的体现

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;}@Overrideprotected byte[] doInBackground(String... params) {//进行子线程操作的函数byte[] content = HttpUtils.getByteContent(params[0]);return content;}@Overrideprotected 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";@Overrideprotected 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() {@Overridepublic void onSuccess(byte[] bytes) {try {String s = new String(bytes, 0, bytes.length, "UTF-8");tv2.setText(s);} catch (UnsupportedEncodingException e) {e.printStackTrace();}}@Overridepublic 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() {@Overridepublic void onSuccess(byte[] bytes) {Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);iv.setImageBitmap(bitmap);}@Overridepublic 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() {@Overridepublic void onEnsure(String msg) {Log.i("=====", "onEnsure: "+msg);tv.setText(msg);}});}
}

上面通过接口回调很灵活,不仅通过该接口可以实现图片的加载也可以实现网页数据的加载。
在这里插入图片描述
因为在到点击事件的时候设置接口(是new的),当传入到Mytask类里的时候,通过传过来的对象给当前的接口赋值,然后通过当前接口调用的方法( mCallBack.onSuccess(bytes); mCallBack.onError();),从而去执行实现了的接口方法。