android搜索的关联性判断,Android之搜索框+含搜索历史记录

需求背景

今天在讨论群里,发现有多位童鞋们问到了这个问题,于是乎,产生了撸个轮子玩玩!这也是我第一次以这样方式玩简书,希望能帮助童鞋们解决实际中的问题,这才是重点!

知识要点梳理

使用Android自带的SQLiteOpenHelper

数据库的增删改查

sql 语句的编写

下面开始开车啦,老司机们赶紧上车哦!!哈哈。。。

1.撸个页面

activity_main.xml

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">

android:textColor="@color/gray"

android:textSize="14sp"

android:layout_marginTop="10dp"

android:layout_width="match_parent"

android:layout_height="45dp">

android:id="@+id/btn_serarch"

android:layout_width="80dp"

android:layout_height="match_parent"

android:layout_alignParentRight="true"

android:hint="搜索"/>

android:id="@+id/et_search"

android:hint="输入内容"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_toLeftOf="@id/btn_serarch"/>

android:padding="10dp"

android:layout_width="match_parent"

android:layout_height="wrap_content">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="历史记录"/>

android:id="@+id/tv_deleteAll"

android:layout_alignParentRight="true"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="删除历史记录"/>

android:id="@+id/mRecyclerView"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_marginTop="10dp">

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 extends RecyclerView.Adapter{

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. 我知道效果图才是老铁们的最爱:造就完了

71272b3e2a9b

view1.gif

问题反馈:

这几天陆续有几位老铁反馈,下载demo运行是没有问题,但用在自己的项目中报错(具体报错信息请看老铁的留言),原因很简单,baseAdapter 复制代码不全,导致的。

解决方案:

1.使用自己定义adapter即可。

2.直接copy demo里面的baseAdapter,不建议,自己手写一半,复制一半,导致复制代码不全。

71272b3e2a9b

yhx.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值