Android中的接口回调机制

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

    @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;
     }
  }
}

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

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;
    }

    @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();),从而去执行实现了的接口方法。

猜你喜欢

转载自blog.csdn.net/ChenYiRan123456/article/details/122766476