204 lines
8.6 KiB
Java
204 lines
8.6 KiB
Java
package org.mariotaku.twidere.task.twitter;
|
|
|
|
import android.content.ContentResolver;
|
|
import android.content.ContentValues;
|
|
import android.content.Context;
|
|
import android.database.Cursor;
|
|
import android.net.Uri;
|
|
import android.support.annotation.NonNull;
|
|
import android.util.Log;
|
|
|
|
import org.apache.commons.lang3.ArrayUtils;
|
|
import org.mariotaku.sqliteqb.library.Columns;
|
|
import org.mariotaku.sqliteqb.library.Expression;
|
|
import org.mariotaku.sqliteqb.library.RawItemArray;
|
|
import org.mariotaku.sqliteqb.library.SQLFunctions;
|
|
import org.mariotaku.twidere.api.twitter.Twitter;
|
|
import org.mariotaku.twidere.api.twitter.TwitterException;
|
|
import org.mariotaku.twidere.api.twitter.model.Paging;
|
|
import org.mariotaku.twidere.api.twitter.model.ResponseList;
|
|
import org.mariotaku.twidere.api.twitter.model.Status;
|
|
import org.mariotaku.twidere.provider.TwidereDataStore;
|
|
import org.mariotaku.twidere.task.CacheUsersStatusesTask;
|
|
import org.mariotaku.twidere.task.ManagedAsyncTask;
|
|
import org.mariotaku.twidere.util.AsyncTaskUtils;
|
|
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
|
import org.mariotaku.twidere.util.ContentValuesCreator;
|
|
import org.mariotaku.twidere.util.DataStoreUtils;
|
|
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
|
|
import org.mariotaku.twidere.util.TwitterAPIFactory;
|
|
import org.mariotaku.twidere.util.TwitterContentUtils;
|
|
import org.mariotaku.twidere.util.TwitterWrapper;
|
|
import org.mariotaku.twidere.util.UriUtils;
|
|
import org.mariotaku.twidere.util.Utils;
|
|
import org.mariotaku.twidere.util.content.ContentResolverUtils;
|
|
import org.mariotaku.twidere.util.message.GetStatusesTaskEvent;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import edu.tsinghua.hotmobi.HotMobiLogger;
|
|
import edu.tsinghua.hotmobi.model.RefreshEvent;
|
|
import edu.tsinghua.hotmobi.model.TimelineType;
|
|
|
|
/**
|
|
* Created by mariotaku on 16/1/2.
|
|
*/
|
|
public abstract class GetStatusesTask extends ManagedAsyncTask<Object, TwitterWrapper.TwitterListResponse<Status>, List<TwitterWrapper.StatusListResponse>> {
|
|
|
|
private final long[] accountIds, maxIds, sinceIds;
|
|
private AsyncTwitterWrapper twitterWrapper;
|
|
|
|
public GetStatusesTask(AsyncTwitterWrapper twitterWrapper, final long[] accountIds,
|
|
final long[] maxIds, final long[] sinceIds, final String tag) {
|
|
super(twitterWrapper.getContext(), tag);
|
|
this.accountIds = accountIds;
|
|
this.maxIds = maxIds;
|
|
this.sinceIds = sinceIds;
|
|
this.twitterWrapper = twitterWrapper;
|
|
}
|
|
|
|
public abstract ResponseList<org.mariotaku.twidere.api.twitter.model.Status> getStatuses(Twitter twitter, Paging paging)
|
|
throws TwitterException;
|
|
|
|
@NonNull
|
|
protected abstract Uri getDatabaseUri();
|
|
|
|
final boolean isMaxIdsValid() {
|
|
return maxIds != null && maxIds.length == accountIds.length;
|
|
}
|
|
|
|
final boolean isSinceIdsValid() {
|
|
return sinceIds != null && sinceIds.length == accountIds.length;
|
|
}
|
|
|
|
private void storeStatus(long accountId, List<org.mariotaku.twidere.api.twitter.model.Status> statuses,
|
|
long sinceId, long maxId, boolean notify, int loadItemLimit) {
|
|
if (statuses == null || statuses.isEmpty() || accountId <= 0) {
|
|
return;
|
|
}
|
|
final Uri uri = getDatabaseUri();
|
|
final Context context = twitterWrapper.getContext();
|
|
final ContentResolver resolver = context.getContentResolver();
|
|
final boolean noItemsBefore = DataStoreUtils.getStatusCountInDatabase(context, uri, accountId) <= 0;
|
|
final ContentValues[] values = new ContentValues[statuses.size()];
|
|
final long[] statusIds = new long[statuses.size()];
|
|
long minId = -1;
|
|
int minIdx = -1;
|
|
boolean hasIntersection = false;
|
|
for (int i = 0, j = statuses.size(); i < j; i++) {
|
|
final org.mariotaku.twidere.api.twitter.model.Status status = statuses.get(i);
|
|
values[i] = ContentValuesCreator.createStatus(status, accountId);
|
|
final long id = status.getId();
|
|
if (sinceId > 0 && id <= sinceId) {
|
|
hasIntersection = true;
|
|
}
|
|
if (minId == -1 || id < minId) {
|
|
minId = id;
|
|
minIdx = i;
|
|
}
|
|
statusIds[i] = id;
|
|
}
|
|
// Delete all rows conflicting before new data inserted.
|
|
final Expression accountWhere = Expression.equals(TwidereDataStore.Statuses.ACCOUNT_ID, accountId);
|
|
final Expression statusWhere = Expression.in(new Columns.Column(TwidereDataStore.Statuses.STATUS_ID),
|
|
new RawItemArray(statusIds));
|
|
final String countWhere = Expression.and(accountWhere, statusWhere).getSQL();
|
|
final String[] projection = {SQLFunctions.COUNT()};
|
|
final int rowsDeleted;
|
|
final Cursor countCur = resolver.query(uri, projection, countWhere, null, null);
|
|
try {
|
|
if (countCur != null && countCur.moveToFirst()) {
|
|
rowsDeleted = countCur.getInt(0);
|
|
} else {
|
|
rowsDeleted = 0;
|
|
}
|
|
} finally {
|
|
Utils.closeSilently(countCur);
|
|
}
|
|
|
|
// BEGIN HotMobi
|
|
final RefreshEvent event = RefreshEvent.create(context, statusIds, getTimelineType());
|
|
HotMobiLogger.getInstance(context).log(accountId, event);
|
|
// END HotMobi
|
|
|
|
// Insert a gap.
|
|
final boolean deletedOldGap = rowsDeleted > 0 && ArrayUtils.contains(statusIds, maxId);
|
|
final boolean noRowsDeleted = rowsDeleted == 0;
|
|
final boolean insertGap = minId > 0 && (noRowsDeleted || deletedOldGap) && !noItemsBefore
|
|
&& !hasIntersection;
|
|
if (insertGap && minIdx != -1) {
|
|
values[minIdx].put(TwidereDataStore.Statuses.IS_GAP, true);
|
|
}
|
|
// Insert previously fetched items.
|
|
final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
|
|
ContentResolverUtils.bulkInsert(resolver, insertUri, values);
|
|
|
|
}
|
|
|
|
protected abstract TimelineType getTimelineType();
|
|
|
|
@SafeVarargs
|
|
@Override
|
|
protected final void onProgressUpdate(TwitterWrapper.TwitterListResponse<org.mariotaku.twidere.api.twitter.model.Status>... values) {
|
|
AsyncTaskUtils.executeTask(new CacheUsersStatusesTask(twitterWrapper.getContext()), values);
|
|
}
|
|
|
|
|
|
@Override
|
|
protected void onPostExecute(List<TwitterWrapper.StatusListResponse> result) {
|
|
super.onPostExecute(result);
|
|
bus.post(new GetStatusesTaskEvent(getDatabaseUri(), false, AsyncTwitterWrapper.getException(result)));
|
|
}
|
|
|
|
@Override
|
|
protected void onPreExecute() {
|
|
super.onPreExecute();
|
|
bus.post(new GetStatusesTaskEvent(getDatabaseUri(), true, null));
|
|
}
|
|
|
|
@Override
|
|
protected List<TwitterWrapper.StatusListResponse> doInBackground(final Object... params) {
|
|
final List<TwitterWrapper.StatusListResponse> result = new ArrayList<>();
|
|
if (accountIds == null) return result;
|
|
int idx = 0;
|
|
final SharedPreferencesWrapper preferences = twitterWrapper.getPreferences();
|
|
final Context context = twitterWrapper.getContext();
|
|
final int loadItemLimit = preferences.getInt(KEY_LOAD_ITEM_LIMIT, DEFAULT_LOAD_ITEM_LIMIT);
|
|
for (final long accountId : accountIds) {
|
|
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(context, accountId, true);
|
|
if (twitter == null) continue;
|
|
try {
|
|
final Paging paging = new Paging();
|
|
paging.count(loadItemLimit);
|
|
final long maxId, sinceId;
|
|
if (maxIds != null && maxIds[idx] > 0) {
|
|
maxId = maxIds[idx];
|
|
paging.maxId(maxId);
|
|
} else {
|
|
maxId = -1;
|
|
}
|
|
if (sinceIds != null && sinceIds[idx] > 0) {
|
|
sinceId = sinceIds[idx];
|
|
paging.sinceId(sinceId - 1);
|
|
if (maxIds == null || sinceIds[idx] <= 0) {
|
|
paging.setLatestResults(true);
|
|
}
|
|
} else {
|
|
sinceId = -1;
|
|
}
|
|
final List<org.mariotaku.twidere.api.twitter.model.Status> statuses = getStatuses(twitter, paging);
|
|
TwitterContentUtils.getStatusesWithQuoteData(twitter, statuses);
|
|
storeStatus(accountId, statuses, sinceId, maxId, true, loadItemLimit);
|
|
publishProgress(new TwitterWrapper.StatusListResponse(accountId, statuses));
|
|
} catch (final TwitterException e) {
|
|
Log.w(LOGTAG, e);
|
|
result.add(new TwitterWrapper.StatusListResponse(accountId, e));
|
|
}
|
|
idx++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
}
|