当思维逻辑有限之时总会因为简单至极的东西而踌躇不安,关于接口回调这种简单的思想,我也曾辗转反侧,导致每个阶段的想法不尽相同,所以此篇记录了我不同时期对其意义的理解,当年每个时期得理解也分别写了一片blog,但是现在我都综合在了一起 ~
早期思考
当年我被接口回调绕晕的时候,后来回头一看发现这其实就是一个简单的代理方法,对大家帮助不大,因为是回忆,所以不做什么大修改了,说到这里大家可以关闭了 ,加油 ~
package com.example.call_back_demo;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener, CallBack {
private TextView mBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtn = (TextView) findViewById(R.id.btn);
/**
* 回调的思想:
* 回调的描述莫过于说:"我现在办不了这这件事情,等我能办了,我就告诉你."
*
* 回调步骤:
* 1.首先回调是涉及到接口
* 2.数据的处理方式
* 3.需要的地方告诉其处理的结果
* */
mBtn.setOnClickListener(this);
}
//点击事件,创建办事儿着,由他通过接口告诉我们处理的结果
@Override
public void onClick(View v) {
DataSpeace data=new DataSpeace(this);
data.setData(this);
}
//实现了我们定义的接口
public void Basket(Object obj) {
Toast.makeText(this, "obj="+obj, 0).show();
}
/**
* 2.篮子已有,那么我们创建一个类来存放之前我们办事儿的"控件"
* */
public class DataSpeace{
//接口充当成员
//创建成员变量和成员方法,且做初始化
public CallBack mCallBack;
public DataSpeace(CallBack mCallBack) {
this.mCallBack = mCallBack;
}
//存放数据的方式了,处理方案写在这里
public void setData(CallBack obj){
Toast.makeText(MainActivity.this, "我可以处理这件事儿了="+obj, 0).show();
}
}
}
接口必不可少:
package com.example.call_back_demo;
/**
* 1.接口(篮子,数据后续存放的控件)
* */
public interface CallBack {
void Basket(Object obj);
}
如果想运行Demo,布局当然必不可少:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
>
<TextView
android:background="#658742"
android:layout_centerInParent="true"
android:id="@+id/btn"
android:textColor="#fff"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="回调Demo" />
RelativeLayout>
中期思考
接口回调在Android中用的太多,当你学不精的时候,会发现有很多种方式回调,希望以下的对你有所帮助
接口:
package com.example.myapplicationdelect;
public interface Ditch {
//用于交流,获取答案----好比一个渠道
void talk(String string);
}
Student :
package com.example.myapplicationdelect;
import android.util.Log;
public class Student implements Ditch{
Teacher teacher;
public Student(Teacher teacher){
this.teacher=teacher;
}
//这里是问的问题,这里调用Teacher的方法
public void ask(String ask){
teacher.answer(Student.this,ask);
}
@Override
public void talk(String string) {
Log.e("tag","This is Te }
Teacher
package com.example.myapplicationdelect;
public class Teacher {
public void answer(Ditch ditch,String ask){
ditch.talk("这其实是一个简单的逻辑处理,我们在Student中进行Teacher的引用,同时也引用他的方法,只不过我们在Student中同时做了回调的监听,当Teacher做完任务的时候会直接返回给我们需要的数据");
}
}
MainActivity
package com.example.myapplicationdelect;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
public TextView mText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText=(TextView) findViewById(R.id.main);
mText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//这里我们看到了,我们在Student中持有Teacher的引用
Teacher teacher = new Teacher();
Student student = new Student(teacher);
student.ask("这就是我们要问的问题,这里用于接收回调");
}
});
}
}
后期思考
对…,你没有看错!接口回调这已经是我写的第三篇博文了,之前的概念一直迷迷糊糊,一直照猫画虎,只有其形,而无其意,这篇本章可能是目前为止理解最深的一篇关于接口回调的博文了,我以俩种方式进行讲解的,第一种是常规方式,进行举例,第二种方式是已观察者和订阅者的理解举例的。
后面的补充内容,为后期补录的彩蛋!
代码中的 A/B/C标注均有作用,后续可自行查看执行逻辑。
个人理解:
1.接口回调主要有三方,一方为需求方(A方),这里我们往往要获取我们想要的数据,如我们需要投资理财产品,这时候我们就需要找对应平台产品去投资,就像房屋中介一样的性质,这里我们用的就是接口(一个容器,简称B方),由B去帮我们找数据,找资源,让他去处理,而B去查看的区域,就是C方了, 这里告诉了我们该具体都是哪一款产品,哪一款房子!(其实在这里我们已经把我们想要的数据存储在了B方),之后我们就可以返回A方,进行数据填充,确定投资方向!
这里的执行逻辑是 :A - B - C - A
这里的写入(就是写代码的顺序)逻辑是:B - C - A or B - A -C
2.现在的三方框架如EvEntBus或者RxAndroid or RxJava,EventBus下我们在数据改变处(监听)可以发送状态,进行数据存入,然后在数据可需处,进行EventBus的注册,注册, 然后通过sub方法进行数据读取进行操作。
这个更像Rx下的机制,我们都知道现在很多这样的开发模式中,有观察者,被观察者,执行者,其实这里也可以很好的诠释接口回调的问题,我们在数据获取的类,放入被观察者(接口),然后回到数据可需处,等被观察者的数据的存入,我们在当前调用执行者进行逻辑处理
OwnListener (接口 - 容器)
package com.yl.aninterface.interfacedata;
/**
* Created by YongLiu on 2017/7/21.
*/
public interface OwnListener {
void setData (String string);
}
Listener (监听处 - 相当于Set数据的过程)
package com.yl.aninterface.interfacedata;
import android.content.Context;
/**
* Created by YongLiu on 2017/7/21.
*/
public class Listener {
public Context mContext;
public OwnListener ownListener;
public Listener(Context context,OwnListener listener){
this.mContext=context;
this.ownListener=listener;
}
//B :数据处理
void setListener(){
ownListener.setData("这里我们储存了数据");
}
}
MainActivity (这里我们相当于发送请求(执行过程:1.发送 2.查看接口实现处 3.接口实现处获取的数据 4.设置接口中已经保存的数据)):
package com.yl.aninterface.interfacedata;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener,OwnListener {
private TextView mView;
private TextView mContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mView = (TextView) findViewById(R.id.tv_btn);
mContent = (TextView) findViewById(R.id.tv_content);
mView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// A :相当于发送数据
if(v.getId()==R.id.tv_btn){
new Listener(this, this).setListener();
}
}
// C :获取数据
@Override
public void setData(String string) {
mContent.setText(string);
}
}
补充内容:因为准备在新项目中采用MVP的开发模式进行开发,所以接口回调的使用必须熟练使用,故意进行博文补录
目前梳理之后,我归结为接口的回调的常用使用方式有三种,下面通过代码片段帮助大家理解
第一种,常规监听
思想总结 : A类调用B类方法,当B类的方法回调接口,把结果传回A类
下面代码中,MainActivity 代表 A类, AClass代表B类
执行步骤:
1.创建一个接口,同时接口内部创建一个方法,用于数据回传(MainActivity 处实现此接口),如
package com.bakheet.effect.interfacedemo;
/**
* Created by YongLiu on 2017/11/8.
*/
public interface MainListener {
void setData(String data);
}
2.在ManiActivity中实现这个接口,如
@Override
public void setData(String data) {
mBtn.setText(data);
}
3.调用AClass的方法,首先要拥有AClass的实例,之后调取AClass中的
aClass = new AClass(this);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
aClass.setData("MainActivity 传到 AClass的数据");
}
});
4.AClass类的代码要注意,首先要拥有MainListener的成员变量,注册在成员方法中,如
public MainListener listener;
public AClass(MainListener listener){
this.listener=listener;
}
public void setData(String data) {
String ste=data+"AClass 接收信息之后的回传";
listener.setData(ste);
}
第二种方法,常用的成功,失败回调
1.创建接口
package com.bakheet.effect.interfacedemo;
/**
* Created by YongLiu on 2017/11/8.
*/
public interface BListener {
void Succeed();
void Faieail();
}
2.AClass类创建方法,满足一定条件之后,使用接口进行标记
void setListener(String ste,BListener bListener){
if(ste.equals("MainActivity 传到 AClass的数据AClass 接收信息之后的回传")){
Log.e("tag","AClass要传入的数据");
bListener.Succeed();
}else{
Log.e("tag","Main传来的数据");
bListener.Faieail();
}
}
3.MainActivity 调用处
aClass = new AClass(this);
aClass.setListener(mBtn.getText().toString(), new BListener() {
@Override
public void Succeed() {
Log.e("tag", "Set Succeed回调");
}
@Override
public void Faieail() {
Log.e("tag", "Set Faieail回调");
}
});
第三种方式 ,Activity 之间接口回调
主要思想 :中转站思想,使用Manager进行接口中转,如
package com.bakheet.effect.interfacedemo;
/**
* Created by YongLiu on 2017/11/8.
*/
public class InterManager {
public SecoundListener secoundListener;
private InterManager() {
}
public static InterManager interManager = new InterManager();
public InterManager getInstance() {
return interManager;
}
public void setSecoundListener(SecoundListener secoundListener) {
this.secoundListener = secoundListener;
}
}
SecoundListener
package com.bakheet.effect.interfacedemo;
public interface SecoundListener{
void getData(String data);
}
MainActivity
//注册监听 同时实现接口内方法
InterManager.interManager.setSecoundListener(this);
@Override
public void getData(String data) {
Toast.makeText(this, "---" + data, Toast.LENGTH_SHORT).show();
mBtn.setText(data);
}
SecoundActivity
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendData(InterManager.interManager.secoundListener);
}
});
private void sendData(SecoundListener listener) {
listener.getData("回头已是百年时");
}
下载地址