Android視角,精妙絕倫的回調方法

衆所周知,在android裏面充斥着衆多的監聽器,如一個按鈕具備的OnClickListener,能對按鈕的點擊事件進行監聽,這些監聽器一般是一個接口,咱們能夠經過實現接口裏的回調方法,執行事件處理。而AsyncTask也能經過其回調方法在恰當的時間執行異步任務(doInBackground()中),而且在執行完畢後回調到onPostExecute(),咱們能夠在onPostExecute下面得到異步任務的結果,並使結果安全地在UI線程中顯示。AsyncTask是個抽象類,這些回調方法多是抽象方法,也多是普通的方法,像doInBackground是抽象方法,強制使用AsyncTask的人去實現,而onPostExecute等回調方法則不是抽象的,使用者可選地對其進行重寫。android

回調方法這種設計在我看來是如此的精妙絕倫,它總能在恰到好處的時間返回和執行正確的事。上面提到了兩種實現回調方法的方式:1.是抽象的抽象,面向接口,全部監聽器中的方法都必須實現。2.是單純的抽象,可以可選地進行回調須要的方法。下面我就本身寫了兩種方式的回調,及說明使用場景。安全

方式一:使用接口(使用場景:自定義View時做爲事件監聽器)app

/**
 * 自定義列表頭視圖
 * 
 * @author Change
 * 
 */
public class ListHeadView extends LinearLayout implements OnClickListener {
    private OnHeadControlListener colLis;
    private CheckBox c_all;
    private TextView field1, field2, field3, field4;
    private Button controlBtn;
    private final int count = 4;

    public ListHeadView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        inflateView(context);
    }

    public ListHeadView(Context context, AttributeSet attrs) {
        super(context, attrs);
        inflateView(context);
    }

    public ListHeadView(Context context) {
        super(context);
        inflateView(context);
    }

    private void initView() {
        c_all = (CheckBox) this.findViewById(R.id.c_all);
        field1 = (TextView) findViewById(R.id.field1);
        field2 = (TextView) findViewById(R.id.field2);
        field3 = (TextView) findViewById(R.id.field3);
        field4 = (TextView) findViewById(R.id.field4);
        controlBtn = (Button) findViewById(R.id.controlBtn);
        controlBtn.setOnClickListener(this);
        c_all.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                colLis.onCheckAllChange(isChecked);// 調用1
            }
        });
    }

    private void inflateView(Context context) {
        View.inflate(context, R.layout.list_head, this);
        initView();
    }

    public void setTexts(String[] texts) {
        if(texts.length>=count){
            field1.setText(texts[0]);
            field2.setText(texts[1]);
            field3.setText(texts[2]);
            field4.setText(texts[3]);
        }else{
            throw new ArrayIndexOutOfBoundsException("you don't have tomany fields!");
        }
    }
    
    public void setButtonResource(int resid){
        controlBtn.setBackgroundResource(resid);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.controlBtn:
            colLis.onClickRightBtn();// 調用2
            break;
        default:
            break;
        }
    }

    /**
     * 回調接口,提供按鈕和複選框的監聽
     * 
     * @author Change
     * 
     */
    public interface OnHeadControlListener {
        /**
         * 點擊右邊按鈕後觸發
         */
        public void onClickRightBtn();

        /**
         * 複選框狀態改變後觸發
         * 
         * @param isChecked
         */
        public void onCheckAllChange(boolean isChecked);
    }

    /**
     * 設置監聽器
     * 
     * @param colLis
     */
    public void setOnHeadControlListener(OnHeadControlListener colLis) {
        this.colLis = colLis;
    }

}

那麼,咱們在使用的時候就能夠經過異步

setOnHeadControlListener方法去設置監聽器了。
ListHeadView headView = new ListHeadView(context);
        headView.setOnHeadControlListener(new OnHeadControlListener() {
            
            @Override
            public void onClickRightBtn() {
                Toast.makeText(context, "點擊按鈕", Toast.LENGTH_SHORT).show();
            }
            
            @Override
            public void onCheckAllChange(boolean isChecked) {
                Toast.makeText(context, "選擇變化爲"+isChecked, Toast.LENGTH_SHORT).show();
            }
        });

 

方式二:使用抽象類(異步任務結果返回)ide

/**
 * apk搜索器
 * 
 * @author Change
 * 
 */
public abstract class ApkFileSearcher {
    private String keyword;// 搜索關鍵字

    private static final String TAG = ApkFileSearcher.class.getSimpleName();

    public ApkFileSearcher(String keyword) {
        this.keyword = keyword;
    }

    /**
     * 從列表中得到關鍵字匹配的新列表
     * 
     * @param allApps
     * @return
     */
    public List<AppsBean> onSearchIn(List<AppsBean> allApps) {
        List<AppsBean> results = new ArrayList<AppsBean>();
            for (AppsBean app : allApps) {
                if (app.appName.contains(keyword)
                        || app.pkgName.contains(keyword)) {
                    results.add(app);
                }
            }
            allApps.clear();
            allApps.addAll(results);
            return allApps;
    }

    /**
     * 抽象方法:回調搜索結果
     * 
     * @param result
     */
    public abstract void onSearchFinished(List<AppsBean> result);

    /**
     * 本地異步搜索
     * 
     * @param allApps
     */
    public void startAsyncLocalSearch(final List<AppsBean> allApps) {
        new AsyncTask<Void, Void, List<AppsBean>>() {
            @Override
            protected List<AppsBean> doInBackground(Void... params) {
                return onSearchIn(allApps);
            }

            @Override
            protected void onPostExecute(List<AppsBean> result) {
                onSearchFinished(result);// 調用,傳入結果
            };
        }.execute();
    }

使用的時候便要實現其中的抽象方法。this

final ApkFileSearcher searcher = new ApkFileSearcher(keyword) {
                @Override
                public void onSearchFinished(List<AppsBean> result) {
                    //在界面對結果進行處理。如傳入並構建列表適配器
                }
            };

再次感慨這前人偉大的發明,無敵的回調設計,固然,使用回調方法也有弊端,我的認爲大量使用匿名內部類將下降代碼的可讀性,用的時候須要慎重,不過,貴在用之方便,依舊強調它的特色--恰到好處spa

相關文章
相關標籤/搜索