Android之搜索框+含搜索历史记录
16lz
2021-01-25
需求背景
今天在讨论群里,发现有多位童鞋们问到了这个问题,于是乎,产生了撸个轮子玩玩!这也是我第一次以这样方式玩简书,希望能帮助童鞋们解决实际中的问题,这才是重点!
知识要点梳理
1.使用Android自带的SQLiteOpenHelper
2.数据库的增删改查
3.sql 语句的编写
下面开始开车啦,老司机们赶紧上车哦!!哈哈。。。
1.撸个页面
activity_main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.yhx.app.MainActivity"> <RelativeLayout android:textColor="@color/gray" android:textSize="14sp" android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="45dp"> <Button android:id="@+id/btn_serarch" android:layout_width="80dp" android:layout_height="match_parent" android:layout_alignParentRight="true" android:hint="搜索"/> <EditText android:id="@+id/et_search" android:hint="输入内容" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_toLeftOf="@id/btn_serarch"/> RelativeLayout> <RelativeLayout android:padding="10dp" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="历史记录"/> <TextView android:id="@+id/tv_deleteAll" android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="删除历史记录"/> RelativeLayout> <android.support.v7.widget.RecyclerView android:id="@+id/mRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="10dp"> android.support.v7.widget.RecyclerView>LinearLayout>
2.使用Android自带的SQLiteOpenHelper来创建表数据
/** * Created by yi.huangxing on 17/12/13.类描述: */public class RecordSQLiteOpenHelper extends SQLiteOpenHelper{ private static String name = "record.db"; private static Integer version = 1; public RecordSQLiteOpenHelper(Context context) { super(context, name, null, version); } @Override public void onCreate(SQLiteDatabase db) { //打开数据库,建立了一个叫records的表,里面只有一列name来存储历史记录: db.execSQL("create table records(id integer primary key autoincrement,name varchar(200))"); } @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { }}
3.表数据建好了,当然就是数据库的增,删,改,查,啰,为了使代码可读性性强,来个Dao层吧,那就叫DbDao
注意了,代码中的注释都是关键点,容易出错的地方哦。。。
public class DbDao { private Context context; private RecordSQLiteOpenHelper helper; private SQLiteDatabase db; public DbDao(Context context) { this.context = context; init(); } private void init() { //实例化数据库SQLiteOpenHelper子类对象 helper = new RecordSQLiteOpenHelper(context); // 第一次进入时查询所有的历史记录 queryData(""); } public List queryData(String tempName) { List data = new ArrayList<>(); //模糊搜索 Cursor cursor = helper.getReadableDatabase().rawQuery( "select id as _id,name from records where name like '%" + tempName + "%' order by id desc ", null); while (cursor.moveToNext()) { //注意这里的name跟建表的name统一 String name = cursor.getString(cursor.getColumnIndex("name")); data.add(name); } cursor.close(); return data; } /** * 检查数据库中是否已经有该条记录 * * @param tempName * @return */ public boolean hasData(String tempName) { //从Record这个表里找到name=tempName的id Cursor cursor = helper.getReadableDatabase().rawQuery( "select id as _id,name from records where name =?", new String[]{tempName}); //判断是否有下一个 return cursor.moveToNext(); } /** * 插入数据 * * @param tempName */ public void insertData(String tempName) { db = helper.getWritableDatabase(); db.execSQL("insert into records(name) values('" + tempName + "')"); db.close(); } /** * 插入数据 * * @param name * @return */ public int delete(String name) { // 获取数据 SQLiteDatabase db = helper.getWritableDatabase(); // 执行SQL int delete = db.delete("records", " name=?", new String[]{name}); // 关闭数据库连接 db.close(); return delete; } /** * 清空数据 */ public void deleteData() { db = helper.getWritableDatabase(); db.execSQL("delete from records"); db.close(); }}
4.如何使用?
public class MainActivity extends AppCompatActivity { private Button mbtn_serarch; private EditText met_search; private RecyclerView mRecyclerView; private TextView mtv_deleteAll; private SeachRecordAdapter mAdapter; private DbDao mDbDao; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); } private void initViews() { mDbDao =new DbDao(this); mbtn_serarch = (Button) findViewById(R.id.btn_serarch); met_search = (EditText) findViewById(R.id.et_search); mtv_deleteAll = (TextView) findViewById(R.id.tv_deleteAll); mtv_deleteAll.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mDbDao.deleteData(); mAdapter.updata(mDbDao.queryData("")); } }); mRecyclerView = (RecyclerView) findViewById(R.id.mRecyclerView); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mAdapter =new SeachRecordAdapter(mDbDao.queryData(""),this); mAdapter.setRvItemOnclickListener(new BaseRecycleAdapter.RvItemOnclickListener() { @Override public void RvItemOnclick(int position) { mDbDao.delete(mDbDao.queryData("").get(position)); mAdapter.updata(mDbDao.queryData("")); } }); mRecyclerView.setAdapter(mAdapter); //事件监听 mbtn_serarch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (met_search.getText().toString().trim().length() != 0){ boolean hasData = mDbDao.hasData(met_search.getText().toString().trim()); if (!hasData){ mDbDao.insertData(met_search.getText().toString().trim()); }else { Toast.makeText(MainActivity.this, "该内容已在历史记录中", Toast.LENGTH_SHORT).show(); } // mAdapter.updata(mDbDao.queryData("")); }else { Toast.makeText(MainActivity.this, "请输入内容", Toast.LENGTH_SHORT).show(); } } }); }}
5.demo中我使用了baseAdapter, 一并撸上吧
/** * Created by yi.huangxing on 17/12/13.类描述: */public abstract class BaseRecycleAdapter <T> extends RecyclerView.Adapter<BaseRecycleAdapter.BaseViewHolder>{ protected List datas; protected Context mContext; public BaseRecycleAdapter(List datas,Context mContext) { this.datas = datas; this.mContext =mContext; } // 头部控件 private View mHeaderView; // 底部控件 private View mFooterView; // item 的三种类型 public static final int ITEM_TYPE_NORMAL = 0X1111; // 正常的item类型 public static final int ITEM_TYPE_HEADER = 0X1112; // header public static final int ITEM_TYPE_FOOTER = 0X1113; // footer private boolean isHasHeader = false; private boolean isHasFooter = false; @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if(viewType==ITEM_TYPE_FOOTER){ // 如果是底部类型,返回底部视图 return new BaseViewHolder(mFooterView); } if(viewType==ITEM_TYPE_HEADER){ return new BaseViewHolder(mHeaderView); } View view = LayoutInflater.from(parent.getContext()).inflate(getLayoutId(),parent,false); return new BaseViewHolder(view); } @Override public void onBindViewHolder(BaseRecycleAdapter.BaseViewHolder holder, final int position) { if(isHasHeader&&isHasFooter){ // 有头布局和底部时,向前便宜一个,且最后一个不能绑定数据 if(position==0 ||position==datas.size()+1){ return; } bindData(holder,position-1); } if(position!=0&&isHasHeader&&!isHasFooter){ // 有顶部,但没有底部 bindData(holder,position-1); } if(!isHasHeader&&isHasFooter){ // 没有顶部,但有底部 if(position==datas.size()){ return; } bindData(holder,position); } if(!isHasHeader&&!isHasFooter){ // 没有顶部,没有底部 bindData(holder,position); } } /** * 添加头部视图 * @param header */ public void setHeaderView(View header){ this.mHeaderView = header; isHasHeader = true; notifyDataSetChanged(); } /** * 添加底部视图 * @param footer */ public void setFooterView(View footer){ this.mFooterView = footer; isHasFooter = true; notifyDataSetChanged(); } @Override public int getItemViewType(int position) { // 根据索引获取当前View的类型,以达到复用的目的 // 根据位置的索引,获取当前position的类型 if(isHasHeader&&position==0){ return ITEM_TYPE_HEADER; } if(isHasHeader&&isHasFooter&&position==datas.size()+1){ // 有头部和底部时,最后底部的应该等于size+! return ITEM_TYPE_FOOTER; }else if(!isHasHeader&&isHasFooter&&position==datas.size()){ // 没有头部,有底部,底部索引为size return ITEM_TYPE_FOOTER; } return ITEM_TYPE_NORMAL; } /** * 刷新数据 * @param datas */ public void refresh(List datas){ this.datas.clear(); this.datas.addAll(datas); notifyDataSetChanged(); } /** * 刷新数据 * @param data */ public void updata(List data){ this.datas=data; notifyDataSetChanged(); } /** * 添加数据 * @param datas */ public void addData(List datas){ this.datas.addAll(datas); notifyDataSetChanged(); } /** * 移除数据 * * @param position */ public void remove(int position) { if (position >= 0 && position < datas.size()) { datas.remove(position); notifyDataSetChanged(); } } /** * 绑定数据 * @param holder 具体的viewHolder * @param position 对应的索引 */ protected abstract void bindData(BaseViewHolder holder, int position); @Override public int getItemCount() { int size = datas.size(); if(isHasFooter) size ++; if(isHasHeader) size++; return size; } /** * 封装ViewHolder ,子类可以直接使用 */ public class BaseViewHolder extends RecyclerView.ViewHolder{ private Map mViewMap; public BaseViewHolder(View itemView) { super(itemView); mViewMap = new HashMap<>(); } /** * 获取设置的view * @param id * @return */ public View getView(int id) { View view = mViewMap.get(id); if (view == null) { view = itemView.findViewById(id); mViewMap.put(id, view); } return view; } } /** * 获取子item * @return */ public abstract int getLayoutId(); /** * 设置文本属性 * @param view * @param text */ public void setItemText(View view,String text){ if(view instanceof TextView){ ((TextView) view).setText(text); } } public RvItemOnclickListener getRvItemOnclickListener() { return mRvItemOnclickListener; } public void setRvItemOnclickListener(RvItemOnclickListener rvItemOnclickListener) { mRvItemOnclickListener = rvItemOnclickListener; } protected RvItemOnclickListener mRvItemOnclickListener; public interface RvItemOnclickListener{ void RvItemOnclick(int position); } /** * 这个方法很重要的 * @param holder *///// @Override// public void onAttachedToRecyclerView(RecyclerView recyclerView) {// super.onAttachedToRecyclerView(recyclerView);//// RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();// if(manager instanceof GridLayoutManager) {// final GridLayoutManager gridManager = ((GridLayoutManager) manager);// gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {// @Override// public int getSpanSize(int position) {// return getItemViewType(position) == TYPE_HEADER// ? gridManager.getSpanCount() : 1;// }// });// }// }}
6. 我知道效果图才是老铁们的最爱:造就完了
7.简书地址:https://www.jianshu.com/p/71272b3e2a9b
如有帮助,不妨点赞+评论+关注哦!!!!
更多相关文章
- “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
- Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
- 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
- Android与JavaScript交互
- 理解Android中的引用类型
- Android中ListView通过ContextMenu删除当前点击的一行数据
- android中json数据的解析
- Android中Sqlite数据库多线程并发问题
- android 与 C# socket之间的收发数据