很多初学者都遇到过这类问题:在列表项(ListView、GridView等)button 事件的响应与列表冲突,这一类型的问题,要解决其实很简单,且看接口回调。
在Android开发中回调用的比较广泛,主要有接口回调,类回调函数,特别类Activity直接调用方法等,这里我们先从接口回调说起,可以先来看一段简单代码块:
public class LoginImp {
public static void main(String[] args) {
String userName="lanyan";
String password="12345";
onLogin(userName, password);
}
public static void onLogin(String userName,String password){
}
}
以这段代码为例,把登录方法分离到接口,用接口回调的表现形式。
形式一:
/**
* 登录接口
* @author LanYan
*
*/
public interface OnLoginListener {
/**
* 登录方法
* @param userName
* @param password
*/
void onLogin(String userName,String password);
}
修改后调用代码实例:
public class LoginImp {
public static void main(String[] args) {
String userName="lanyan";
String password="12345";
login(userName, password);
}
public static void login(String userName,String password){
onLoginListener.onLogin(userName, password);
}
static OnLoginListener onLoginListener=new OnLoginListener() {
@Override
public void onLogin(String userName, String password) {
}
};
}
形式一的方式必须重载所有的接口定义方法,在开发中如果接口定义了多个方法,而在某块代码只需用到其中一个,此时就显得有点累赘了。具体优化稍后提到。
形式二:
public class LoginHeper {
public void onLogin(String userName,String password){
}
public void onLogout(String userName,String password){
}
}
形式二的代码调用实例:
public class LoginImp {
public static void main(String[] args) {
String userName="lanyan";
String password="12345";
login(userName, password);
}
public static void login(String userName,String password){
mLoginHelper.onLogin(userName, password);
}
static LoginHeper mLoginHelper=new LoginHeper(){
public void onLogin(String userName, String password) {
}
};
}
看似代码相差不大,但是仔细的同学就会发现,LoginHeler内部有两个方法,这里只选择重载了onLogin方法,这是一大亮点,但是当用户不想手动重载时,缺点就出来了。不过可以考虑配合结合接口使用,达到鬼斧神工之效。具体详解往下看
形式三:
public class LoginImp implements OnLoginListener{
public static void main(String[] args) {
String userName="lanyan";
String password="12345";
login(userName, password,new LoginImp(){
@Override
public void onLogin(String userName, String password) {
// TODO Auto-generated method stub
super.onLogin(userName, password);
}
});
}
public static void login(String userName,String password,LoginImp mCallback){
mCallback.onLogin(userName, password);
}
@Override
public void onLogin(String userName, String password) {
}
}
表现形式三通过类实现接口,调用时通过类实例调用方法,与形式一差别不大,但在某种情况下,不希望手动重载,这样就显得不够完美了。
表现形式四:
public interface OnProgressListener {
void onStart();
void onProgress(int progress,int currentSize,int totalSize);
void onStop();
}
public abstract class OnHttpListener implements OnProgressListener{
@Override
public void onStart() {
// TODO Auto-generated method stub
}
@Override
public void onProgress(int progress, int currentSize, int totalSize) {
// TODO Auto-generated method stub
}
@Override
public void onStop() {
// TODO Auto-generated method stub
}
public abstract void onFail(Exception e,String result);
public abstract void onSuccess(String result);
}
测试代码:
public class HttpTest {
public static void main(String[] args) {
new HttpTest().doPost(null, null, new OnHttpListener() {
public void onStart() {
//手动重载
}
@Override
public void onSuccess(String result) {
// TODO Auto-generated method stub
}
@Override
public void onFail(Exception e, String result) {
// TODO Auto-generated method stub
}
} );
}
public void doPost(String url,JSONObject requestJson,OnHttpListener onHttpListener){
}
}
表现形式四是最好用的也是用的最广泛的,比如Xutils框架等第三方框架有用到。
表现形式五:
public abstract class OnProgressListener {
protected abstract void onStart();
protected abstract void onProgress(int progress,int currentSize,int totalSize);
protected abstract void onStop();
}
public abstract class OnHttpListener extends OnProgressListener{
@Override
protected void onStart() {
// TODO Auto-generated method stub
}
@Override
protected void onProgress(int progress, int currentSize, int totalSize) {
// TODO Auto-generated method stub
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
}
public abstract void onFail(Exception e,String result);
public abstract void onSuccess(String result);
}
形式五,这里把接口改用抽象,把实现改用继承,相比较形式四哪一种更好,这里暂不讨论。,先通过一段Activity配合adapter的调用实例,让我们深入理解接口回调:
定义列表的相关接口:
import android.view.View;
public interface ListListener{
interface OnCheckedListener{
void onCheckedChange(boolean isChecked ,int position);
}
interface OnClickListener<T>{
void onClick(View v, T result ,int position);
}
void onReferesh();
void onBackTop();
void onScrollTop(int distance);
void onScrollBottom(int distance);
}
接口的抽象实现类:
public abstract class OnListListener<T> implements ListListener,OnCheckedListener,OnClickListener<T>{
@Override
public void onCheckedChange(boolean isChecked, int position) {
}
@Override
public void onClick(View v, T result, int position) {
}
@Override
public void onBackTop() {
}
@Override
public void onReferesh() {
}
@Override
public void onScrollBottom(int distance) {
}
@Override
public void onScrollTop(int distance) {
}
public abstract void onItemClick(View v,T result ,int position);
}
adapter基类(部分空方法具体实现这里就不写了,这不是重点哇)
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import com.example.interfaces.OnListListener;
public abstract class ListAdapter<T> extends BaseAdapter{
protected LayoutInflater mInflater;
protected ArrayList<T> mList;
protected Context mContext;
protected OnListListener<T> callback=null;
public ListAdapter(Context mContext,ArrayList<T> mList) {
this(mContext, mList, null);
}
public ListAdapter(Context mContext,ArrayList<T> mList,OnListListener<T> callback) {
initiazed(mContext, mList, callback);
}
public void initiazed(Context mContext,ArrayList<T> mList,OnListListener<T> callback){
this.mContext=mContext;
this.mInflater=LayoutInflater.from(mContext);
setmList(mList);
this.callback=callback;
}
@Override
public int getCount() {
return mList.size();
}
@Override
public T getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position,View convertView,final ViewGroup parent) {
if(convertView==null){
convertView=mInflater.inflate(setContextView(), null);
}
convertView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(callback!=null){
//OnItemClick回调,从此不再调用系统的OnItemClickListener了
callback.onItemClick(parent, getItem(position), position);
}
}
});
initView(convertView,getItem(position),position);
return convertView;
}
public ArrayList<T> getmList() {
return mList;
}
public void setmList(ArrayList<T> mList) {
if(mList==null){
this.mList=new ArrayList<T>();
}else{
this.mList = mList;
}
}
public void setOnListListener(OnListListener<T> callback){
this.callback=callback;
}
public OnListListener<T> getOnListListener(){
return callback;
}
public void onReferesh(ArrayList<T> mList){
}
public void onLoadMore(ArrayList<T> mList){
}
public void removeItem(int position){
}
public void removeCollection(ArrayList<T> mList){
}
public void updateItem(T result){
}
public abstract int setContextView();
public abstract void initView(View converView,T result,int position);
}
adapter测试类OptionAdapter:
public class OptionAdapter extends ListAdapter<UserBean>{
//两个构造方法可根据自己习惯调用
public OptionAdapter(Context mContext, ArrayList<UserBean> mList,
OnListListener<UserBean> callback) {
super(mContext, mList, callback);
}
public OptionAdapter(Context mContext, ArrayList<UserBean> mList) {
this(mContext, mList,null);
}
@Override
public int setContextView() {
return R.layout.item_option;
}
@Override
public void initView(final View converView,final UserBean result,final int position) {
//这里面给控件赋值,并对空间给予监听,回调相关方法,方法不足时自行扩展,这里可通过辅助类
//ViewHoler.get()..辅助完成赋值,
}
}
下面是Activity调用实例:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//方法一
adapter=new OptionAdapter(this, null);
mListView.setAdapter(adapter);
adapter.setOnListListener(new OnListListener<UserBean>() {
@Override
public void onItemClick(View v, UserBean result, int position) {
}
@Override
public void onCheckedChange(boolean isChecked, int position) {
super.onCheckedChange(isChecked, position);
//手动可选重载方法
}
});
//方法二
adapter=new OptionAdapter(this, null,new OnListListener<UserBean>() {
@Override
public void onItemClick(View v, UserBean result, int position) {
// TODO Auto-generated method stub
}
});
}
下面我们来浅谈接口回调在Volley框架的具体实战。
Volley里的重定向接口定义:
public abstract interface RetryPolicy
{
public abstract int getCurrentTimeout();
public abstract int getCurrentRetryCount();
public abstract void retry(VolleyError paramVolleyError)
throws VolleyError;
}
该接口的实现类如下(这种接口定义,把参数分离出接口,又其实现类构造方法传入参数,这是一大亮点):
public class DefaultRetryPolicy implements RetryPolicy{
//.................此处略.......................
public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier){
this.mCurrentTimeoutMs = initialTimeoutMs;
this.mMaxNumRetries = maxNumRetries;
this.mBackoffMultiplier = backoffMultiplier;
}
public int getCurrentTimeout(){
return this.mCurrentTimeoutMs;
}
public int getCurrentRetryCount(){
return this.mCurrentRetryCount;
}
}
Volley里的cache缓存接口定义如下:
import java.util.Collections;
import java.util.Map;
public abstract interface Cache
{
public abstract Entry get(String paramString);
public abstract void put(String paramString, Entry paramEntry);
public abstract void initialize();
public abstract void invalidate(String paramString, boolean paramBoolean);
public abstract void remove(String paramString);
public abstract void clear();
public static class Entry
{
public byte[] data;
public String etag;
public long serverDate;
public long ttl;
public long softTtl;
public Map<String, String> responseHeaders = Collections.emptyMap();
public boolean isExpired()
{
return this.ttl < System.currentTimeMillis();
}
public boolean refreshNeeded()
{
return this.softTtl < System.currentTimeMillis();
}
}
}
缓存的实现类(重载interface接口的方法并添加了同步关键字):
public class DiskBasedCache implements Cache{
//..........此处略.......
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes)
{
this.mRootDirectory = rootDirectory;
this.mMaxCacheSizeInBytes = maxCacheSizeInBytes;
}
public DiskBasedCache(File rootDirectory)
{
this(rootDirectory, 5242880);
}
public synchronized void clear()
{
File[] files = this.mRootDirectory.listFiles();
if (files != null) {
for (File file : files) {
file.delete();
}
}
this.mEntries.clear();
this.mTotalSize = 0L;
VolleyLog.d("Cache cleared.", new Object[0]);
}
public synchronized Cache.Entry get(String key)
{
//..........此处略.......
}
}
诸如此类的接口回调着实太多,就不一一列举了,顺便提一下,当下各种框架盛行,让开发者不知道该如何选择是好,其实原理都大同小异差别不大,10分钟左右就可以上手,我们应该至少应该精通一种框架开发,提高开发效率,至于其他的额框架还是应该有个了解(换到不同的公司后可以一眼就认出使用框架,以免被人认为是小白,嘿嘿)