【问题标题】:Break SQL query into parts for accessing content provider将 SQL 查询分解为访问内容提供程序的部分
【发布时间】:2020-02-18 13:59:56
【问题描述】:

我有一个来自字符串的 SQL 查询并试图访问 ContentProvider。 sql查询如下:

String query = "SELECT * FROM application_settings WHERE _id = ?";

我必须通过获取ContentResolver 来访问内容提供者,例如:

context.getContentResolver().query()

但查询方法接受:

Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);

有没有办法可以将字符串查询拆分为投影、选择、selectionArgs 和 sortOrder?

我不希望执行原始查询,因此我希望有一个带有绑定值的函数的解决方案。

【问题讨论】:

    标签: android android-sqlite android-contentprovider


    【解决方案1】:

    我刚刚编写了一个库,它可以提供您需要的东西。您只需将其复制并粘贴到项目中,如果您想根据需要添加、扩展和自定义它。

    SqliteHandler.java

    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    import android.util.Log;
    
    class SqliteHandler {
    // VERY IMPORTANT MAKE SURE IT'S CORRECT AND REGISTERED IN THE MANIFEST
    private String PROVIDER_NAME = "com.example.android.mySqlite";
    private String CONTENT_URL = "content://" + PROVIDER_NAME + "/";
    private Context context;
    
    SqliteHandler(Context context, String PROVIDER_NAME) {
        this.context = context;
        this.PROVIDER_NAME = PROVIDER_NAME;
    }
    
    Cursor exeQuery(String query) {
        try {
            queryObject obj = convertQueryStringToQueryObject(query);
            return context.getContentResolver().query(obj.uri, obj.projection, obj.selection, obj.selectionArgs, null);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    Cursor exeQuery(String query, String[] selectionArgs) {
        try {
            queryObject obj = convertQueryStringToQueryObject(query);
            return context.getContentResolver().query(obj.uri, obj.projection, obj.selection, selectionArgs, null);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    Cursor exeQuery(String query, String selection, String[] selectionArgs) {
        try {
            queryObject obj = convertQueryStringToQueryObject(query);
            return context.getContentResolver().query(obj.uri, obj.projection, selection, selectionArgs, null);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    Cursor exeQuery(String query, String[] projection, String[] selectionArgs) {
        try {
            queryObject obj = convertQueryStringToQueryObject(query);
            return context.getContentResolver().query(obj.uri, projection, obj.selection, selectionArgs, null);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    Cursor exeQuery(queryObject obj) {
        try {
            return context.getContentResolver().query(obj.uri, obj.projection, obj.selection, obj.selectionArgs, null);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    
    class queryObject {
        Uri uri;
        String[] projection;
        String selection;
        String[] selectionArgs;
        String sortOrder;
    
        queryObject(String table_name, String[] projection, String selection, String[]
                selectionArgs) {
            this.uri = Uri.parse(CONTENT_URL + table_name);
            this.projection = projection;
            this.selection = selection;
            this.selectionArgs = selectionArgs;
        }
    }
    
    queryObject convertQueryStringToQueryObject(String query) {
        try {
            String selection = null;
            String[] selectionArgs = null;
            query = query.toLowerCase();
            String[] s = query.split("select")[1].split("from");
            String[] projection = s[0].split(",");
            String[] s2 = s[1].split("where");
            String table_name = s2[0];
            String logText = "";
            if (s2.length > 1) {
                selection = s2[1];
                String[] args = s2[1].split("=");
                selectionArgs = new String[args.length - 1];// half of the args are values others are keys
                int count = 0;
                for (int i = 1; i < args.length; i++) {
                    selectionArgs[count] = args[i]
                            .split("and")[0]
                            .split("or")[0]
                            .replace(" ", "")
                            .replace("and", "")
                            .replace("or", "");
                    count++;
                }
                for (int i = 0; i < selectionArgs.length; i++) {
                    logText += selectionArgs[i];
                    if (i < selectionArgs.length - 1) logText += ",";
                    selection = selection.replace(selectionArgs[i], "?");
                }
            }
            Log.i("table_name", table_name);
            Log.i("selection: ", selection == null ? "null" : selection);
            Log.i("selectionArgs", logText.equals("") ? "null" : logText);
            logText = "";
            for (int i = 0; i < projection.length; i++) {
                logText += projection[i];
                if (i < projection.length - 1) logText += ",";
            }
            Log.i("projection", logText);
            return new queryObject(table_name, projection, selection, selectionArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }}
    

    如何使用

    实例化SqliteHandler,传递有效的PROVIDER_NAME 并确保您的CONTENT_PROVIDER 已在AndroidManiFest.xml 中注册非常重要。为了说明它是如何工作的,我们传递三个不同的查询并获得返回值,它们是 queryObject 类型的对象

    SqliteHandler sh = new SqliteHandler(this,"PROVIDER_NAME");
    SqliteHandler.queryObject obj1 = sh.convertQueryStringToQueryObject("SELECT * FROM table_name");
    SqliteHandler.queryObject obj2 = sh.convertQueryStringToQueryObject("SELECT * FROM table_name WHERE _id = ?");
    SqliteHandler.queryObject obj3 = sh.convertQueryStringToQueryObject("SELECT param1,param2,param3 FROM table_name WHERE param1 =\"a\" and param2=\"b\" or param3=\"c\"");
    

    convertQueryStringToQueryObject 方法将query string 转换为query class 然后我们可以将这个类用于getContentResolver().query()


    重要提示:因为getContentResolver().query() 需要Uri。因此,我们需要从table_name 创建一个Uri。因此,我们需要将有效的PROVIDER_NAME 传递给SqliteHandler 的实例。


    输出日志

    如您所见,三个不同的查询分解为参数,我们可以在 getContentResolver().query() 中使用这些参数

    // 1th query 
    I/table_name:  table_name
    I/selection:: null
    I/selectionArgs: null
    I/projection:  * 
    // 2th query 
    I/table_name:  table_name 
    I/selection::  _id = ?
    I/selectionArgs: ?
    I/projection:  * 
    // 3th query 
    I/table_name:  table_name 
    I/selection::  param1 =? and param2=? or param3=?
    I/selectionArgs: "a","b","c"
    I/projection:  param1,param2,param3 
    

    完整示例

    SqliteHandler.java 中有exeQuery 方法,它有几个重载。此外,根据不同的输入参数,您可以在Content Provider处有一个Cursor

    SqliteHandler sh = new SqliteHandler(this,"PROVIDER_NAME");
    SqliteHandler.queryObject obj1 = sh.convertQueryStringToQueryObject("SELECT * FROM table_name");
    SqliteHandler.queryObject obj2 = sh.convertQueryStringToQueryObject("SELECT * FROM table_name WHERE _id = ?");
    SqliteHandler.queryObject obj3 = sh.convertQueryStringToQueryObject("SELECT param1,param2,param3 FROM table_name WHERE param1 =\"a\" and param2=\"b\" or param3=\"c\"");
    Cursor c = sh.exeQuery(obj1);
    Cursor c = sh.exeQuery(obj2);
    Cursor c = sh.exeQuery(obj3);
    Cursor c = sh.exeQuery("SELECT param1,param2,param3 FROM table_name WHERE param1 =\"a\" and param2=\"b\" or param3=\"c\"");
    Cursor c = sh.exeQuery("SELECT * FROM table_name WHERE _id = ?",new String[]{"whereArg"});
    Cursor c = sh.exeQuery("SELECT * FROM table_name"," _id = ? ",new String[]{"whereArg"});
    Cursor c = sh.exeQuery("SELECT ? FROM table_name WHERE _id = ?",new String[]{"Field"},new String[]{"whereArg"});
    

    但是,如果您不想使用 exeQuery,请尝试以下操作:

    queryObject obj = convertQueryStringToQueryObject(query);
    Cursor c = this.getContentResolver().query(obj.uri, obj.projection, obj.selection, obj.selectionArgs, null);
    

    【讨论】:

    • 即使您的答案最终有效,但肯定还有很大的改进空间,因为这可能会在很多地方崩溃。但结果是它有效,所以谢谢你的回答
    • @matrix 欢迎您,我在 github 中创建了一个存储库来发布错误和崩溃。我很乐意为此做出贡献。 github.com/MrAshFar/SqliteHandler
    【解决方案2】:

    来自安卓文档https://developer.android.com/guide/topics/providers/content-provider-basics#ClientProvider

    cursor = getContentResolver().query(
        UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
        projection,                        // The columns to return for each row
        selectionClause,                   // Selection criteria
        selectionArgs,                     // Selection criteria
        sortOrder);                        // The sort order for the returned rows
    

    你可以这样做

    String[] projection = {"*"};
    String[] selectionArgs = {"1", "2"}; //your ids here
    Cursor cursor = getContentResolver().query(Uri.parse("content://your_provider/your_table"), projection, "_id", selectionArgs, null);
    cursor.close();
    

    要创建提供程序,请参阅https://developer.android.com/guide/topics/providers/content-provider-creating#top_of_page

    也看到这个答案https://stackoverflow.com/a/1031101/10989990

    【讨论】:

    • 这不是我问的
    猜你喜欢
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多