improved database performance
fixed auto complete hashtag icon
This commit is contained in:
parent
dd729d2d5c
commit
fe5a6eb6c6
|
@ -35,7 +35,7 @@ import static android.text.TextUtils.isEmpty;
|
|||
|
||||
public class ContentResolverUtils {
|
||||
|
||||
private static final int MAX_DELETE_COUNT = 128;
|
||||
public static final int MAX_BULK_COUNT = 128;
|
||||
|
||||
public static <T> int bulkDelete(final ContentResolver resolver, final Uri uri, final String inColumn,
|
||||
final Collection<T> colValues, final String extraWhere, final boolean valuesIsString) {
|
||||
|
@ -47,10 +47,10 @@ public class ContentResolverUtils {
|
|||
final T[] colValues, final String extraWhere, final boolean valuesIsString) {
|
||||
if (resolver == null || uri == null || isEmpty(inColumn) || colValues == null || colValues.length == 0)
|
||||
return 0;
|
||||
final int col_values_length = colValues.length, blocks_count = col_values_length / MAX_DELETE_COUNT + 1;
|
||||
final int col_values_length = colValues.length, blocks_count = col_values_length / MAX_BULK_COUNT + 1;
|
||||
int rows_deleted = 0;
|
||||
for (int i = 0; i < blocks_count; i++) {
|
||||
final int start = i * MAX_DELETE_COUNT, end = Math.min(start + MAX_DELETE_COUNT, col_values_length);
|
||||
final int start = i * MAX_BULK_COUNT, end = Math.min(start + MAX_BULK_COUNT, col_values_length);
|
||||
final String[] block = TwidereArrayUtils.toStringArray(TwidereArrayUtils.subArray(colValues, start, end));
|
||||
if (valuesIsString) {
|
||||
final StringBuilder where = new StringBuilder(inColumn + " IN(" + TwidereArrayUtils.toStringForSQL(block)
|
||||
|
@ -78,10 +78,10 @@ public class ContentResolverUtils {
|
|||
|
||||
public static int bulkInsert(final ContentResolver resolver, final Uri uri, final ContentValues[] values) {
|
||||
if (resolver == null || uri == null || values == null || values.length == 0) return 0;
|
||||
final int colValuesLength = values.length, blocksCount = colValuesLength / MAX_DELETE_COUNT + 1;
|
||||
final int colValuesLength = values.length, blocksCount = colValuesLength / MAX_BULK_COUNT + 1;
|
||||
int rowsInserted = 0;
|
||||
for (int i = 0; i < blocksCount; i++) {
|
||||
final int start = i * MAX_DELETE_COUNT, end = Math.min(start + MAX_DELETE_COUNT, colValuesLength);
|
||||
final int start = i * MAX_BULK_COUNT, end = Math.min(start + MAX_BULK_COUNT, colValuesLength);
|
||||
final ContentValues[] block = new ContentValues[end - start];
|
||||
System.arraycopy(values, start, block, 0, end - start);
|
||||
rowsInserted += resolver.bulkInsert(uri, block);
|
||||
|
|
|
@ -129,6 +129,12 @@ public class Expression implements SQLLang {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public static Expression like(final Column column, final SQLLang expression) {
|
||||
return new Expression(String.format(Locale.ROOT, "%s LIKE %s", column.getSQL(), expression.getSQL()));
|
||||
}
|
||||
|
||||
|
||||
public static Expression likeRaw(final Column column, final String pattern) {
|
||||
return new Expression(String.format(Locale.ROOT, "%s LIKE %s", column.getSQL(), pattern));
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.mariotaku.querybuilder.query.SQLDropTriggerQuery;
|
|||
import org.mariotaku.querybuilder.query.SQLDropViewQuery;
|
||||
import org.mariotaku.querybuilder.query.SQLInsertQuery;
|
||||
import org.mariotaku.querybuilder.query.SQLSelectQuery;
|
||||
import org.mariotaku.querybuilder.query.SQLUpdateQuery;
|
||||
|
||||
public class SQLQueryBuilder {
|
||||
|
||||
|
@ -105,6 +106,10 @@ public class SQLQueryBuilder {
|
|||
return new SQLInsertQuery.Builder().insertInto(onConflict, table);
|
||||
}
|
||||
|
||||
public static SQLUpdateQuery.Builder update(final OnConflict onConflict, final Table table) {
|
||||
return new SQLUpdateQuery.Builder().update(onConflict, table);
|
||||
}
|
||||
|
||||
public static SQLInsertQuery.Builder insertInto(final String table) {
|
||||
return insertInto(null, table);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ import java.util.Locale;
|
|||
public class SetValue implements SQLLang {
|
||||
|
||||
private final Columns.Column column;
|
||||
private final Expression expression;
|
||||
private final SQLLang expression;
|
||||
|
||||
public SetValue(Columns.Column column, Expression expression) {
|
||||
public SetValue(Columns.Column column, SQLLang expression) {
|
||||
this.column = column;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.mariotaku.querybuilder.Expression;
|
|||
import org.mariotaku.querybuilder.OnConflict;
|
||||
import org.mariotaku.querybuilder.SQLQuery;
|
||||
import org.mariotaku.querybuilder.SetValue;
|
||||
import org.mariotaku.querybuilder.Table;
|
||||
import org.mariotaku.querybuilder.Utils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
@ -11,7 +12,7 @@ import java.util.Locale;
|
|||
public class SQLUpdateQuery implements SQLQuery {
|
||||
|
||||
private OnConflict onConflict;
|
||||
private String table;
|
||||
private Table table;
|
||||
private SetValue[] values;
|
||||
private Expression where;
|
||||
|
||||
|
@ -27,7 +28,7 @@ public class SQLUpdateQuery implements SQLQuery {
|
|||
if (onConflict != null) {
|
||||
sb.append(String.format(Locale.ROOT, "OR %s ", onConflict.getAction()));
|
||||
}
|
||||
sb.append(String.format(Locale.ROOT, "%s ", table));
|
||||
sb.append(String.format(Locale.ROOT, "%s ", table.getSQL()));
|
||||
sb.append(String.format(Locale.ROOT, "SET %s ", Utils.toString(values, ',', false)));
|
||||
if (where != null) {
|
||||
sb.append(String.format(Locale.ROOT, "WHERE %s ", where.getSQL()));
|
||||
|
@ -47,7 +48,7 @@ public class SQLUpdateQuery implements SQLQuery {
|
|||
this.onConflict = onConflict;
|
||||
}
|
||||
|
||||
void setTable(final String table) {
|
||||
void setTable(final Table table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
|
@ -80,14 +81,14 @@ public class SQLUpdateQuery implements SQLQuery {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder update(final OnConflict onConflict, final String table) {
|
||||
public Builder update(final OnConflict onConflict, final Table table) {
|
||||
checkNotBuilt();
|
||||
query.setOnConflict(onConflict);
|
||||
query.setTable(table);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder update(final String table) {
|
||||
public Builder update(final Table table) {
|
||||
return update(null, table);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,10 @@
|
|||
|
||||
<application>
|
||||
<activity
|
||||
tools:replace="android:label"
|
||||
android:name="im.dino.dbinspector.activities.DbInspectorActivity"
|
||||
android:label="Database Inspector">
|
||||
android:exported="false"
|
||||
android:label="Database Inspector"
|
||||
tools:replace="android:label">
|
||||
<intent-filter tools:node="removeAll">
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
|
|
|
@ -33,7 +33,7 @@ import static org.mariotaku.twidere.annotation.Preference.Type.STRING;
|
|||
public interface Constants extends TwidereConstants {
|
||||
|
||||
String DATABASES_NAME = "twidere.sqlite";
|
||||
int DATABASES_VERSION = 90;
|
||||
int DATABASES_VERSION = 92;
|
||||
|
||||
int MENU_GROUP_STATUS_EXTENSION = 10;
|
||||
int MENU_GROUP_COMPOSE_EXTENSION = 11;
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.content.Context;
|
|||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.PorterDuff.Mode;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.widget.SimpleCursorAdapter;
|
||||
import android.view.View;
|
||||
|
@ -118,8 +119,10 @@ public class UserHashtagAutoCompleteAdapter extends SimpleCursorAdapter implemen
|
|||
mProfileImageLoader.cancelDisplayTask(icon);
|
||||
// icon.setImageResource(R.drawable.ic_profile_image_default);
|
||||
}
|
||||
icon.clearColorFilter();
|
||||
} else {
|
||||
icon.setImageResource(R.drawable.ic_action_hashtag);
|
||||
icon.setColorFilter(text1.getCurrentTextColor(), Mode.SRC_ATOP);
|
||||
}
|
||||
super.bindView(view, context, cursor);
|
||||
}
|
||||
|
|
|
@ -201,6 +201,10 @@ public class SearchFragment extends BaseSupportFragment implements RefreshScroll
|
|||
return getArguments().getString(EXTRA_QUERY);
|
||||
}
|
||||
|
||||
public long getAccountId() {
|
||||
return getArguments().getLong(EXTRA_ACCOUNT_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_search, menu);
|
||||
|
@ -223,9 +227,7 @@ public class SearchFragment extends BaseSupportFragment implements RefreshScroll
|
|||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
final Bundle args = getArguments();
|
||||
if (twitter != null && args != null) {
|
||||
final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1);
|
||||
final String query = args.getString(EXTRA_QUERY);
|
||||
twitter.createSavedSearchAsync(accountId, query);
|
||||
twitter.createSavedSearchAsync(getAccountId(), getQuery());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -233,6 +235,7 @@ public class SearchFragment extends BaseSupportFragment implements RefreshScroll
|
|||
final Intent intent = new Intent(getActivity(), ComposeActivity.class);
|
||||
intent.setAction(INTENT_ACTION_COMPOSE);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, String.format("#%s ", getQuery()));
|
||||
intent.putExtra(EXTRA_ACCOUNT_ID, getAccountId());
|
||||
startActivity(intent);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.loader.support;
|
|||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
|
||||
|
@ -50,8 +51,9 @@ public class MediaTimelineLoader extends Twitter4JStatusesLoader {
|
|||
mIsMyTimeline = userId > 0 ? accountId == userId : accountId == getAccountId(context, screenName);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ResponseList<Status> getStatuses(final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
protected ResponseList<Status> getStatuses(@NonNull final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
if (twitter == null) return null;
|
||||
if (mUserId != -1)
|
||||
return twitter.getMediaTimeline(mUserId, paging);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.loader.support;
|
|||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
|
||||
|
@ -49,8 +50,9 @@ public class RetweetsOfMeLoader extends Twitter4JStatusesLoader {
|
|||
return mTotalItemsCount;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ResponseList<Status> getStatuses(final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
protected ResponseList<Status> getStatuses(@NonNull final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
if (twitter == null) return null;
|
||||
final ResponseList<Status> statuses = twitter.getRetweetsOfMe(paging);
|
||||
if (mTotalItemsCount == -1 && !statuses.isEmpty()) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.mariotaku.twidere.loader.support;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
|
||||
|
@ -45,8 +46,9 @@ public class StatusRepliesLoader extends UserMentionsLoader {
|
|||
mInReplyToStatusId = statusId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<Status> getStatuses(final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
public List<Status> getStatuses(@NonNull final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
final Context context = getContext();
|
||||
final List<Status> result = new ArrayList<>();
|
||||
if (shouldForceUsingPrivateAPIs(context) || isOfficialTwitterInstance(context, twitter)) {
|
||||
|
|
|
@ -22,7 +22,6 @@ package org.mariotaku.twidere.loader.support;
|
|||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
@ -30,8 +29,6 @@ import android.util.Log;
|
|||
import org.mariotaku.jsonserializer.JSONFileIO;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.task.CacheUsersStatusesTask;
|
||||
import org.mariotaku.twidere.util.TwitterWrapper.StatusListResponse;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -55,7 +52,6 @@ public abstract class Twitter4JStatusesLoader extends ParcelableStatusesLoader {
|
|||
private final long mAccountId;
|
||||
private final long mMaxId, mSinceId;
|
||||
private final SQLiteDatabase mDatabase;
|
||||
private final Handler mHandler;
|
||||
private final Object[] mSavedStatusesFileArgs;
|
||||
private Comparator<ParcelableStatus> mComparator;
|
||||
|
||||
|
@ -68,7 +64,6 @@ public abstract class Twitter4JStatusesLoader extends ParcelableStatusesLoader {
|
|||
mMaxId = maxId;
|
||||
mSinceId = sinceId;
|
||||
mDatabase = TwidereApplication.getInstance(context).getSQLiteDatabase();
|
||||
mHandler = new Handler();
|
||||
mSavedStatusesFileArgs = savedStatusesArgs;
|
||||
}
|
||||
|
||||
|
@ -117,7 +112,6 @@ public abstract class Twitter4JStatusesLoader extends ParcelableStatusesLoader {
|
|||
}
|
||||
final long minStatusId = statuses.isEmpty() ? -1 : Collections.min(statuses).getId();
|
||||
final boolean insertGap = minStatusId > 0 && statuses.size() > 1 && !data.isEmpty() && !truncated;
|
||||
mHandler.post(CacheUsersStatusesTask.getRunnable(context, new StatusListResponse(mAccountId, statuses)));
|
||||
for (final Status status : statuses) {
|
||||
final long id = status.getId();
|
||||
final boolean deleted = deleteStatus(data, id);
|
||||
|
@ -143,6 +137,7 @@ public abstract class Twitter4JStatusesLoader extends ParcelableStatusesLoader {
|
|||
mComparator = comparator;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
protected abstract List<Status> getStatuses(@NonNull Twitter twitter, Paging paging) throws TwitterException;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.loader.support;
|
|||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
|
||||
|
@ -46,8 +47,9 @@ public class UserFavoritesLoader extends Twitter4JStatusesLoader {
|
|||
mUserScreenName = screen_name;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ResponseList<Status> getStatuses(final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
public ResponseList<Status> getStatuses(@NonNull final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
if (twitter == null) return null;
|
||||
if (mUserId != -1)
|
||||
return twitter.getFavorites(mUserId, paging);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.loader.support;
|
|||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
|
||||
|
@ -54,8 +55,9 @@ public class UserListTimelineLoader extends Twitter4JStatusesLoader {
|
|||
KEY_FILTERS_FOR_RTS, true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ResponseList<Status> getStatuses(final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
protected ResponseList<Status> getStatuses(@NonNull final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
if (twitter == null) return null;
|
||||
if (mListId > 0)
|
||||
return twitter.getUserListStatuses(mListId, paging);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.loader.support;
|
|||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
|
||||
|
@ -51,8 +52,9 @@ public class UserTimelineLoader extends Twitter4JStatusesLoader {
|
|||
mIsMyTimeline = userId > 0 ? accountId == userId : accountId == getAccountId(context, screenName);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ResponseList<Status> getStatuses(final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
protected ResponseList<Status> getStatuses(@NonNull final Twitter twitter, final Paging paging) throws TwitterException {
|
||||
if (twitter == null) return null;
|
||||
if (mUserId != -1)
|
||||
return twitter.getUserTimeline(mUserId, paging);
|
||||
|
|
|
@ -174,7 +174,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
|||
values.getAsLong(CachedUsers.USER_ID));
|
||||
mDatabaseWrapper.update(table, values, where.getSQL(), null);
|
||||
newIds[result++] = mDatabaseWrapper.insertWithOnConflict(table, null,
|
||||
values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
} else if (tableId == TABLE_ID_SEARCH_HISTORY) {
|
||||
for (final ContentValues values : valuesArray) {
|
||||
|
|
|
@ -26,115 +26,71 @@ import android.os.AsyncTask;
|
|||
|
||||
import com.twitter.Extractor;
|
||||
|
||||
import org.mariotaku.querybuilder.Expression;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedStatuses;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
|
||||
import org.mariotaku.twidere.util.AsyncTaskUtils;
|
||||
import org.mariotaku.twidere.util.TwitterWrapper.TwitterListResponse;
|
||||
import org.mariotaku.twidere.util.content.ContentResolverUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import twitter4j.User;
|
||||
|
||||
import static org.mariotaku.twidere.util.ContentValuesCreator.createCachedUser;
|
||||
import static org.mariotaku.twidere.util.ContentValuesCreator.createStatus;
|
||||
import static org.mariotaku.twidere.util.content.ContentResolverUtils.bulkDelete;
|
||||
import static org.mariotaku.twidere.util.content.ContentResolverUtils.bulkInsert;
|
||||
|
||||
public class CacheUsersStatusesTask extends AsyncTask<Void, Void, Void> implements Constants {
|
||||
public class CacheUsersStatusesTask extends AsyncTask<TwitterListResponse<twitter4j.Status>, Void, Void> implements Constants {
|
||||
|
||||
private final TwitterListResponse<twitter4j.Status>[] responses;
|
||||
private final Context context;
|
||||
|
||||
@SafeVarargs
|
||||
public CacheUsersStatusesTask(final Context context, final TwitterListResponse<twitter4j.Status>... responses) {
|
||||
public CacheUsersStatusesTask(final Context context) {
|
||||
this.context = context;
|
||||
this.responses = responses;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@Override
|
||||
protected Void doInBackground(final Void... args) {
|
||||
if (responses == null || responses.length == 0) return null;
|
||||
protected final Void doInBackground(final TwitterListResponse<twitter4j.Status>... args) {
|
||||
if (args == null || args.length == 0) return null;
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
final Extractor extractor = new Extractor();
|
||||
final Set<ContentValues> usersValues = new HashSet<>();
|
||||
final Set<ContentValues> statusesValues = new HashSet<>();
|
||||
final Set<ContentValues> hashTagValues = new HashSet<>();
|
||||
final Set<Long> allStatusIds = new HashSet<>();
|
||||
final Set<String> allHashTags = new HashSet<>();
|
||||
final Set<User> users = new HashSet<>();
|
||||
|
||||
for (final TwitterListResponse<twitter4j.Status> response : responses) {
|
||||
for (final TwitterListResponse<twitter4j.Status> response : args) {
|
||||
if (response == null || response.list == null) {
|
||||
continue;
|
||||
}
|
||||
final List<twitter4j.Status> list = response.list;
|
||||
final Set<Long> userIds = new HashSet<>();
|
||||
for (final twitter4j.Status status : list) {
|
||||
for (int bulkIdx = 0, totalSize = list.size(); bulkIdx < totalSize; bulkIdx += 100) {
|
||||
for (int idx = bulkIdx, end = Math.min(totalSize, bulkIdx + ContentResolverUtils.MAX_BULK_COUNT); idx < end; idx++) {
|
||||
final twitter4j.Status status = list.get(idx);
|
||||
if (status == null || status.getId() <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (status.isRetweet()) {
|
||||
final User retweetUser = status.getRetweetedStatus().getUser();
|
||||
userIds.add(retweetUser.getId());
|
||||
}
|
||||
allStatusIds.add(status.getId());
|
||||
statusesValues.add(createStatus(status, response.account_id));
|
||||
allHashTags.addAll(extractor.extractHashtags(status.getText()));
|
||||
final User user = status.getUser();
|
||||
users.add(user);
|
||||
userIds.add(user.getId());
|
||||
final ContentValues filtered_users_values = new ContentValues();
|
||||
filtered_users_values.put(Filters.Users.NAME, user.getName());
|
||||
filtered_users_values.put(Filters.Users.SCREEN_NAME, user.getScreenName());
|
||||
final String filtered_users_where = Expression.equals(Filters.Users.USER_ID, user.getId()).getSQL();
|
||||
resolver.update(Filters.Users.CONTENT_URI, filtered_users_values, filtered_users_where, null);
|
||||
}
|
||||
}
|
||||
|
||||
bulkDelete(resolver, CachedStatuses.CONTENT_URI, CachedStatuses.STATUS_ID, allStatusIds, null, false);
|
||||
bulkInsert(resolver, CachedStatuses.CONTENT_URI, statusesValues);
|
||||
final Set<ContentValues> usersValues = new HashSet<>();
|
||||
final Set<ContentValues> statusesValues = new HashSet<>();
|
||||
final Set<ContentValues> hashTagValues = new HashSet<>();
|
||||
|
||||
for (final String hashtag : allHashTags) {
|
||||
statusesValues.add(createStatus(status, response.accountId));
|
||||
for (final String hashtag : extractor.extractHashtags(status.getText())) {
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(CachedHashtags.NAME, hashtag);
|
||||
hashTagValues.add(values);
|
||||
}
|
||||
bulkDelete(resolver, CachedHashtags.CONTENT_URI, CachedHashtags.NAME, allHashTags, null, true);
|
||||
bulkInsert(resolver, CachedHashtags.CONTENT_URI, hashTagValues);
|
||||
|
||||
for (final User user : users) {
|
||||
usersValues.add(createCachedUser(user));
|
||||
usersValues.add(createCachedUser(status.getUser()));
|
||||
if (status.isRetweet()) {
|
||||
usersValues.add(createCachedUser(status.getRetweetedStatus().getUser()));
|
||||
}
|
||||
|
||||
bulkInsert(resolver, CachedStatuses.CONTENT_URI, statusesValues);
|
||||
bulkInsert(resolver, CachedHashtags.CONTENT_URI, hashTagValues);
|
||||
bulkInsert(resolver, CachedUsers.CONTENT_URI, usersValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static Runnable getRunnable(final Context context,
|
||||
final TwitterListResponse<twitter4j.Status>... all_statuses) {
|
||||
return new ExecuteCacheUserStatusesTaskRunnable(context, all_statuses);
|
||||
}
|
||||
|
||||
static class ExecuteCacheUserStatusesTaskRunnable implements Runnable {
|
||||
final Context context;
|
||||
final TwitterListResponse<twitter4j.Status>[] all_statuses;
|
||||
|
||||
@SafeVarargs
|
||||
ExecuteCacheUserStatusesTaskRunnable(final Context context,
|
||||
final TwitterListResponse<twitter4j.Status>... all_statuses) {
|
||||
this.context = context;
|
||||
this.all_statuses = all_statuses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
AsyncTaskUtils.executeTask(new CacheUsersStatusesTask(context, all_statuses));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
|
|||
import org.mariotaku.twidere.provider.TwidereDataStore.SavedSearches;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
import org.mariotaku.twidere.service.BackgroundOperationService;
|
||||
import org.mariotaku.twidere.task.CacheUsersStatusesTask;
|
||||
import org.mariotaku.twidere.task.ManagedAsyncTask;
|
||||
import org.mariotaku.twidere.util.collection.LongSparseMap;
|
||||
import org.mariotaku.twidere.util.content.ContentResolverUtils;
|
||||
|
@ -1788,7 +1789,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
final List<DirectMessage> messages = new ArrayList<>();
|
||||
final boolean truncated = truncateMessages(getDirectMessages(twitter, paging), messages,
|
||||
since_id);
|
||||
result.add(new MessageListResponse(accountId, max_id, since_id, load_item_limit, messages,
|
||||
result.add(new MessageListResponse(accountId, max_id, since_id, messages,
|
||||
truncated));
|
||||
storeMessages(accountId, messages, isOutgoing(), true);
|
||||
} catch (final TwitterException e) {
|
||||
|
@ -1809,11 +1810,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
if (messages == null) return true;
|
||||
final Uri uri = getDatabaseUri();
|
||||
final ContentValues[] valuesArray = new ContentValues[messages.size()];
|
||||
final long[] messageIds = new long[messages.size()];
|
||||
|
||||
for (int i = 0, j = messages.size(); i < j; i++) {
|
||||
final DirectMessage message = messages.get(i);
|
||||
messageIds[i] = message.getId();
|
||||
valuesArray[i] = createDirectMessage(message, accountId, isOutgoing);
|
||||
}
|
||||
|
||||
|
@ -2037,7 +2036,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
|
||||
}
|
||||
|
||||
abstract class GetStatusesTask extends ManagedAsyncTask<Void, Void, List<StatusListResponse>> {
|
||||
abstract class GetStatusesTask extends ManagedAsyncTask<Void, TwitterListResponse<twitter4j.Status>, List<StatusListResponse>> {
|
||||
|
||||
private final long[] mAccountIds, mMaxIds, mSinceIds;
|
||||
|
||||
|
@ -2055,10 +2054,10 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
return mMaxIds != null && mMaxIds.length == mAccountIds.length;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@Override
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
super.onProgressUpdate(values);
|
||||
// new CacheUsersStatusesTask(mContext, responses.toArray(array)).executeTask();
|
||||
protected final void onProgressUpdate(TwitterListResponse<twitter4j.Status>... values) {
|
||||
AsyncTaskUtils.executeTask(new CacheUsersStatusesTask(mContext), values);
|
||||
}
|
||||
|
||||
private void storeStatus(long accountId, List<twitter4j.Status> statuses, long maxId, boolean truncated, boolean notify) {
|
||||
|
@ -2159,6 +2158,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
final List<twitter4j.Status> statuses = new ArrayList<>();
|
||||
final boolean truncated = truncateStatuses(getStatuses(twitter, paging), statuses, sinceId);
|
||||
storeStatus(accountId, statuses, maxId, truncated, true);
|
||||
publishProgress(new StatusListResponse(accountId, statuses));
|
||||
} catch (final TwitterException e) {
|
||||
Log.w(LOGTAG, e);
|
||||
result.add(new StatusListResponse(accountId, e));
|
||||
|
|
|
@ -228,22 +228,22 @@ public class TwitterWrapper implements Constants {
|
|||
|
||||
public final boolean truncated;
|
||||
|
||||
public MessageListResponse(final long account_id, final Exception exception) {
|
||||
this(account_id, -1, -1, null, false, exception);
|
||||
public MessageListResponse(final long accountId, final Exception exception) {
|
||||
this(accountId, -1, -1, null, false, exception);
|
||||
}
|
||||
|
||||
public MessageListResponse(final long account_id, final List<DirectMessage> list) {
|
||||
this(account_id, -1, -1, list, false, null);
|
||||
public MessageListResponse(final long accountId, final List<DirectMessage> list) {
|
||||
this(accountId, -1, -1, list, false, null);
|
||||
}
|
||||
|
||||
public MessageListResponse(final long account_id, final long max_id, final long since_id,
|
||||
final int load_item_limit, final List<DirectMessage> list, final boolean truncated) {
|
||||
this(account_id, max_id, since_id, list, truncated, null);
|
||||
public MessageListResponse(final long accountId, final long maxId, final long sinceId,
|
||||
final List<DirectMessage> list, final boolean truncated) {
|
||||
this(accountId, maxId, sinceId, list, truncated, null);
|
||||
}
|
||||
|
||||
MessageListResponse(final long account_id, final long max_id, final long since_id,
|
||||
MessageListResponse(final long accountId, final long maxId, final long sinceId,
|
||||
final List<DirectMessage> list, final boolean truncated, final Exception exception) {
|
||||
super(account_id, max_id, since_id, list, exception);
|
||||
super(accountId, maxId, sinceId, list, exception);
|
||||
this.truncated = truncated;
|
||||
}
|
||||
|
||||
|
@ -253,22 +253,22 @@ public class TwitterWrapper implements Constants {
|
|||
|
||||
public final boolean truncated;
|
||||
|
||||
public StatusListResponse(final long account_id, final Exception exception) {
|
||||
this(account_id, -1, -1, null, false, exception);
|
||||
public StatusListResponse(final long accountId, final Exception exception) {
|
||||
this(accountId, -1, -1, null, false, exception);
|
||||
}
|
||||
|
||||
public StatusListResponse(final long account_id, final List<Status> list) {
|
||||
this(account_id, -1, -1, list, false, null);
|
||||
public StatusListResponse(final long accountId, final List<Status> list) {
|
||||
this(accountId, -1, -1, list, false, null);
|
||||
}
|
||||
|
||||
public StatusListResponse(final long account_id, final long max_id, final long since_id,
|
||||
final int load_item_limit, final List<Status> list, final boolean truncated) {
|
||||
this(account_id, max_id, since_id, list, truncated, null);
|
||||
public StatusListResponse(final long accountId, final long maxId, final long sinceId,
|
||||
final List<Status> list, final boolean truncated) {
|
||||
this(accountId, maxId, sinceId, list, truncated, null);
|
||||
}
|
||||
|
||||
StatusListResponse(final long account_id, final long max_id, final long since_id, final List<Status> list,
|
||||
StatusListResponse(final long accountId, final long maxId, final long sinceId, final List<Status> list,
|
||||
final boolean truncated, final Exception exception) {
|
||||
super(account_id, max_id, since_id, list, exception);
|
||||
super(accountId, maxId, sinceId, list, exception);
|
||||
this.truncated = truncated;
|
||||
}
|
||||
|
||||
|
@ -276,22 +276,22 @@ public class TwitterWrapper implements Constants {
|
|||
|
||||
public static class TwitterListResponse<Data> extends ListResponse<Data> {
|
||||
|
||||
public final long account_id, max_id, since_id;
|
||||
public final long accountId, maxId, sinceId;
|
||||
|
||||
public TwitterListResponse(final long account_id, final Exception exception) {
|
||||
this(account_id, -1, -1, null, exception);
|
||||
public TwitterListResponse(final long accountId, final Exception exception) {
|
||||
this(accountId, -1, -1, null, exception);
|
||||
}
|
||||
|
||||
public TwitterListResponse(final long account_id, final long max_id, final long since_id, final List<Data> list) {
|
||||
this(account_id, max_id, since_id, list, null);
|
||||
public TwitterListResponse(final long accountId, final long maxId, final long sinceId, final List<Data> list) {
|
||||
this(accountId, maxId, sinceId, list, null);
|
||||
}
|
||||
|
||||
TwitterListResponse(final long account_id, final long max_id, final long since_id, final List<Data> list,
|
||||
TwitterListResponse(final long accountId, final long maxId, final long sinceId, final List<Data> list,
|
||||
final Exception exception) {
|
||||
super(list, exception);
|
||||
this.account_id = account_id;
|
||||
this.max_id = max_id;
|
||||
this.since_id = since_id;
|
||||
this.accountId = accountId;
|
||||
this.maxId = maxId;
|
||||
this.sinceId = sinceId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,8 +30,10 @@ import org.mariotaku.querybuilder.Columns;
|
|||
import org.mariotaku.querybuilder.Columns.Column;
|
||||
import org.mariotaku.querybuilder.Expression;
|
||||
import org.mariotaku.querybuilder.NewColumn;
|
||||
import org.mariotaku.querybuilder.OnConflict;
|
||||
import org.mariotaku.querybuilder.SQLQuery;
|
||||
import org.mariotaku.querybuilder.SQLQueryBuilder;
|
||||
import org.mariotaku.querybuilder.SetValue;
|
||||
import org.mariotaku.querybuilder.Table;
|
||||
import org.mariotaku.querybuilder.query.SQLCreateIndexQuery;
|
||||
import org.mariotaku.querybuilder.query.SQLCreateTableQuery;
|
||||
|
@ -121,12 +123,44 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
private void createTriggers(SQLiteDatabase db) {
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_statuses").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_mentions").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_cached_statuses").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_received_messages").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_sent_messages").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "on_user_cache_update_trigger").getSQL());
|
||||
db.execSQL(SQLQueryBuilder.dropTrigger(true, "delete_old_cached_hashtags").getSQL());
|
||||
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_statuses", Statuses.TABLE_NAME).getSQL());
|
||||
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_mentions", Mentions.TABLE_NAME).getSQL());
|
||||
db.execSQL(createDeleteDuplicateStatusTrigger("delete_old_cached_statuses", CachedStatuses.TABLE_NAME).getSQL());
|
||||
db.execSQL(createDeleteDuplicateMessageTrigger("delete_old_received_messages", DirectMessages.Inbox.TABLE_NAME).getSQL());
|
||||
db.execSQL(createDeleteDuplicateMessageTrigger("delete_old_sent_messages", DirectMessages.Outbox.TABLE_NAME).getSQL());
|
||||
|
||||
// Update user info in filtered users
|
||||
final Table cachedUsersTable = new Table(CachedUsers.TABLE_NAME);
|
||||
final Table filteredUsersTable = new Table(Filters.Users.TABLE_NAME);
|
||||
db.execSQL(SQLQueryBuilder.createTrigger(false, true, "on_user_cache_update_trigger")
|
||||
.type(Type.BEFORE)
|
||||
.event(Event.INSERT)
|
||||
.on(cachedUsersTable)
|
||||
.forEachRow(true)
|
||||
.actions(SQLQueryBuilder.update(OnConflict.REPLACE, filteredUsersTable)
|
||||
.set(new SetValue(new Column(Filters.Users.NAME), new Column(Table.NEW, CachedUsers.NAME)),
|
||||
new SetValue(new Column(Filters.Users.SCREEN_NAME), new Column(Table.NEW, CachedUsers.SCREEN_NAME)))
|
||||
.where(Expression.equals(new Column(Filters.Users.USER_ID), new Column(Table.NEW, CachedUsers.USER_ID)))
|
||||
.build())
|
||||
.buildSQL());
|
||||
|
||||
// Delete duplicated hashtags ignoring case
|
||||
final Table cachedHashtagsTable = new Table(CachedHashtags.TABLE_NAME);
|
||||
db.execSQL(SQLQueryBuilder.createTrigger(false, true, "delete_old_cached_hashtags")
|
||||
.type(Type.BEFORE)
|
||||
.event(Event.INSERT)
|
||||
.on(cachedHashtagsTable)
|
||||
.forEachRow(true)
|
||||
.actions(SQLQueryBuilder.deleteFrom(cachedHashtagsTable)
|
||||
.where(Expression.like(new Column(CachedHashtags.NAME), new Column(Table.NEW, CachedHashtags.NAME)))
|
||||
.build())
|
||||
.buildSQL());
|
||||
|
||||
}
|
||||
|
||||
private SQLQuery createDeleteDuplicateStatusTrigger(String triggerName, String tableName) {
|
||||
|
|
Loading…
Reference in New Issue