通过ContentResolver.query,或AsyncQueryHandler中的startQuery方法如何加入SQLite中的GROUP BY语句

本文介绍在异步查询环境下如何利用SQL的GROUP BY功能来获取特定联系人的最新消息记录。通过AsyncQueryHandler的startQuery方法及合理设置参数,可以有效地实现按联系人分组并获取最新消息的需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题是这样的:
在项目中,需要从消息的数据库中得到每个联系人最新的消息,并且显示到界面上,类似于咱们手机上短信列表那样。那么,在诸多的消息中,如何得到每一个联系人对应的聊天记录呢?只要把每个人对应的聊天记录找到,就可以知道与这个联系人通信的最后一条聊天记录是哪个了。在SQL中,如果数据库中有联系人字段,那么我们就可以用GROUP BY来将属于同一联系人的消息都查询出来了。然而,我需要异步查询,或者通过ContentResolver对象来查询的话,要怎么写各个参数呢?

例如:在AsyncQueryHandler中,startQuery()方法的参数分别为:
int token: 令牌,和onQueryConplete一致;
Object cookies: 要携带的对象;
Uri uri: 要访问数据库的uri;
String[] projection: 要查询的字段集合;
String selection: 查询条件;
String[] selectionArgs: 匹配查询条件中的“?”;
String orderBy: 排序规则。

其中,我们一般是通过uri、selection和selectionArgs来限制查询数据库后要返回的数据的,selection在SQL中,是WHERE后面的语句。那如果我想要加上GROUP BY,要写到哪个参数里面呢?

代码中,我是这么实现的:
String where = “0==0) GROUP BY (“+……;
所以,只要加上“0==0)”,在其后面加上你想要实现的GROUP BY语句就可以啦~~
不过要注意括号哦~~~

