![JAR search and dependency download from the Maven repository](/logo.png)
com.avos.avoscloud.im.v2.AVIMMessageStorage Maven / Gradle / Ivy
The newest version!
package com.avos.avoscloud.im.v2;
import android.annotation.TargetApi;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.text.TextUtils;
import com.alibaba.fastjson.JSON;
import com.avos.avoscloud.AVOSCloud;
import com.avos.avoscloud.AVUtils;
import com.avos.avoscloud.LogUtil;
import com.avos.avoscloud.im.v2.AVIMMessage.AVIMMessageStatus;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by lbt05 on 4/13/15.
*/
@TargetApi(8)
class AVIMMessageStorage {
static final int MESSAGE_INNERTYPE_BIN = 1;
static final int MESSAGE_INNERTYPE_PLAIN = 0;
static final String DB_NAME_PREFIX = "com.avos.avoscloud.im.v2.";
static final String MESSAGE_TABLE = "messages";
static final String MESSAGE_INDEX = "message_index";
static final int DB_VERSION = 10;
static final String COLUMN_MESSAGE_ID = "message_id";
static final String COLUMN_TIMESTAMP = "timestamp";
static final String COLUMN_CONVERSATION_ID = "conversation_id";
static final String COLUMN_FROM_PEER_ID = "from_peer_id";
static final String COLUMN_MESSAGE_DELIVEREDAT = "receipt_timestamp";
static final String COLUMN_MESSAGE_READAT = "readAt";
static final String COLUMN_MESSAGE_UPDATEAT = "updateAt";
static final String COLUMN_PAYLOAD = "payload";
static final String COLUMN_STATUS = "status";
static final String COLUMN_BREAKPOINT = "breakpoint";
static final String COLUMN_DEDUPLICATED_TOKEN = "dtoken";
static final String COLUMN_MSG_MENTION_ALL = "mentionAll";
static final String COLUMN_MSG_MENTION_LIST = "mentionList";
static final String COLUMN_MSG_INNERTYPE = "iType";
static final String CONVERSATION_TABLE = "conversations";
static final String COLUMN_EXPIREAT = "expireAt";
static final String COLUMN_ATTRIBUTE = "attr";
static final String COLUMN_INSTANCEDATA = "instanceData";
static final String COLUMN_UPDATEDAT = "updatedAt";
static final String COLUMN_CREATEDAT = "createdAt";
static final String COLUMN_CREATOR = "creator";
static final String COLUMN_MEMBERS = "members";
static final String COLUMN_LM = "lm";
static final String COLUMN_LASTMESSAGE = "last_message";
static final String COLUMN_TRANSIENT = "isTransient";
static final String COLUMN_UNREAD_COUNT = "unread_count";
static final String COLUMN_CONV_MENTIONED = "mentioned";
static final String COLUMN_CONVERSATION_READAT = "readAt";
static final String COLUMN_CONVRESATION_DELIVEREDAT = "deliveredAt";
static final String COLUMN_CONV_LASTMESSAGE_INNERTYPE = "last_msg_iType";
static final String COLUMN_CONV_TEMP = "temp";
static final String COLUMN_CONV_TEMP_TTL = "temp_ttl";
static final String COLUMN_CONV_SYSTEM = "sys";
static final String NUMBERIC = "NUMBERIC";
static final String INTEGER = "INTEGER";
static final String BLOB = "BLOB";
static final String TEXT = "TEXT";
static final String VARCHAR32 = "VARCHAR(32)";
/**
* table: messages
* schema:
* |--------------------------------------------------------------------------------------------------------------------------------|
* |varchar |numberic |varchar |text |numberic |number |number |blob |int |int |varchar|
* |message_id |timestamp |conversation_id |from_peer_id |receipt_timestamp |readAt |updatedAt |payload |status |breakpoint |dtoken |
* |not null | |not null |not null | | | | | | | |
* | * | | * | <-- primary key |
* |--------------------------------------------------------------------------------------------------------------------------------|
*
* table: conversations
* schema:
* |---------------------------------------------------------------------------------------------------------------------------------------------------------------|
* |expireAt |attr |instanceData |updatedAt |createdAt |creator |members |lm |last_message |isTransient |unread_count |readAt |deliveredAt | sys | temp | temp_ttl |
* |---------------------------------------------------------------------------------------------------------------------------------------------------------------|
*
*/
static class SQL {
static final String TIMESTAMP_MORE_OR_TIMESTAMP_EQUAL_BUT_MESSAGE_ID_MORE_AND_CONVERSATION_ID =
" ( " +
COLUMN_TIMESTAMP + " > ? or (" + COLUMN_TIMESTAMP + " = ? and " + COLUMN_MESSAGE_ID
+ " > ? )) and " +
COLUMN_CONVERSATION_ID + " = ? ";
static final String TIMESTAMP_LESS_AND_CONVERSATION_ID = COLUMN_TIMESTAMP + " < ? and "
+ COLUMN_CONVERSATION_ID + " = ? ";
// 在时间戳第一排序,MessageId 第二排序的情况下,找到时间戳小于,或者时间戳等于但MessageId小于的消息
// 三条消息(时间戳/MessageId) 2/a、1/a、1/b, 则用 1/b 来找历史消息的时候,返回1/a
static final String TIMESTAMP_LESS_OR_TIMESTAMP_EQUAL_BUT_MESSAGE_ID_LESS_AND_CONVERSATION_ID =
" ( " +
COLUMN_TIMESTAMP + " < ? or (" + COLUMN_TIMESTAMP + " = ? and " + COLUMN_MESSAGE_ID
+ " < ? )) and " +
COLUMN_CONVERSATION_ID + " = ? ";
static final String ORDER_BY_TIMESTAMP_DESC_THEN_MESSAGE_ID_DESC =
COLUMN_TIMESTAMP + " desc, " + COLUMN_MESSAGE_ID + " desc";
static final String ORDER_BY_TIMESTAMP_ASC_THEN_MESSAGE_ID_ASC =
COLUMN_TIMESTAMP + " , " + COLUMN_MESSAGE_ID;
static final String DELETE_LOCAL_MESSAGE = COLUMN_CONVERSATION_ID + " = ? and " + COLUMN_MESSAGE_ID + " = ? and "
+ COLUMN_STATUS + " = ? and " + COLUMN_DEDUPLICATED_TOKEN + " = ? ";
static final String SELECT_VALID_CONVS = "("+ COLUMN_CONV_TEMP + " < 1 and " + COLUMN_EXPIREAT + " > ?) or (" + COLUMN_CONV_TEMP + "> 0 and " + COLUMN_CONV_TEMP_TTL + " > ?)";
}
private DBHelper dbHelper;
private static ConcurrentHashMap storages =
new ConcurrentHashMap();
static class DBHelper extends SQLiteOpenHelper {
static final String MESSAGE_CREATE_SQL =
"CREATE TABLE IF NOT EXISTS " + MESSAGE_TABLE + " ("
+ COLUMN_CONVERSATION_ID + " VARCHAR(32) NOT NULL, "
+ COLUMN_MESSAGE_ID + " VARCHAR(32) NOT NULL, "
+ COLUMN_TIMESTAMP + " NUMBERIC, "
+ COLUMN_FROM_PEER_ID + " TEXT NOT NULL, "
+ COLUMN_MESSAGE_DELIVEREDAT + " NUMBERIC, "
+ COLUMN_MESSAGE_READAT + " NUMBERIC, "
+ COLUMN_MESSAGE_UPDATEAT + " NUMBERIC, "
+ COLUMN_PAYLOAD + " BLOB, "
+ COLUMN_STATUS + " INTEGER, "
+ COLUMN_BREAKPOINT + " INTEGER, "
+ COLUMN_DEDUPLICATED_TOKEN + " VARCHAR(32), "
+ COLUMN_MSG_MENTION_ALL + " INTEGER default 0, "
+ COLUMN_MSG_MENTION_LIST + " TEXT NULL, "
+ COLUMN_MSG_INNERTYPE + " INTEGER default 0, "
+ "PRIMARY KEY(" + COLUMN_CONVERSATION_ID + "," + COLUMN_MESSAGE_ID + ")) ";
static final String MESSAGE_UNIQUE_INDEX_SQL =
"CREATE UNIQUE INDEX IF NOT EXISTS " + MESSAGE_INDEX + " on " + MESSAGE_TABLE + " ("
+ COLUMN_CONVERSATION_ID + ", " + COLUMN_TIMESTAMP + ", " + COLUMN_MESSAGE_ID + ") ";
static final String CONVERSATION_CREATE_SQL = "CREATE TABLE IF NOT EXISTS "
+ CONVERSATION_TABLE + " ("
+ COLUMN_CONVERSATION_ID + " VARCHAR(32) NOT NULL,"
+ COLUMN_EXPIREAT + " NUMBERIC,"
+ COLUMN_ATTRIBUTE + " BLOB,"
+ COLUMN_INSTANCEDATA + " BLOB,"
+ COLUMN_UPDATEDAT + " VARCHAR(32),"
+ COLUMN_CREATEDAT + " VARCHAR(32),"
+ COLUMN_CREATOR + " TEXT,"
+ COLUMN_MEMBERS + " TEXT,"
+ COLUMN_TRANSIENT + " INTEGER,"
+ COLUMN_UNREAD_COUNT + " INTEGER,"
+ COLUMN_CONVERSATION_READAT + " NUMBERIC,"
+ COLUMN_CONVRESATION_DELIVEREDAT + " NUMBERIC,"
+ COLUMN_LM + " NUMBERIC,"
+ COLUMN_LASTMESSAGE + " TEXT,"
+ COLUMN_CONV_MENTIONED + " INTEGER default 0,"
+ COLUMN_CONV_LASTMESSAGE_INNERTYPE + " INTEGER default 0, "
+ COLUMN_CONV_SYSTEM + " INTEGER default 0, "
+ COLUMN_CONV_TEMP + " INTEGER default 0, "
+ COLUMN_CONV_TEMP_TTL + " NUMBERIC, "
+ "PRIMARY KEY(" + COLUMN_CONVERSATION_ID + "))";
public DBHelper(Context context, String clientId) {
super(context, getDatabasePath(clientId), null, DB_VERSION);
}
private static String getDatabasePath(String clientId) {
// 要 MD5 ?
return DB_NAME_PREFIX + clientId;
}
private static String getAddColumnSql(String table, String column, String type) {
return String.format("ALTER TABLE %s ADD COLUMN %s %s;", table, column, type);
}
private static String getAddColumnSql(String table, String column, String type, String defaultV) {
return String.format("ALTER TABLE %s ADD COLUMN %s %s default %s;", table, column, type, defaultV);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(MESSAGE_CREATE_SQL);
sqLiteDatabase.execSQL(MESSAGE_UNIQUE_INDEX_SQL);
sqLiteDatabase.execSQL(CONVERSATION_CREATE_SQL);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
if (oldVersion == 1) {
upgradeToVersion2(sqLiteDatabase);
oldVersion += 1;
}
if (oldVersion == 2) {
upgradeToVersion3(sqLiteDatabase);
oldVersion += 1;
}
if (oldVersion == 3) {
upgradeToVersion4(sqLiteDatabase);
oldVersion += 1;
}
if (oldVersion == 4) {
upgradeToVersion5(sqLiteDatabase);
oldVersion += 1;
}
if (oldVersion == 5) {
upgradeToVersion6(sqLiteDatabase);
oldVersion += 1;
}
if (oldVersion == 6) {
upgradeToVersion7(sqLiteDatabase);
oldVersion += 1;
}
if (oldVersion == 7) {
upgradeToVersion8(sqLiteDatabase);
oldVersion += 1;
}
if (oldVersion == 8) {
upgradeToVersion9(sqLiteDatabase);
oldVersion += 1;
}
if (oldVersion == 9) {
upgradeToVersion10(sqLiteDatabase);
oldVersion += 1;
}
}
private void upgradeToVersion2(SQLiteDatabase db) {
db.execSQL(CONVERSATION_CREATE_SQL);
}
private void upgradeToVersion3(SQLiteDatabase db) {
try {
if (!columnExists(db, MESSAGE_TABLE, COLUMN_DEDUPLICATED_TOKEN)) {
db.execSQL(getAddColumnSql(MESSAGE_TABLE, COLUMN_DEDUPLICATED_TOKEN, VARCHAR32));
}
} catch (Exception e) {}
}
private void upgradeToVersion4(SQLiteDatabase db) {
try {
if (!columnExists(db, CONVERSATION_TABLE, COLUMN_LASTMESSAGE)) {
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_LASTMESSAGE, TEXT));
}
} catch (Exception e) {}
}
private void upgradeToVersion5(SQLiteDatabase db) {
try {
if (!columnExists(db, CONVERSATION_TABLE, COLUMN_INSTANCEDATA)) {
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_INSTANCEDATA, BLOB));
}
} catch (Exception e) {
}
}
private void upgradeToVersion6(SQLiteDatabase db) {
try {
if (!columnExists(db, CONVERSATION_TABLE, COLUMN_UNREAD_COUNT)) {
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_UNREAD_COUNT, INTEGER));
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_CONVERSATION_READAT, NUMBERIC));
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_CONVRESATION_DELIVEREDAT, NUMBERIC));
}
if (!columnExists(db, MESSAGE_TABLE, COLUMN_MESSAGE_READAT)) {
db.execSQL(getAddColumnSql(MESSAGE_TABLE, COLUMN_MESSAGE_READAT, NUMBERIC));
}
} catch (Exception e) {
}
}
private void upgradeToVersion7(SQLiteDatabase db) {
try {
if (!columnExists(db, MESSAGE_TABLE, COLUMN_MESSAGE_UPDATEAT)) {
db.execSQL(getAddColumnSql(MESSAGE_TABLE, COLUMN_MESSAGE_UPDATEAT, NUMBERIC));
}
} catch (Exception e) {
}
}
private void upgradeToVersion8(SQLiteDatabase db) {
try {
if (!columnExists(db, MESSAGE_TABLE, COLUMN_MSG_MENTION_ALL)) {
db.execSQL(getAddColumnSql(MESSAGE_TABLE, COLUMN_MSG_MENTION_ALL, INTEGER, "0"));
}
if (!columnExists(db, MESSAGE_TABLE, COLUMN_MSG_MENTION_LIST)) {
db.execSQL(getAddColumnSql(MESSAGE_TABLE, COLUMN_MSG_MENTION_LIST, TEXT));
}
if (!columnExists(db, CONVERSATION_TABLE, COLUMN_CONV_MENTIONED)) {
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_CONV_MENTIONED, INTEGER, "0"));
}
} catch (Exception e) {
}
}
private void upgradeToVersion9(SQLiteDatabase db) {
try {
if (!columnExists(db, MESSAGE_TABLE, COLUMN_MSG_INNERTYPE)) {
db.execSQL(getAddColumnSql(MESSAGE_TABLE, COLUMN_MSG_INNERTYPE, INTEGER, "0"));
}
if (!columnExists(db, CONVERSATION_TABLE, COLUMN_CONV_LASTMESSAGE_INNERTYPE)) {
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_CONV_LASTMESSAGE_INNERTYPE, INTEGER, "0"));
}
} catch (Exception e) {
}
}
private void upgradeToVersion10(SQLiteDatabase db) {
try {
if (!columnExists(db, CONVERSATION_TABLE, COLUMN_CONV_SYSTEM)) {
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_CONV_SYSTEM, INTEGER, "0"));
}
if (!columnExists(db, CONVERSATION_TABLE, COLUMN_CONV_TEMP)) {
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_CONV_TEMP, INTEGER, "0"));
}
if (!columnExists(db, CONVERSATION_TABLE, COLUMN_CONV_TEMP_TTL)) {
db.execSQL(getAddColumnSql(CONVERSATION_TABLE, COLUMN_CONV_TEMP_TTL, NUMBERIC));
}
} catch (Exception ex) {
;
}
}
private static boolean columnExists(SQLiteDatabase db, String table, String column) {
try {
Cursor cursor = db.query(table, null, null, null, null, null, null);
return cursor.getColumnIndex(column) != -1;
} catch (Exception e) {
return false;
}
}
}
String clientId;
private AVIMMessageStorage(Context context, String clientId) {
dbHelper = new DBHelper(context, clientId);
// FIXME: 2017/8/22 it is not need to invoke onUpgrade manually.
dbHelper.onUpgrade(dbHelper.getWritableDatabase(), dbHelper.getWritableDatabase().getVersion(),
DB_VERSION);
this.clientId = clientId;
}
public synchronized static AVIMMessageStorage getInstance(String clientId) {
AVIMMessageStorage storage = storages.get(clientId);
if (storage != null) {
return storage;
} else {
storage = new AVIMMessageStorage(AVOSCloud.applicationContext, clientId);
AVIMMessageStorage elderStorage = storages.putIfAbsent(clientId, storage);
return elderStorage == null ? storage : elderStorage;
}
}
private static String getWhereClause(String... columns) {
List conditions = new ArrayList();
for (String column : columns) {
conditions.add(column + " = ? ");
}
return TextUtils.join(" and ", conditions);
}
public void insertMessage(AVIMMessage message, boolean breakpoint) {
if (null == message) {
return;
}
insertMessages(Arrays.asList(message), breakpoint);
}
/*
* 这个代码是用于插入由本地发送的消息,由于存在deduplicated Message 所以有些特殊,需要做额外的token检查
*/
public synchronized boolean insertLocalMessage(AVIMMessage message) {
if (null == message
|| !AVUtils.isBlankString(message.getMessageId())
|| AVUtils.isBlankString(message.conversationId)
|| AVUtils.isBlankString(message.uniqueToken)) {
if (null == message) {
LogUtil.avlog.e("message is null");
} else {
LogUtil.avlog.e(String.format("invalid state. msgId=%s, convId=%s, uniToken=%s", message.getMessageId(), message.conversationId, message.uniqueToken));
}
return false;
}
String internalMessageId = generateInternalMessageId(message.uniqueToken);
try {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_CONVERSATION_ID, message.conversationId);
values.put(COLUMN_MESSAGE_ID, internalMessageId);
values.put(COLUMN_TIMESTAMP, message.getTimestamp());
values.put(COLUMN_FROM_PEER_ID, message.getFrom());
if (message instanceof AVIMBinaryMessage) {
values.put(COLUMN_PAYLOAD, ((AVIMBinaryMessage)message).getBytes());
values.put(COLUMN_MSG_INNERTYPE, MESSAGE_INNERTYPE_BIN);
} else {
values.put(COLUMN_PAYLOAD, message.getContent().getBytes());
}
values.put(COLUMN_MESSAGE_DELIVEREDAT, message.getDeliveredAt());
values.put(COLUMN_MESSAGE_READAT, message.getReadAt());
values.put(COLUMN_MESSAGE_UPDATEAT, message.getUpdateAt());
values.put(COLUMN_STATUS, AVIMMessageStatus.AVIMMessageStatusFailed.getStatusCode());
values.put(COLUMN_BREAKPOINT, 0);
values.put(COLUMN_DEDUPLICATED_TOKEN, message.uniqueToken);
values.put(COLUMN_MSG_MENTION_ALL, message.isMentionAll()? 1: 0);
values.put(COLUMN_MSG_MENTION_LIST, message.getMentionListString());
long ret = db.insertWithOnConflict(MESSAGE_TABLE, null, values, SQLiteDatabase.CONFLICT_IGNORE);
if (ret < 0) {
LogUtil.avlog.e("failed to insert Message table. values=" + values.toString());
}
return ret != -1;
} catch (Exception ex) {
return false;
}
}
/**
* remove local message.
*
* @param message
*/
public synchronized boolean removeLocalMessage(AVIMMessage message) {
if (null == message
|| AVUtils.isBlankString(message.conversationId)
|| AVUtils.isBlankString(message.uniqueToken)) {
return false;
}
String internalMessageId = generateInternalMessageId(message.uniqueToken);
String status = String.valueOf(AVIMMessageStatus.AVIMMessageStatusFailed.getStatusCode());
try {
SQLiteDatabase db = dbHelper.getWritableDatabase();
int ret = db.delete(MESSAGE_TABLE, SQL.DELETE_LOCAL_MESSAGE,
new String[]{message.conversationId, internalMessageId, status, message.uniqueToken});
return ret > 0;
} catch (Exception ex) {
return false;
}
}
private String generateInternalMessageId(String uniqueToken) {
if (AVUtils.isBlankString(uniqueToken)) {
return "";
}
return uniqueToken;
}
private synchronized int insertMessages(List messages, boolean breakpoint) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
int insertCount = 0;
for (AVIMMessage message : messages) {
ContentValues values = new ContentValues();
values.put(COLUMN_CONVERSATION_ID, message.getConversationId());
values.put(COLUMN_MESSAGE_ID, message.getMessageId());
values.put(COLUMN_TIMESTAMP, message.getTimestamp());
values.put(COLUMN_FROM_PEER_ID, message.getFrom());
if (message instanceof AVIMBinaryMessage) {
values.put(COLUMN_PAYLOAD, ((AVIMBinaryMessage)message).getBytes());
values.put(COLUMN_MSG_INNERTYPE, MESSAGE_INNERTYPE_BIN);
} else {
values.put(COLUMN_PAYLOAD, message.getContent().getBytes());
values.put(COLUMN_MSG_INNERTYPE, MESSAGE_INNERTYPE_PLAIN);
}
values.put(COLUMN_MESSAGE_DELIVEREDAT, message.getDeliveredAt());
values.put(COLUMN_MESSAGE_READAT, message.getReadAt());
values.put(COLUMN_MESSAGE_UPDATEAT, message.getUpdateAt());
values.put(COLUMN_STATUS, message.getMessageStatus().getStatusCode());
values.put(COLUMN_BREAKPOINT, breakpoint ? 1 : 0);
values.put(COLUMN_MSG_MENTION_ALL, message.isMentionAll()? 1: 0);
values.put(COLUMN_MSG_MENTION_LIST, message.getMentionListString());
try {
long itemId =
db.insertWithOnConflict(MESSAGE_TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
boolean insert = itemId > -1;
if (insert) {
insertCount++;
}
} catch (SQLException e) {
if (AVOSCloud.isDebugLogEnabled()) {
e.printStackTrace();
}
}
}
db.setTransactionSuccessful();
db.endTransaction();
return insertCount;
}
/**
* 顺序由调用者保证,需要按照时间升序排列
* @param messages
* @param conversationId
*/
public void insertContinuousMessages(List messages, String conversationId) {
if (null == messages || messages.isEmpty() || AVUtils.isBlankString(conversationId)) {
return;
}
AVIMMessage firstMessage = messages.get(0);
List tailMessages = messages.subList(1, messages.size());
AVIMMessage lastMessage = messages.get(messages.size() - 1);
if (!containMessage(lastMessage)) {
AVIMMessage eldestMessage = getNextMessage(lastMessage);
if (eldestMessage != null) {
updateBreakpoints(Arrays.asList(eldestMessage), true, conversationId);
}
}
if (!tailMessages.isEmpty()) {
insertMessages(tailMessages, false);
// remove breakpoints
updateBreakpoints(tailMessages, false, conversationId);
}
insertMessage(firstMessage, true);
}
public boolean containMessage(AVIMMessage message) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query(MESSAGE_TABLE, new String[] {},
getWhereClause(COLUMN_CONVERSATION_ID, COLUMN_MESSAGE_ID),
new String[] {message.conversationId, message.getMessageId()}, null, null, null);
boolean contained = cursor.getCount() > 0;
cursor.close();
return contained;
}
protected synchronized void updateBreakpoints(List messages,
boolean breakpoint, String conversationId) {
// sqlite max ? variable size = 999
int batchSize = 900;
if (messages.size() > batchSize) {
updateBreakpointsForBatch(messages.subList(0, batchSize), breakpoint, conversationId);
updateBreakpoints(messages.subList(batchSize, messages.size()), breakpoint, conversationId);
} else {
updateBreakpointsForBatch(messages, breakpoint, conversationId);
}
}
private synchronized int updateBreakpointsForBatch(List messages,
boolean breakpoint, String conversationId) {
String[] arguments = new String[messages.size()];
List placeholders = new ArrayList();
int i;
for (i = 0; i < messages.size(); i++) {
AVIMMessage message = messages.get(i);
arguments[i] = message.getMessageId();
placeholders.add("?");
}
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(COLUMN_BREAKPOINT, breakpoint ? 1 : 0);
String joinedPlaceholders = TextUtils.join(",", placeholders);
int updateCount = db.update(MESSAGE_TABLE, cv, COLUMN_MESSAGE_ID
+ " in (" + joinedPlaceholders + ") ", arguments);
return updateCount;
}
public synchronized boolean updateMessage(AVIMMessage message, String originalId) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_TIMESTAMP, message.getTimestamp());
values.put(COLUMN_STATUS, message.getMessageStatus().getStatusCode());
values.put(COLUMN_MESSAGE_DELIVEREDAT, message.getDeliveredAt());
values.put(COLUMN_MESSAGE_READAT, message.getReadAt());
values.put(COLUMN_MESSAGE_UPDATEAT, message.getUpdateAt());
values.put(COLUMN_MESSAGE_ID, message.getMessageId());
values.put(COLUMN_MSG_MENTION_ALL, message.isMentionAll()? 1: 0);
values.put(COLUMN_MSG_MENTION_LIST, message.getMentionListString());
long itemId =
db.update(MESSAGE_TABLE, values, getWhereClause(COLUMN_MESSAGE_ID),
new String[] {originalId});
return itemId > -1;
}
synchronized boolean updateMessageForPatch(AVIMMessage message) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
if (message instanceof AVIMBinaryMessage) {
values.put(COLUMN_PAYLOAD, ((AVIMBinaryMessage)message).getBytes());
values.put(COLUMN_MSG_INNERTYPE, MESSAGE_INNERTYPE_BIN);
} else {
values.put(COLUMN_PAYLOAD, message.getContent());
values.put(COLUMN_MSG_INNERTYPE, MESSAGE_INNERTYPE_PLAIN);
}
values.put(COLUMN_STATUS, message.getMessageStatus().getStatusCode());
values.put(COLUMN_MESSAGE_UPDATEAT, message.getUpdateAt());
long itemId = db.update(MESSAGE_TABLE, values, getWhereClause(COLUMN_MESSAGE_ID),
new String[] {message.getMessageId()});
return itemId > -1;
}
public synchronized void deleteMessages(List messages, String conversationId) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
for (AVIMMessage message : messages) {
String messageId = message.getMessageId();
AVIMMessage nextMessage = getNextMessage(message);
if (nextMessage != null) {
updateBreakpoints(Arrays.asList(message), true, conversationId);
}
db.delete(MESSAGE_TABLE, getWhereClause(COLUMN_MESSAGE_ID),
new String[] {messageId});
}
}
public synchronized void deleteConversationData(String conversationId) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete(MESSAGE_TABLE, getWhereClause(COLUMN_CONVERSATION_ID),
new String[] {conversationId});
db.delete(CONVERSATION_TABLE, getWhereClause(COLUMN_CONVERSATION_ID),
new String[] {conversationId});
}
public synchronized void deleteClientData() {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete(MESSAGE_TABLE, null, null);
db.delete(CONVERSATION_TABLE, null, null);
}
/**
* 查询该消息是否为断点
*/
void getMessage(String msgId, long timestamp, String conversationId,
StorageMessageCallback callback) {
if (timestamp == 0) {
callback.done(null, false);
} else {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor;
if (msgId == null) {
cursor =
db.query(MESSAGE_TABLE, null, getWhereClause(COLUMN_TIMESTAMP, COLUMN_CONVERSATION_ID),
new String[] {Long.toString(timestamp), conversationId}, null, null, null, "1");
} else {
cursor = db.query(MESSAGE_TABLE, null, getWhereClause(COLUMN_MESSAGE_ID),
new String[] {msgId}, null, null, null, "1");
}
AVIMMessage message = null;
boolean breakpoint = false;
if (cursor.moveToFirst()) {
message = createMessageFromCursor(cursor);
breakpoint = cursor.getInt(cursor.getColumnIndex(COLUMN_BREAKPOINT)) != 0;
}
cursor.close();
callback.done(message, breakpoint);
}
}
void dumpMessages(String conversationId) {
long curTs = System.currentTimeMillis();
SQLiteDatabase db = dbHelper.getReadableDatabase();
String condition = SQL.TIMESTAMP_LESS_AND_CONVERSATION_ID;
String[] conditionArgs = new String[]{Long.toString(curTs), conversationId};
Cursor cursor = db.query(MESSAGE_TABLE, null, condition, conditionArgs, null, null, SQL.ORDER_BY_TIMESTAMP_DESC_THEN_MESSAGE_ID_DESC);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
AVIMMessage message = createMessageFromCursor(cursor);
boolean breakpoint = cursor.getInt(cursor.getColumnIndex(COLUMN_BREAKPOINT)) != 0;
System.out.println("msg: {id=" + message.getMessageId() + ", ts=" + message.getTimestamp() + ", breakpoint=" + breakpoint + "}");
cursor.moveToNext();
}
}
}
/**
* 根据条件查询本地缓存消息,消息有可能不连续,是否连续会通过 callback 返回
*
* @param msgId
* @param timestamp
* @param limit
* @param conversationId
* @param callback
*/
public void getMessages(String msgId, long timestamp, int limit, String conversationId,
StorageQueryCallback callback) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
String selection;
String[] selectionArgs;
if (timestamp > 0) {
if (msgId == null) {
selection = SQL.TIMESTAMP_LESS_AND_CONVERSATION_ID;
selectionArgs = new String[] {Long.toString(timestamp), conversationId};
} else {
selection = SQL.TIMESTAMP_LESS_OR_TIMESTAMP_EQUAL_BUT_MESSAGE_ID_LESS_AND_CONVERSATION_ID;
selectionArgs =
new String[] {Long.toString(timestamp), Long.toString(timestamp), msgId, conversationId};
}
} else {
selection = getWhereClause(COLUMN_CONVERSATION_ID);
selectionArgs = new String[] {conversationId};
}
Cursor cursor = db.query(MESSAGE_TABLE, null, selection, selectionArgs, null, null,
SQL.ORDER_BY_TIMESTAMP_DESC_THEN_MESSAGE_ID_DESC, limit + "");
processMessages(cursor, callback);
}
public long getMessageCount(String conversationId) {
AVIMMessage lastBreakPointMessage = this.getLatestMessageWithBreakpoint(conversationId, true);
SQLiteDatabase db = dbHelper.getReadableDatabase();
long messageCount = 0;
if (lastBreakPointMessage == null) {
messageCount =
DatabaseUtils.longForQuery(db, "select count(*) from " + MESSAGE_TABLE + " where "
+ COLUMN_CONVERSATION_ID + " = ?", new String[] {conversationId});
} else {
messageCount = DatabaseUtils.longForQuery(
db,
"select count(*) from " + MESSAGE_TABLE + " where "
+ COLUMN_CONVERSATION_ID + " = ? and (" + COLUMN_TIMESTAMP + " > ? or ( "
+ COLUMN_TIMESTAMP + " = ? and "
+ COLUMN_MESSAGE_ID + " >= ? )) order by "
+ SQL.ORDER_BY_TIMESTAMP_DESC_THEN_MESSAGE_ID_DESC,
new String[] {conversationId, String.valueOf(lastBreakPointMessage.timestamp),
String.valueOf(lastBreakPointMessage.timestamp),
lastBreakPointMessage.messageId});
}
return messageCount;
}
private AVIMMessage createMessageFromCursor(Cursor cursor) {
String mid = cursor.getString(cursor.getColumnIndex(COLUMN_MESSAGE_ID));
long timestamp = cursor.getLong(cursor.getColumnIndex(COLUMN_TIMESTAMP));
String cid = cursor.getString(cursor.getColumnIndex(COLUMN_CONVERSATION_ID));
String from = cursor.getString(cursor.getColumnIndex(COLUMN_FROM_PEER_ID));
long deliveredAt = cursor.getLong(cursor.getColumnIndex(COLUMN_MESSAGE_DELIVEREDAT));
long readAt = cursor.getLong(cursor.getColumnIndex(COLUMN_MESSAGE_READAT));
long updateAt = cursor.getLong(cursor.getColumnIndex(COLUMN_MESSAGE_UPDATEAT));
byte[] payload = cursor.getBlob(cursor.getColumnIndex(COLUMN_PAYLOAD));
String uniqueToken = cursor.getString(cursor.getColumnIndex(COLUMN_DEDUPLICATED_TOKEN));
int status = cursor.getInt(cursor.getColumnIndex(COLUMN_STATUS));
int mentionAll = cursor.getInt(cursor.getColumnIndex(COLUMN_MSG_MENTION_ALL));
String mentionListStr = cursor.getString(cursor.getColumnIndex(COLUMN_MSG_MENTION_LIST));
int innerType = cursor.getInt(cursor.getColumnIndex(COLUMN_MSG_INNERTYPE));
AVIMMessage message = null;
if (innerType == MESSAGE_INNERTYPE_BIN) {
message = new AVIMBinaryMessage(cid, from, timestamp, deliveredAt, readAt);
((AVIMBinaryMessage)message).setBytes(payload);
} else {
message = new AVIMMessage(cid, from, timestamp, deliveredAt, readAt);
message.setContent(new String(payload));
}
message.setMessageId(mid);
message.setUniqueToken(uniqueToken);
message.setMessageStatus(AVIMMessage.AVIMMessageStatus.getMessageStatus(status));
message.setUpdateAt(updateAt);
message.setMentionAll( mentionAll == 1);
message.setCurrentClient(this.clientId);
if (!AVUtils.isBlankString(mentionListStr)) {
message.setMentionListString(mentionListStr);
}
return AVIMMessageManager.parseTypedMessage(message);
}
private void processMessages(Cursor cursor, StorageQueryCallback callback) {
List messages = Collections.EMPTY_LIST;
List breakpoints = Collections.EMPTY_LIST;
if (cursor.moveToFirst()) {
messages = new ArrayList();
breakpoints = new ArrayList();
while (!cursor.isAfterLast()) {
AVIMMessage message = createMessageFromCursor(cursor);
messages.add(message);
boolean breakpoint = cursor.getInt(cursor.getColumnIndex(COLUMN_BREAKPOINT)) != 0;
breakpoints.add(breakpoint);
cursor.moveToNext();
}
}
cursor.close();
callback.done(messages, breakpoints);
}
protected AVIMMessage getNextMessage(AVIMMessage currentMessage) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor =
db.query(
MESSAGE_TABLE,
null,
SQL.TIMESTAMP_MORE_OR_TIMESTAMP_EQUAL_BUT_MESSAGE_ID_MORE_AND_CONVERSATION_ID,
new String[] {Long.toString(currentMessage.getTimestamp()),
Long.toString(currentMessage.getTimestamp()),
currentMessage.getMessageId(), currentMessage.getConversationId()}, null, null,
SQL.ORDER_BY_TIMESTAMP_ASC_THEN_MESSAGE_ID_ASC, "1");
AVIMMessage message = null;
if (cursor.moveToFirst()) {
message = createMessageFromCursor(cursor);
}
cursor.close();
return message;
}
AVIMMessage getLatestMessage(String conversationId) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query(MESSAGE_TABLE, null, getWhereClause(COLUMN_CONVERSATION_ID),
new String[] {conversationId}, null, null,
SQL.ORDER_BY_TIMESTAMP_DESC_THEN_MESSAGE_ID_DESC, "1");
AVIMMessage message = null;
if (cursor.moveToFirst()) {
message = createMessageFromCursor(cursor);
}
cursor.close();
return message;
}
AVIMMessage getLatestMessageWithBreakpoint(String conversationId, boolean breakpoint) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query(MESSAGE_TABLE, null,
getWhereClause(COLUMN_CONVERSATION_ID, COLUMN_BREAKPOINT),
new String[] {conversationId, breakpoint ? "1" : "0"}, null, null,
SQL.ORDER_BY_TIMESTAMP_DESC_THEN_MESSAGE_ID_DESC, "1");
AVIMMessage message = null;
if (cursor.moveToFirst()) {
message = createMessageFromCursor(cursor);
}
cursor.close();
return message;
}
public interface StorageQueryCallback {
void done(List messages, List breakpoints);
}
public interface StorageMessageCallback {
void done(AVIMMessage message, boolean breakpoint);
}
public void insertConversations(List conversations) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
for (AVIMConversation conversation : conversations) {
ContentValues values = new ContentValues();
values.put(COLUMN_ATTRIBUTE, JSON.toJSONString(conversation.attributes));
values.put(COLUMN_INSTANCEDATA, JSON.toJSONString(conversation.instanceData));
values.put(COLUMN_CREATEDAT, conversation.createdAt);
values.put(COLUMN_UPDATEDAT, conversation.updatedAt);
values.put(COLUMN_CREATOR, conversation.creator);
values.put(COLUMN_EXPIREAT, System.currentTimeMillis()
+ Conversation.DEFAULT_CONVERSATION_EXPIRE_TIME_IN_MILLS);
if (conversation.lastMessageAt != null) {
values.put(COLUMN_LM, conversation.lastMessageAt.getTime());
}
final AVIMMessage message = conversation.getLastMessage();
if (null != message) {
if (message instanceof AVIMBinaryMessage) {
byte[] bytes = ((AVIMBinaryMessage)message).getBytes();
String base64Msg = AVUtils.base64Encode(bytes);
values.put(COLUMN_LASTMESSAGE, base64Msg);
values.put(COLUMN_CONV_LASTMESSAGE_INNERTYPE, MESSAGE_INNERTYPE_BIN);
} else {
String lastMessage = JSON.toJSONString(message);
values.put(COLUMN_LASTMESSAGE, lastMessage);
values.put(COLUMN_CONV_LASTMESSAGE_INNERTYPE, MESSAGE_INNERTYPE_PLAIN);
}
}
values.put(COLUMN_MEMBERS, JSON.toJSONString(conversation.getMembers()));
values.put(COLUMN_TRANSIENT, conversation.isTransient ? 1 : 0);
values.put(COLUMN_UNREAD_COUNT, conversation.getUnreadMessagesCount());
values.put(COLUMN_CONV_MENTIONED, conversation.unreadMessagesMentioned()? 1:0);
values.put(COLUMN_CONVERSATION_READAT, conversation.getLastReadAt());
values.put(COLUMN_CONVRESATION_DELIVEREDAT, conversation.getLastDeliveredAt());
values.put(COLUMN_CONVERSATION_ID, conversation.getConversationId());
// add temporary conversation data.
values.put(COLUMN_CONV_SYSTEM, conversation.isSystem()? 1 : 0);
values.put(COLUMN_CONV_TEMP, conversation.isTemporary()? 1 : 0);
values.put(COLUMN_CONV_TEMP_TTL, conversation.getTemporaryExpiredat());
// if (AVOSCloud.isDebugLogEnabled()) {
// LogUtil.avlog.d(String.format("insert or update conversation: %s", values.toString()));
// }
//
db.insertWithOnConflict(CONVERSATION_TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
db.setTransactionSuccessful();
db.endTransaction();
}
boolean updateConversationTimes(AVIMConversation conversation) {
if (getConversation(conversation.getConversationId()) != null) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_CONVERSATION_READAT, conversation.getLastReadAt());
values.put(COLUMN_CONVRESATION_DELIVEREDAT, conversation.getLastDeliveredAt());
long dbId = db.update(CONVERSATION_TABLE, values, getWhereClause(COLUMN_CONVERSATION_ID),
new String[] {conversation.getConversationId()});
return dbId != -1;
}
return false;
}
boolean updateConversationUreadCount(String conversationId, long unreadCount, boolean mentioned) {
if (getConversation(conversationId) != null) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_UNREAD_COUNT, unreadCount);
values.put(COLUMN_CONV_MENTIONED, mentioned? 1:0);
long dbId = db.update(CONVERSATION_TABLE, values, getWhereClause(COLUMN_CONVERSATION_ID),
new String[] {conversationId});
return dbId != -1;
}
return false;
}
public boolean updateConversationLastMessageAt(AVIMConversation conversation) {
if (getConversation(conversation.getConversationId()) != null
&& conversation.getLastMessageAt() != null) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_LM, conversation.getLastMessageAt().getTime());
long dbId = db.update(CONVERSATION_TABLE, values, getWhereClause(COLUMN_CONVERSATION_ID),
new String[] {conversation.getConversationId()});
return dbId != -1;
}
return false;
}
public List getAllCachedConversations() {
List conversations = new LinkedList();
long currentTs = System.currentTimeMillis();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor =
db.query(CONVERSATION_TABLE, null, SQL.SELECT_VALID_CONVS,
new String[] {String.valueOf(currentTs), String.valueOf(currentTs/1000)}, null, null, null,
null);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
conversations.add(parseConversationFromCursor(cursor));
cursor.moveToNext();
}
}
cursor.close();
return conversations;
}
private AVIMConversation parseConversationFromCursor(Cursor cursor) {
String conversationId = cursor.getString(cursor.getColumnIndex(COLUMN_CONVERSATION_ID));
String createdAt = cursor.getString(cursor.getColumnIndex(COLUMN_CREATEDAT));
String updatedAt = cursor.getString(cursor.getColumnIndex(COLUMN_UPDATEDAT));
String membersStr = cursor.getString(cursor.getColumnIndex(COLUMN_MEMBERS));
String attrsStr = cursor.getString(cursor.getColumnIndex(COLUMN_ATTRIBUTE));
String instanceData = cursor.getString(cursor.getColumnIndex(COLUMN_INSTANCEDATA));
String creator = cursor.getString(cursor.getColumnIndex(COLUMN_CREATOR));
long lastMessageTS = cursor.getLong(cursor.getColumnIndex(COLUMN_LM));
int transientValue = cursor.getInt(cursor.getColumnIndex(COLUMN_TRANSIENT));
int unreadCount = cursor.getInt(cursor.getColumnIndex(COLUMN_UNREAD_COUNT));
int mentioned = cursor.getInt(cursor.getColumnIndex(COLUMN_CONV_MENTIONED));
long readAt = cursor.getLong(cursor.getColumnIndex(COLUMN_CONVERSATION_READAT));
long deliveredAt = cursor.getLong(cursor.getColumnIndex(COLUMN_CONVRESATION_DELIVEREDAT));
String lastMessage = cursor.getString(cursor.getColumnIndex(COLUMN_LASTMESSAGE));
int lastMessageInnerType = cursor.getInt(cursor.getColumnIndex(COLUMN_CONV_LASTMESSAGE_INNERTYPE));
int system = cursor.getInt(cursor.getColumnIndex(COLUMN_CONV_SYSTEM));
int temporary = cursor.getInt(cursor.getColumnIndex(COLUMN_CONV_TEMP));
AVIMConversation conversation = null;
if (temporary > 0) {
conversation = new AVIMTemporaryConversation(AVIMClient.getInstance(clientId), conversationId);
long tempExpiredAt = cursor.getLong(cursor.getColumnIndex(COLUMN_CONV_TEMP_TTL));
conversation.setTemporaryExpiredat(tempExpiredAt);
} else if (system > 0) {
conversation = new AVIMServiceConversation(AVIMClient.getInstance(clientId), conversationId);
} else if (transientValue > 0) {
conversation = new AVIMChatRoom(AVIMClient.getInstance(clientId), conversationId);
} else {
conversation = new AVIMConversation(AVIMClient.getInstance(clientId), conversationId);
}
// if (AVOSCloud.isDebugLogEnabled()) {
// LogUtil.avlog.d(String.format("parse conversation: id=%s, creator=%s, transient=%d, sys=%d, temp=%d, return=%s",
// conversationId, creator, transientValue, system, temporary, conversation.getClass().getSimpleName()));
// }
//
conversation.createdAt = createdAt;
conversation.updatedAt = updatedAt;
try {
conversation.members.clear();
if (!AVUtils.isBlankContent(membersStr)) {
conversation.members.addAll(JSON.parseObject(membersStr, Set.class));
}
conversation.attributes.clear();
if (!AVUtils.isBlankContent(attrsStr)) {
conversation.attributes.putAll(JSON.parseObject(attrsStr, HashMap.class));
}
conversation.instanceData.clear();
if (!AVUtils.isBlankContent(instanceData)) {
conversation.instanceData.putAll(JSON.parseObject(instanceData, HashMap.class));
}
if (lastMessageInnerType != MESSAGE_INNERTYPE_BIN) {
AVIMMessage msg = JSON.parseObject(lastMessage, AVIMMessage.class);
conversation.lastMessage = msg;
} else {
AVIMBinaryMessage binaryMsg = new AVIMBinaryMessage(conversationId, null);// don't care who sent message.
binaryMsg.setBytes(AVUtils.base64Decode(lastMessage));
conversation.lastMessage = binaryMsg;
}
} catch (Exception e) {
if (AVOSCloud.isDebugLogEnabled()) {
LogUtil.avlog.e("error during conversation cache parse:" + e.getMessage());
}
}
conversation.creator = creator;
conversation.lastMessageAt = new Date(lastMessageTS);
conversation.unreadMessagesCount = unreadCount;
conversation.unreadMessagesMentioned = mentioned == 1;
conversation.lastReadAt = readAt;
conversation.lastDeliveredAt = deliveredAt;
return conversation;
}
public AVIMConversation getConversation(String conversationId) {
AVIMConversation conversation = null;
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor =
db.query(CONVERSATION_TABLE, null, getWhereClause(COLUMN_CONVERSATION_ID) + " and "
+ COLUMN_EXPIREAT + " > ?",
new String[] {conversationId, String.valueOf(System.currentTimeMillis())}, null, null,
null,
null);
if (cursor.moveToFirst()) {
if (!cursor.isAfterLast()) {
conversation = parseConversationFromCursor(cursor);
}
}
cursor.close();
return conversation;
}
public List getCachedConversations(List conversationIds) {
List conversations = new LinkedList();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor =
db.rawQuery("SELECT * FROM " + CONVERSATION_TABLE + " WHERE " + COLUMN_CONVERSATION_ID
+ " in ('" + AVUtils.joinCollection(conversationIds, "','") + "')", null);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
conversations.add(parseConversationFromCursor(cursor));
cursor.moveToNext();
}
}
cursor.close();
return conversations;
}
public void deleteConversation(String conversationId) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete(CONVERSATION_TABLE, getWhereClause(COLUMN_CONVERSATION_ID),
new String[] {conversationId});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy