1. 程式人生 > >Android中的介面回撥詳解,回撥機制:以Activity和Adapter傳遞資料為例。

Android中的介面回撥詳解,回撥機制:以Activity和Adapter傳遞資料為例。

首先解決啥是回撥:

我覺得這個例子比較好:某天,我打電話向你請教問題,當然是個難題,你一時想不出解決方法,我又不能拿著電話在那裡傻等,於是我們約定:等你想出辦法後打手機通知我,這樣,我就掛掉電話辦其它事情去了。過了XX分鐘,我的手機響了,你興高采烈的說問題已經搞定,應該如此這般處理。

以Activity和Adapter為例:

我們知道,Activity中的ListVIew的為介面層,其資料要通過放到介面卡中去,才能展示。Activity的通過各種邏輯(不論是模擬資料,還是網路載入的資料)得到的資料,一般是通過介面卡的構造方法來傳遞的。這樣的話,介面卡拿到資料就去一一適配展示了。但是,如果activity想要去拿到adapter的資料呢?比如:我想拿到ListView的每條item的資料(或者某個控制元件或者item的位置id),想想怎麼拿呢?------------------這時候就不好拿了是吧?

下面會上一個Demo,Demo中簡單的實現我想通過點選每個item的某個控制元件那個這個item的位置id。

Adapter的程式碼:

package com.example.adaptercallbackdemo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import 
java.util.List; /** * Created by Administrator on 2017/10/19. */ public class MyAdapter extends BaseAdapter { private Context mContext; private List<String> mList; private LayoutInflater mLayoutInflater; private OnClickMyTextView mOnClickMyTextView;
    //建構函式接收MainActivity傳遞過來的資料
public 
MyAdapter(Context context, List<String> list) { mLayoutInflater = LayoutInflater.from(context); this.mContext = context; this.mList = list; } @Override public int getCount() { return mList.size(); } @Override public Object getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder mViewHolder = null; if (convertView == null) { mViewHolder = new ViewHolder(); convertView = mLayoutInflater.inflate(R.layout.list_item, null); mViewHolder.mTextView = (TextView) convertView.findViewById(R.id.text); convertView.setTag(mViewHolder); } else { mViewHolder = (ViewHolder) convertView.getTag(); } mViewHolder.mTextView.setText(mList.get(position).toString());
//這裡便是知道難題答案的地方,setOnClickListener即點選了item的控制元件TextView,
點選了就能拿到id撒,但是這個時候我要告訴Activity啊,就有了介面回撥。
if (mOnClickMyTextView != null){
            mViewHolder.mTextView.setOnClickListener(new View.OnClickListener() {
                @Override
public void onClick(View v) {
//想到問題的答案的地方。其實這裡的mOnClickMyTextView是傳來的介面物件,介面就是一種規範,這裡的
myTextViewClick
函式
和activity處的
myTextViewClick
都要遵守這個規範(即指向同一個介面物件),才能回撥成功。
mOnClickMyTextView.myTextViewClick(position);
               }            
});        
}        
return convertView;    
public class ViewHolder {
       TextView mTextView;   
 }    
public interface OnClickMyTextView {//建立一個介面類
void myTextViewClick(int id);//建立一個回撥函式,例項化介面的時候就要具體化這個回撥函式,即要有函式體
}    
//註冊函式
public void setOnClickMyTextView(OnClickMyTextView onClickMyTextView){   
this.mOnClickMyTextView = onClickMyTextView;    
}
}
Activity的程式碼:
public class MainActivity extends AppCompatActivity {
    private ListView mListView;//宣告ListView控制元件來展示資料
private ArrayList<String> mlist;//列表存放資料
private MyAdapter myAdapter;//自定義的adapter
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.listview);
        initData();
        myAdapter = new MyAdapter(MainActivity.this, mlist);//將資料傳到介面卡中去
mListView.setAdapter(myAdapter);

        //介面的呼叫,獲取傳遞的id
//其實想想,下面的程式碼在OnCreate方法中呼叫,必定會執行setOnClickMyTextView方法(裡面的
myTextViewClick暫時不會執行),(相當於我Activity在問你Adapter,這個第幾個位置啊?即這個的id是多少啊?
這時沒點選某一個item,我怎麼告訴你id啊,就是上面的遇到難題要思考一下),那就先思考著吧)
//呼叫了此方法就表示有人聯絡你了,註冊到這來了
myAdapter.setOnClickMyTextView(new MyAdapter.OnClickMyTextView() {
            @Override
public void myTextViewClick(int id) {
                String string = mlist.get(id);
                Toast.makeText(MainActivity
                        .this, mlist.get(id), Toast.LENGTH_LONG).show();
            }
        });
    }
    //列表模擬資料
private void initData() {
        mlist = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            mlist.add("這是第" + i);
        }
    }
}
以上各個關鍵的地方都有程式碼註釋,結合了文章開頭的那個例子給出註釋。
那個例子說明了“非同步+回撥”的程式設計模式。其中,我問完你問題之後,我們在各幹各的事,我不用在那一直等你,可以去幹別的事,這邊是“非同步”的過程。
你後來打手機告訴我結果便是一個“回撥”過程;我的手機號碼必須在以前告訴你,這便是註冊回撥函式;我的手機號碼應該有效並且手機能夠接收到你的呼叫,
這是回撥函式必須符合介面規範。

對回撥的深入思考:

程式的本質就是程式碼跳轉,不管同步非同步反射介面虛擬函式,本質上都是函式呼叫。函式我們要呼叫它,就需要它的指標,不同語言通過不同的方式來得到這個指標。而我們定義的介面其實就是一個函式指標,那麼那個註冊過程,其實就是相當於對那個函式指標賦值。通過這個函式指標來呼叫我們定義的自實現函式。

文中例子來自:http://blog.csdn.net/a78270528/article/details/46918601