分析以下报错信息: Failed to execute the transaction: tId:295913160 ClientTransaction{ tId:295913160 transactionItems=[ tId:295913160 LaunchActivityItem{activityToken=android.os.BinderProxy@b6a90f7,intent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 xflg=0x4 cmp=com.example.contacts2/.MainActivity },ident=264802081,info=ActivityInfo{4ffa7a8 com.example.contacts2.MainActivity},curConfig={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h866dp 420dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2337) mMaxBounds=Rect(0, 0 - 1080, 2400) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.86 fontWeightAdjustment=0},overrideConfig={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h866dp 420dpi nrml long port finger qwerty/v/v dpad/v winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2337) mMaxBounds=Rect(0, 0 - 1080, 2400) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0} s.2 fontWeightAdjustment=0},deviceId=0,referrer=com.android.shell,procState=2,state=null,persistentState=null,pendingResults=null,pendingNewIntents=null,sceneTransitionInfo=null,profilerInfo=null,assistToken=android.os.BinderProxy@711f745,shareableActivityToken=android.os.BinderProxy@5b7e9a,activityWindowInfo=ActivityWindowInfo{isEmbedded=false, taskBounds=Rect(0, 0 - 1080, 2400), taskFragmentBounds=Rect(0, 0 - 1080, 2400)}} tId:295913160 ResumeActivityItem{mActivityToken=android.os.BinderProxy@b6a90f7,procState=-1,isForward=true,shouldSendCompatFakeFocus=false} tId:295913160 Target activity: com.example.contacts2.MainActivity tId:295913160 ] tId:295913160 } 2025-07-22 13:25:30.038 10369-10369 AndroidRuntime com.example.contacts2 D Shutting down VM 2025-07-22 13:25:30.039 10369-10369 AndroidRuntime com.example.contacts2 E FATAL EXCEPTION: main Process: com.example.contacts2, PID: 10369 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.contacts2/com.example.contacts2.MainActivity}: android.database.sqlite.SQLiteException: unrecognized token: ":" (code 1 SQLITE_ERROR): , while compiling: SELECT phonetic_name, status_updates.status_res_package AS status_res_package, custom_ringtone, contacts_status_updates.status_ts AS contact_status_ts, account_type, data_version, photo_file_id, contacts_status_updates.status_res_package AS contact_status_res_package, group_sourceid, display_name_alt, sort_key_alt, presence.mode AS mode, 0 AS last_time_used, starred, contacts_status_updates.status_label AS contact_status_label, has_phone_number, presence.chat_capability AS chat_capability, raw_contact_id, carrier_presence, contact_last_updated_timestamp, res_package, photo_uri, data_sync4, phonebook_bucket, 0 AS times_used, display_name, sort_key, data_sync1, version, data_sync2, data_sync3, photo_thumb_uri, status_updates.status_label AS status_label, agg_presence.mode AS contact_presence, in_default_directory, 0 AS times_contacted, _id, account_type_and_data_set, name_raw_contact_id, status_updates.status AS status, phonebook_bucket_alt, 0 AS last_time_contacted, pinned, is_primary, photo_id, contact_id, agg_presence.chat_capability AS contact_chat_capability, contacts_status_updates.status_icon AS contact_status_icon, in_visible_group, phonebook_label, account_name, display_name_source, data9, dirty, sourceid, phonetic_name_style, send_to_voicemail, data8, lookup, data7, data6, phonebook_label_alt, data5, is_super_primary, data4, data3, data2, data1, data_set, contacts_status_updates.status AS contact_status, backup_id, preferred_phone_account_component_name, raw_contact_is_user_profile, status_updates.status_ts AS status_ts, data10, preferred_phone_account_id, data12, mimetype, status_updates.status_icon AS status_icon, data11, data14, data13, hash_id, data15 FROM view_data data LEFT OUTER JOIN agg_presence ON (contact_id = agg_presence.presence_contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id) LEFT OUTER JOIN presence ON (presence_data_id=data._id) LEFT OUTER JOIN status_updates ON (status_updates.status_update_data_id=data._id) LEFT OUTER JOIN (SELECT 0 as STAT_DATA_ID,0 as x_times_used, 0 as x_last_time_used,0 as times_used, 0 as last_time_used where 0) as data_usage_stat ON (STAT_DATA_ID=data._id) WHERE (1 AND mimetype_id=5) AND (content://com.android.contacts/data/phones=1) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4280) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4467) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:222) at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:133) at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:103) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:80) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2823) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loopOnce(Looper.java:248) at android.os.Looper.loop(Looper.java:338) at android.app.ActivityThread.main(ActivityThread.java:9067) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932) 2025-07-22 13:25:30.041 10369-10369 AndroidRuntime com.example.contacts2 E Caused by: android.database.sqlite.SQLiteException: unrecognized token: ":" (code 1 SQLITE_ERROR): , while compiling: SELECT phonetic_name, status_updates.status_res_package AS status_res_package, custom_ringtone, contacts_status_updates.status_ts AS contact_status_ts, account_type, data_version, photo_file_id, contacts_status_updates.status_res_package AS contact_status_res_package, group_sourceid, display_name_alt, sort_key_alt, presence.mode AS mode, 0 AS last_time_used, starred, contacts_status_updates.status_label AS contact_status_label, has_phone_number, presence.chat_capability AS chat_capability, raw_contact_id, carrier_presence, contact_last_updated_timestamp, res_package, photo_uri, data_sync4, phonebook_bucket, 0 AS times_used, display_name, sort_key, data_sync1, version, data_sync2, data_sync3, photo_thumb_uri, status_updates.status_label AS status_label, agg_presence.mode AS contact_presence, in_default_directory, 0 AS times_contacted, _id, account_type_and_data_set, name_raw_contact_id, status_updates.status AS status, phonebook_bucket_alt, 0 AS last_time_contacted, pinned, is_primary, photo_id, contact_id, agg_presence.chat_capability AS contact_chat_capability, contacts_status_updates.status_icon AS contact_status_icon, in_visible_group, phonebook_label, account_name, display_name_source, data9, dirty, sourceid, phonetic_name_style, send_to_voicemail, data8, lookup, data7, data6, phonebook_label_alt, data5, is_super_primary, data4, data3, data2, data1, data_set, contacts_status_updates.status AS contact_status, backup_id, preferred_phone_account_component_name, raw_contact_is_user_profile, status_updates.status_ts AS status_ts, data10, preferred_phone_account_id, data12, mimetype, status_updates.status_icon AS status_icon, data11, data14, data13, hash_id, data15 FROM view_data data LEFT OUTER JOIN agg_presence ON (contact_id = agg_presence.presence_contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id) LEFT OUTER JOIN presence ON (presence_data_id=data._id) LEFT OUTER JOIN status_updates ON (status_updates.status_update_data_id=data._id) LEFT OUTER JOIN (SELECT 0 as STAT_DATA_ID,0 as x_times_used, 0 as x_last_time_used,0 as times_used, 0 as last_time_used where 0) as data_usage_stat ON (STAT_DATA_ID=data._id) WHERE (1 AND mimetype_id=5) AND (content://com.android.contacts/data/phones=1) at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:197) at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:153) at android.content.ContentProviderProxy.query(ContentProviderNative.java:495) at android.content.ContentResolver.query(ContentResolver.java:1231) at android.content.ContentResolver.query(ContentResolver.java:1163) at android.content.ContentResolver.query(ContentResolver.java:1119) at com.example.contacts2.MainActivity.readContacts(MainActivity.java:66) at com.example.contacts2.MainActivity.onCreate(MainActivity.java:36) at android.app.Activity.performCreate(Activity.java:9155) at android.app.Activity.performCreate(Activity.java:9133) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1521) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4262) ... 13 more ---------------------------- PROCESS ENDED (10369) for package com.example.contacts2 ----------------------------
最新发布
07-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值