• Android视角,精妙绝伦的回调方法


    众所周知,在android里面充斥着众多的监听器,如一个按钮具有的OnClickListener,能对按钮的点击事件进行监听,这些监听器通常是一个接口,我们可以通过实现接口里的回调方法,执行事件处理。而AsyncTask也能通过其回调方法在恰当的时间执行异步任务(doInBackground()中),并且在执行完毕后回调到onPostExecute(),我们可以在onPostExecute下面获得异步任务的结果,并使结果安全地在UI线程中显示。AsyncTask是个抽象类,这些回调方法可能是抽象方法,也可能是普通的方法,像doInBackground是抽象方法,强制使用AsyncTask的人去实现,而onPostExecute等回调方法则不是抽象的,使用者可选地对其进行重写。

    回调方法这种设计在我看来是如此的精妙绝伦,它总能在恰到好处的时间返回和执行正确的事。上面提到了两种实现回调方法的方式:1.是抽象的抽象,面向接口,所有监听器中的方法都必须实现。2.是单纯的抽象,能够可选地进行回调需要的方法。下面我就自己写了两种方式的回调,及说明使用场景。

    方式一:使用接口(使用场景:自定义View时作为事件监听器)

    /**
     * 自定义列表头视图
     * 
     * @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();
                }
            });

    方式二:使用抽象类(异步任务结果返回)

    /**
     * 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();
        }

    使用的时候便要实现其中的抽象方法。

    final ApkFileSearcher searcher = new ApkFileSearcher(keyword) {
                    @Override
                    public void onSearchFinished(List<AppsBean> result) {
                        //在界面对结果进行处理。如传入并构建列表适配器
                    }
                };

    再次感慨这前人伟大的发明,无敌的回调设计,当然,使用回调方法也有弊端,个人认为大量使用匿名内部类将降低代码的可读性,用的时候需要慎重,不过,贵在用之方便,依旧强调它的特点--恰到好处

  • 相关阅读:
    基于Qt的图像处理技术和算法
    项目中使用到的算法
    C++将数组的元素顺序随机打乱
    Windows环境下 RabbitMQ集群配置
    Nginx负载均衡配置
    SQL Server Profiler:使用方法和指标说明
    如何查看IIS并发连接数
    23种设计模式的趣味理解
    C# 开源框架(整理)
    git 简易教程
  • 原文地址:https://www.cnblogs.com/changewu/p/3229089.html
Copyright © 2020-2023  润新知