Android中如何优化实时搜索

前言背景

在App开发过程中,搜索功能是必不可少的。一般对于搜索功能,要么是输入一段文字后自己手动点击搜索按钮进行搜索;要么是实时的搜索。如果输入框中每一个字符的改变都要去触发网络请求的话,会浪费用户的流量,增大服务器的负载,并且使页面比较卡顿。这显然是不可取的。举一个很简单的例子,用户想要搜索 “ABC” ,如果我们直接用TextWatcher监听里面的afterTextChanged(Editable s)方法来处理的话,会向服务器发送3次请求。显然这会造成差的用户体验并浪费网路资源。

失败的实现方式

显然我们还是要从TextWatcher 这个监听下做文章,下面是实时搜索失败的实现方式。
 /**
  *  EditText 设置的监听
  *
  */
private TextWatcher mSearchWatch = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            String searchword = s.toString().trim();
            Log.e("tianzhu", searchword);
            startSearch(searchword);
        }
    };

  /**
  *  开始P层搜索
  *
  */
 private void startSearch(String keyword) {
        if (TextUtils.isEmpty(keyword)) {
            return;
        }
        mPresenter.searchData(keyword);
        mSearchEdit.clearFocus();
    }

在上面的方式中,每一个字符的改变都要去触发网络请求的话,会浪费用户的流量,增大服务器的负载,并且使页面比较卡顿。

优化的实现方式

我们可以思考,既然每次文本框的改变都会回调 afterTextChanged(Editable s) ,我进行优化的策略是当EditText中两次改变在 500ms 内不会触发搜索。当输入框文字在500ms 内未发生改变时,再触发搜索。

 /**
  *  EditText 设置的监听
  *
  */
private TextWatcher mSearchWatch = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            String searchword = s.toString().trim();
            //我们可以把每次输入框改变的字符串传给一个工具类,并让它来判断是否进行搜索
             mOptionSearch.optionSearch(searchword);
            Log.e("tianzhu", searchword);

        }
    };

  /**
  *  开始P层搜索
  *
  */
 private void startSearch(String keyword) {
        if (TextUtils.isEmpty(keyword)) {
            return;
        }
        mPresenter.searchData(keyword);
        mSearchEdit.clearFocus();
    }

 @Override
 public void getKeyword(String keyword) {
        //开始搜索
        if (!TextUtils.isEmpty(keyword) && mPresenter != null) {
              startSearch(keyword);
          }
    }

**
 * Created by tianzhu on 17/3/15.
 * 搜索优化,快速点击不会一直触发搜索,这也是最关键的类
 */
public class OptionSearch implements CommonHandler.MessageHandler {
    private String currentWord;
    private IFinishListener mListener;

    private MyRunnable myRunnable = new MyRunnable();

    private CommonHandler mHandler;

    /**
     * 点击按钮响应间隔时间-毫秒
     */
    private int INTERVAL_TIME = 500;

    public OptionSearch(Looper looper) {
        mHandler = new CommonHandler(looper, this);
    }

    /**
     * 这一步就是实时搜索优化的关键代码了,当EditText中的文字发生改变时,我们先会将handle中的Callback移除掉。然后使用Handle发一个延时的消息。最后通过回调getKeyword,让Activity开始搜索
     */
    public void optionSearch(String keyword) {
        this.currentWord = keyword;
        if (myRunnable != null) {
            mHandler.removeCallbacks(myRunnable);
        }
        mHandler.postDelayed(myRunnable, INTERVAL_TIME);
    }

    public void setListener(IFinishListener listener) {
        this.mListener = listener;
    }

    @Override
    public void handleMessage(Message msg) {
            if(mListener!=null){
                mListener.getKeyword(currentWord);
            }
    }


    public interface IFinishListener {
        void getKeyword(String keyword);
    }

    private class MyRunnable implements Runnable {

        @Override
        public void run() {
            mHandler.sendEmptyMessage(1);
        }
    }


}

/**
 * Created by tianzhu on 2016/07/19.
 * 防止内存泄露handle
 */
public class CommonHandler extends Handler {

    public interface MessageHandler {
        void handleMessage(Message msg);
    }

    private WeakReference<MessageHandler> mMessageHandler;

    public CommonHandler(MessageHandler msgHandler) {
        mMessageHandler = new WeakReference<MessageHandler>(msgHandler);
    }

    public CommonHandler(Looper looper, MessageHandler msgHandler) {
        super(looper);
        mMessageHandler = new WeakReference<MessageHandler>(msgHandler);
    }

    @Override
    public void handleMessage(Message msg) {
        MessageHandler realHandler = mMessageHandler.get();
        if (realHandler != null) {
            realHandler.handleMessage(msg);
        }
    }
}

总结

1.在用户快速输入的过程中不触发搜索
2.使用弱引用避免Handler内存泄露
3.使用Handler的 postDelayed 方法 发送延时消息。当用户快速输入时,使用mHandler.removeCallbacks(myRunnable),将当前Handler的中的Callback移除。重新发一个postDelayed。

这样就做到了实时搜索的,小伙伴们赶紧试试吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值