安卓查询系统数据库(ContentResolver)带关键字解决方法
前言
一个类似把手机中文件查询出来的需求,按关键字模糊搜索,测试提了一个bug,说输入 “\”,“%”,"_"这三个特殊字符,得到的搜索结果是异常的.
ContentResolver的query方法简略介绍
我们项目是用安卓的ContentResolver的query方法去搜索系统的原生数据库的,使用的是以下方法:
public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,@Nullable String[] projection, @Nullable String selection,@Nullable String[] selectionArgs, @Nullable String sortOrder) {return query(uri, projection, selection, selectionArgs, sortOrder, null);}
参数含义为
uri
- 查询的表名
projection
- 查询表所需要返回的列
selection
- 查询条件
selectionArgs
- 查询条件的参数
sortOrder
- 排序(升序或者降序)
光说可能有点抽象,我们详细解释一下,例如下面的SQL查询语句:
SELECT artist,title FROM files WHERE media_type=2 and title LIKE '%off%'
我们将SQL查询语句中的条件换成query方法的参数, 就是如下:
private val mResolver = mContext.contentResolverfun test(){//注意:这里是伪代码,方便理解mResolver.query(files, [artist,title], "media_type= ? and title LIKE ?"",[2 , '%off%'], null)}
方法了解到这里就差不多了
问题分析
从前言问题可以得出,是特殊格式符号的搜索结果不正确,那么我们直接用SQL语句去数据库里面查特殊符号,方便排查问题,语句类似如下:
SELECT artist FROM files WHERE media_type=2 and title LIKE '%\_%'
发现,查询出来的并不是我们想要的结果,百度过后发现是因为这些特殊符号其实是SQL语句中的关键字,并不是查询带下划线的数据,因此我们需要将这种关键字替换成可以被当成普通字符查询的API,这时候就要使用到 ESCAPE,它可以帮助我们达到这一目的,我们将上述SQL语句改为如下:
SELECT artist FROM files WHERE media_type=2 and title LIKE '%\_%' ESCAPE '\'
这时,就能得出我们想要的正确结果.
问题解决
我们找到了问题原因,但是安卓查询数据库的写法与SQL不同,需要注意写法,例如,我们有问题的代码如下:
private val mResolver = mContext.contentResolverfun test(queryString : String){val selection = "title like ? "mResolver.query(uri, null, selection, arrayOf("%$queryString%"), null)}
那么我们更改后的代码应该为如下:
private val mResolver = mContext.contentResolverfun test(query : String){val queryString = query.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")val selection = "title like ? ESCAPE '\'"mResolver.query(uri, null, selection, arrayOf("%$queryString%"), null)}
在正确的代码中,我们先将要查询的语句进行转义,然后在真正查询的时候ESCAPE掉,达到将关键字作为搜索语句的效果.