在最近写的一个demo中,遇到这样一个问题:一个button点击就展开或者关闭其对应的一个RecyclerView,但展开或者关闭这个recyclerview又不能在recyclerview的adapter中进行操作,一是因为没有相应的content,二是没有相应的view(没有这两个会导致活动栈和相应的view无法找到),最最重要的就是我在mainActivity中设置了一系列的flag来标识UI的改变,所以,在这里就使用了接口的回调。接下来,我们先认识什么是回调,然后在贴我的代码。
什么是回调:
就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法
举个栗子:
网上怎么都是打电话的栗子呢,好吧,我也跟上:小李有一天遇到一个知识点不会,问题是什么java?然后他就打电话给小黄,小黄说,我也不知道,我要先去查一下书,小李说那你先查,我写作业去了,查出来再打电话告诉我,然后就挂断电话了。10分钟过去了,小黄打电话来,说答案就是java是一种面向对象编程语言。
/**
* 这是一个回调接口
*/
public interface CallBack {
/**
* 这个是小黄知道答案时要调用的函数告诉小李,也就是回调函数
* @param result 是答案
*/
public void solve(String result);
}
看看小李:
/**
* @author xiaanming
*/
public class Li implements CallBack {
// 小黄对象的引用
private Huang huang;
/**
* 小李的构造方法,持有小黄的引用
* @param huang
*/
public Li(Huang huang){
this.huang = huang;
}
/**
* @param question 就是小李要问的问题
*/
public void askQuestion(final String question){
//这里用一个线程就是异步,
new Thread(new Runnable() {
@Override
public void run() {
/**
* 小李调用小黄中的方法,在这里注册回调接口
* 这就相当于A类调用B的方法C
*/
huang.executeMessage(Li.this, question);
}
}).start();
//做作业
play();
}
public void play(){
System.out.println("我要做作业去了");
}
/**
* 小黄知道答案后调用此方法告诉小李,就是所谓的小李的回调方法
*/
@Override
public void solve(String result) {
System.out.println("小黄告诉小李的答案是--->" + result);
}
}
看看小黄:
public class Huang {
/**
* @param callBack
* @param question 小李问的问题
*/
public void executeMessage(CallBack callBack, String question){
System.out.println("小李问的问题--->" + question);
//模拟小王查书需要很长时间
for(int i=0; i<10000;i++){
}
/**
* 小李办完自己的事情之后想到了答案是2
*/
String result = "java是一种面向对象编程语言";
/**
* 于是就打电话告诉小李,调用小李中的方法
* 这就相当于B类反过来调用A的方法D
*/
callBack.solve(result);
}
}
测试类
/**
* @author xiaanming
*
*/
public class Test {
public static void main(String[]args){
Li li = new Li();
Huang huang= new Huang(li);
//当小李遇到问题时
wang.askQuestion("java是什么");
}
}
通过如此通俗的例子,应该大家都比较懂什么是回调与接口了,也应该看懂了怎么去实现
在这里总结一下实现步骤:
- 定义一个接口,其中包含需要回调的函数。(callback)
- 实现B类(Huang),决定什么时候回调
- 实现A类,是否需要回掉,以及实现implements后的方法
《java核心技术卷1》这样概括:
回调(callback)是一种常见的程序设计模式,在这种模式中,可以指出某个特定事件发生时应该采取的动作。
从这段话中就可以清楚知道,什么是回调,而回调方法就是我们implements后需要实现的方法,及上文的solve,与此同时,因为implement的类是我们所决定,这就代表着我们想在哪采取动作,采取什么动作都由自己决定。
说了这么多,贴下最初的问题:
mainActivity
public class MainActivity extends BaseActivity implements OnThisItemClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//其他代码省略
initView();
}
private void initView() {
...
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recLogin.setLayoutManager(layoutManager);
MyLoginListAdapter adapter = new MyLoginListAdapter(loginQQList);
adapter.setOnItemClickListener(this); //设置点击事件的监听者
recLogin.setAdapter(adapter);
}
@Override
public void onItemClicked(int position) {
//需要执行的具体逻辑
isIndicatorUp = false;
isVisible = false;
ibtQQListIndicator.setBackgroundResource(R.drawable.down);
recLogin.setVisibility(View.GONE); //让recyclerView列表消失,并且让游标向下指!
password.setVisibility(View.VISIBLE);
btnLogin.setVisibility(View.VISIBLE);
tvForgetPassword.setVisibility(View.VISIBLE);
tvRegister.setVisibility(View.VISIBLE);
tvAgree.setVisibility(View.VISIBLE);
edtQQnum.setText(loginQQList.get(position).getQqNum().toString());
civAvatar.setVisibility(View.VISIBLE);
civAvatar.setImageResource(loginQQList.get(position).getAvatar());
password.setText(loginQQList.get(position).getPassword());
}
}
最后的adapter:
public class MyLoginListAdapter extends RecyclerView.Adapter<MyLoginListAdapter.ViewHolder>{
public OnThisItemClickListener mOnThisItemClickListener;
......
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_loginlist, parent, false);
final ViewHolder holder = new ViewHolder(view);
holder.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
list.remove(position);
notifyDataSetChanged();
}
});
holder.qqNum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
currentSelectedPosition = holder.getAdapterPosition();
int position = holder.getAdapterPosition();
mOnThisItemClickListener.onItemClicked(position);
}
});
holder.avatar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
currentSelectedPosition = holder.getAdapterPosition();
int position = holder.getAdapterPosition();
mOnThisItemClickListener.onItemClicked(position);
}
});
return holder;
}
.......
public void setOnItemClickListener(OnThisItemClickListener onItemClickListener)
{
mOnThisItemClickListener = onItemClickListener;
}
}
这个项目的github地址:https://github.com/lilei1lll/QQ7.0login
看见这个代码有没有什么想法?对的,像button之类的点击事件都差不多原理和实现方法都是这样子的
还有就是有木有发现这类模式常用在两个地方:解耦和MVP模式
鸿扬大神的ViewPager系列之 打造一个通用的ViewPager:
http://mp.weixin.qq.com/s/I2gY4Xp_JGrE4YpjWQ3cag
既学习了封装viewpager和mvp,又学习了接口,有木有一举两得的感觉啊
想知道其他接口的一些事例,想了解接口的一些实际使用?
推荐:《java核心技术 卷I》原书第10版P222