1. 程式人生 > >詳解Android中回撥機制與RecyclerView的Item點選事件實現

詳解Android中回撥機制與RecyclerView的Item點選事件實現

總是看書上寫著回調回調,以為就是函式呼叫換了個名字,尤其是看了Button的點選事件實現後,覺得不就是觸發機制。

A事件發生->後臺處理邏輯->告訴前臺怎麼做->結束。

Android常見button點選事件:


  loginBtn = (Button) findViewById(R.id.login_button);
  loginBtn.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View v) {
        // TODO Auto-generated method stub
Toast.makeText(TestButtonActivity.this, "login", Toast.LENGTH_SHORT).show(); } });

但其實回撥不是這樣的,完全不是!

這裡由於使用了匿名內部類,機制是不很清晰,下面我們換成Activity實現介面的方式。

public class MainActivity extends Activity implements OnClickListener {

    private Button bt;

    @Override
    protected void
onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt = (Button) findViewById(R.id.bt); bt.setOnClickListener(this); }         //用Activity實現OnClickListener介面 @Override public void onClick(View v) { // TODO Auto-generated method stub
Log.i("用Activity實現OnClickListener介面", "點選事件"); } }

Button類繼承自View類,View類處理點選事件。但是它並不具體指定如何處理,而是給出了介面OnClickListener規範

首先,Acticity這個類中持有Button類例項bt的引用,呼叫他的setOnClickListener()方法(實際還是View類的),傳入了引數this,也就是這個Activity本身,希望View類處理點選事件。

然後,View類接受了請求,並利用傳入的Activity類的引用,使用Avtivity類的 onClick()方法處理點選事件

這就是回撥
就是A類中呼叫B類中的某個方法C,然後B類中反過來呼叫A類中的方法D,D這個方法就叫回調方法

這裡D就是:

 public void onClick(View v) {
        // TODO Auto-generated method stub
        Log.i("用Activity實現OnClickListener介面", "點選事件");
        }
/** 
 * 這個View就相當於B類 
 * 
 */  
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {  
 /** 
     * Call this view's OnClickListener, if it is defined. 
     * 
     * @return True there was an assigned OnClickListener that was called, false 
     *         otherwise is returned. 
     */  
    public boolean performClick() {  
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);  

        if (mOnClickListener != null) {  
            playSoundEffect(SoundEffectConstants.CLICK);  

            //B類(View類)呼叫A類Activity中click方法  
            mOnClickListener.onClick(this);  
            return true;  
        }  

        return false;  
    }  
}  

列印:Log.i(“用Activity實現OnClickListener介面”, “點選事件”);

也附上一個講的很好的回撥機制部落格:回撥機制

—————————————————————————————————————————————————————-

下面結合RecyclerView的點選事件實現例項,回顧一下。

RecyclerView是ListView的替代方案,十分的靈活,相比於ListView.難過的是它並沒有像ListView一樣提供setOnItemClickListener方法。他的點選事件都是由其中的viewholder中的view控制元件單獨註冊的,這樣的好處是,如果再想實現某個列表項中的某個圖示就十分簡潔,不像以前ListView中那樣麻煩。比如下面中的小三角播放按鈕點選事件

列表

但是這時候問題來了,我們想實現原來那樣的整個列表項的點選事件怎麼辦?如:

這裡寫圖片描述

要知道,現在點選事件都是在Adapter中由View自己註冊的。如:

 @Override
    public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
      View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.category_item,parent,false);
       final ViewHolder holder=new ViewHolder(view);
        holder.cateImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int position=holder.getAdapterPosition();
             CateGory   categoryItem=mCateGoryList.get(position);
                Toast.makeText(view.getContext(),"you click view"+categoryItem.getName(),Toast.LENGTH_SHORT).show();//工廠方法


            }
        });


        return holder;
    }

我們的思路是,每個列表項整個的點選事件就是ViewHolder被點選,所以讓他自己註冊自己的點選事件就好了。

首先,讓ViewHolder實現View類的介面,能夠處理自己的點選事件。

class ViewHolder extends  RecyclerView.ViewHolder implements View.OnClickListener {
        ImageView cateImage;
        TextView cateText;


        public ViewHolder(View view){
            super(view);
            cateImage= (ImageView) view.findViewById(R.id.cate_image);
            cateText= (TextView) view.findViewById(R.id.cate_name);
            view.setOnClickListener(this);

        }
        @Override
        public void onClick(View v) {
            if (clickListener != null) {
                clickListener.onClick(getAdapterPosition());

            }
        }
    }

注意這已經是一層回調了。在ViewHolder和View之間的回撥,clickListener是下面這個介面的例項,因為我們還需要一層回撥。

在RecyclerView中定義好介面規範:

 public static interface OnItemClickListener {
        void onClick(int position);
    }

再然後,我們希望在Activity中定義具體的處理邏輯,所以要把cliListener讓外部實現,用方法暴露出去。

 private OnItemClickListener clickListener;

    public void setClickListener(OnItemClickListener clickListener) {
        this.clickListener = clickListener;
    }

在Activity的onCreate中實現:

 adapter.setClickListener(new CateGoryAdapter.OnItemClickListener() {

            @Override
            public void onClick( int position) {
                Toast.makeText(MainActivity.this,position+"",Toast.LENGTH_SHORT).show();
            }
        });

這裡又是一層回撥。在Activity和adapter之間。

寫的不對的地方請告訴我謝謝!