user list bug fix, database fix, async fix

This commit is contained in:
nuclearfog 2023-03-06 21:42:36 +01:00
parent 3ddd0e92ed
commit ec6afb12e2
No known key found for this signature in database
GPG Key ID: 03488A185C476379
9 changed files with 522 additions and 429 deletions

View File

@ -316,7 +316,8 @@ public class TwitterV1 implements Connection {
public Users getFollowing(long id, long cursor) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("user_id=" + id);
params.add("cursor=" + cursor);
if (cursor != 0L)
params.add("cursor=" + cursor);
return getUsers(USERS_FOLLOWING, params);
}
@ -325,7 +326,8 @@ public class TwitterV1 implements Connection {
public Users getFollower(long id, long cursor) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("user_id=" + id);
params.add("cursor=" + cursor);
if (cursor != 0L)
params.add("cursor=" + cursor);
return getUsers(USERS_FOLLOWER, params);
}
@ -334,7 +336,8 @@ public class TwitterV1 implements Connection {
public Users getListMember(long id, long cursor) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("list_id=" + id);
params.add("cursor=" + cursor);
if (cursor != 0L)
params.add("cursor=" + cursor);
Users result = getUsers(USERS_LIST_MEMBER, params);
// fix API returns zero previous_cursor when the end of the list is reached
// override previous cursor
@ -350,7 +353,8 @@ public class TwitterV1 implements Connection {
public Users getListSubscriber(long id, long cursor) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("list_id=" + id);
params.add("cursor=" + cursor);
if (cursor != 0L)
params.add("cursor=" + cursor);
Users result = getUsers(USERS_LIST_SUBSCRIBER, params);
// fix API returns zero previous_cursor when the end of the list is reached
// override previous cursor
@ -365,7 +369,8 @@ public class TwitterV1 implements Connection {
@Override
public Users getBlockedUsers(long cursor) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("cursor=" + cursor);
if (cursor != 0L)
params.add("cursor=" + cursor);
return getUsers(USERS_BLOCKED_LIST, params);
}
@ -373,7 +378,8 @@ public class TwitterV1 implements Connection {
@Override
public Users getMutedUsers(long cursor) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("cursor=" + cursor);
if (cursor != 0L)
params.add("cursor=" + cursor);
return getUsers(USERS_MUTES, params);
}

View File

@ -23,11 +23,21 @@ public abstract class AsyncExecutor<Parameter, Result> {
/**
* maximum task count to run in the background
*/
private static final int N_THREAD = 2;
private static final int N_THREAD = 4;
private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(N_THREAD);
/**
* thread pool executor
*/
private static final ExecutorService THREAD_POOL = Executors.newFixedThreadPool(N_THREAD);
private Handler uiHandler = new Handler(Looper.getMainLooper());
/**
* handler used to send result back to activity/fragment
*/
private static final Handler UI_HANDLER = new Handler(Looper.getMainLooper());
/**
* callback to activity/fragment
*/
private WeakReference<AsyncCallback<Result>> callback;
/**
@ -43,7 +53,7 @@ public abstract class AsyncExecutor<Parameter, Result> {
*/
public final void execute(final Parameter parameter, @Nullable AsyncCallback<Result> callback) {
this.callback = new WeakReference<>(callback);
Future<?> future = EXECUTOR.submit(new Runnable() {
Future<?> future = THREAD_POOL.submit(new Runnable() {
@Override
public void run() {
Result result = doInBackground(parameter);
@ -78,7 +88,7 @@ public abstract class AsyncExecutor<Parameter, Result> {
* @param result result of the background task
*/
private void onPostExecute(final Result result) {
uiHandler.post(new Runnable() {
UI_HANDLER.post(new Runnable() {
@Override
public void run() {
if (!queue.isEmpty())

View File

@ -80,11 +80,11 @@ public class UsersLoader extends AsyncExecutor<UsersLoader.UserParam, UsersLoade
break;
}
} catch (ConnectionException exception) {
return new UserResult(null, exception);
return new UserResult(null, param.index, exception);
} catch (Exception e) {
e.printStackTrace();
}
return new UserResult(users, null);
return new UserResult(users, param.index, null);
}
/**
@ -104,12 +104,13 @@ public class UsersLoader extends AsyncExecutor<UsersLoader.UserParam, UsersLoade
public static final int REQUEST_OUT = 10;
public static final int REQUEST_IN = 11;
public final int type;
public final int type, index;
public final String search;
public final long id, cursor;
public UserParam(int type, long id, long cursor, String search) {
public UserParam(int type, int index, long id, long cursor, String search) {
this.type = type;
this.index = index;
this.id = id;
this.cursor = cursor;
this.search = search;
@ -125,9 +126,11 @@ public class UsersLoader extends AsyncExecutor<UsersLoader.UserParam, UsersLoade
public final Users users;
@Nullable
public final ConnectionException exception;
public final int index;
UserResult(@Nullable Users users, @Nullable ConnectionException exception) {
UserResult(@Nullable Users users, int index, @Nullable ConnectionException exception) {
this.users = users;
this.index = index;
this.exception = exception;
}
}

View File

@ -37,24 +37,6 @@ public class Users extends LinkedList<User> {
return super.get(index);
}
/**
* check if list is linked to a previous list
*
* @return true if list is linked
*/
public boolean hasPrevious() {
return prevCursor != 0;
}
/**
* check if list has a successor
*
* @return true if list has a successor
*/
public boolean hasNext() {
return nextCursor != 0;
}
/**
* get next link to a list
*
@ -64,18 +46,6 @@ public class Users extends LinkedList<User> {
return nextCursor;
}
/**
* replace whole list including cursors
*
* @param list new list
*/
public void replace(Users list) {
super.clear();
super.addAll(list);
prevCursor = list.prevCursor;
nextCursor = list.nextCursor;
}
/**
* set previous cursor
*
@ -94,17 +64,37 @@ public class Users extends LinkedList<User> {
this.nextCursor = nextCursor;
}
/**
* replace whole list including cursors
*
* @param list new list
*/
public void replaceAll(Users list) {
super.clear();
super.addAll(list);
prevCursor = list.prevCursor;
nextCursor = list.nextCursor;
}
/**
* add a sublist at the bottom of this list including next cursor
*
* @param list new sublist
* @param index index of the sub list
*/
public void addAt(Users list, int index) {
super.addAll(index, list);
nextCursor = list.nextCursor;
public boolean addAll(int index, Users list) {
if (isEmpty()) {
prevCursor = list.prevCursor;
nextCursor = list.nextCursor;
} else if (index == 0) {
prevCursor = list.prevCursor;
} else if (index == size() - 1) {
nextCursor = list.nextCursor;
}
return super.addAll(index, list);
}
@Override
@NonNull
public String toString() {

View File

@ -383,7 +383,7 @@ public class DatabaseAdapter {
* @param context application context
* @return database instance
*/
public static DatabaseAdapter getInstance(@NonNull Context context) {
static DatabaseAdapter getInstance(@NonNull Context context) {
if (instance == null) {
try {
instance = new DatabaseAdapter(context.getApplicationContext());
@ -402,7 +402,7 @@ public class DatabaseAdapter {
*
* @return SQLite instance
*/
synchronized SQLiteDatabase getDbRead() {
SQLiteDatabase getDbRead() {
if (!db.isOpen())
db = SQLiteDatabase.openOrCreateDatabase(databasePath, null);
return db;
@ -413,7 +413,7 @@ public class DatabaseAdapter {
*
* @return SQLite instance
*/
synchronized SQLiteDatabase getDbWrite() {
SQLiteDatabase getDbWrite() {
SQLiteDatabase db = getDbRead();
db.beginTransaction();
return db;
@ -422,7 +422,7 @@ public class DatabaseAdapter {
/**
* Commit changes and close Database
*/
synchronized void commit() {
void commit() {
db.setTransactionSuccessful();
db.endTransaction();
}

View File

@ -224,11 +224,10 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
if (o instanceof User) {
user = (User) o;
userId = user.getId();
adapter.setupProfilePage(user.getId());
} else {
userId = i.getLongExtra(KEY_PROFILE_ID, 0);
adapter.setupProfilePage(userId);
}
adapter.setupProfilePage(userId);
if (settings.likeEnabled()) {
tabIndicator = AppStyles.setTabIconsWithText(tabLayout, settings, R.array.profile_tab_icons_like);
} else {
@ -735,6 +734,8 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
Spanned bio = Tagger.makeTextWithLinks(user.getDescription(), settings.getHighlightColor(), this);
following.setText(StringTools.NUMBER_FORMAT.format(user.getFollowing()));
follower.setText(StringTools.NUMBER_FORMAT.format(user.getFollower()));
following.setVisibility(VISIBLE);
follower.setVisibility(VISIBLE);
username.setText(user.getUsername());
screenName.setText(user.getScreenname());
if (user.getStatusCount() >= 0) {
@ -806,9 +807,5 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
profileImage.setImageResource(0);
}
}
if (following.getVisibility() != VISIBLE) {
following.setVisibility(VISIBLE);
follower.setVisibility(VISIBLE);
}
}
}

View File

@ -114,10 +114,10 @@ public class UserAdapter extends Adapter<ViewHolder> implements OnHolderClickLis
@Override
public boolean onPlaceholderClick(int position) {
boolean actionPerformed = listener.onPlaceholderClick(users.getNext());
public boolean onPlaceholderClick(int index) {
boolean actionPerformed = listener.onPlaceholderClick(users.getNext(), index);
if (actionPerformed) {
loadingIndex = position;
loadingIndex = index;
return true;
}
return false;
@ -148,36 +148,24 @@ public class UserAdapter extends Adapter<ViewHolder> implements OnHolderClickLis
*
* @param newUsers new userlist
*/
public void addItems(@NonNull Users newUsers) {
disableLoading();
// add empty list
if (newUsers.isEmpty()) {
// remove placeholder if there isn't a next page
if (!users.isEmpty() && users.peekLast() == null) {
int end = users.size() - 1;
users.remove(end);
notifyItemRemoved(end);
}
}
// add items to the top of the list
else if (users.isEmpty() || !newUsers.hasPrevious()) {
users.replace(newUsers);
// add placeholder if there is a next page
if (newUsers.hasNext()) {
public void addItems(@NonNull Users newUsers, int index) {
if (index < 0) {
users.replaceAll(newUsers);
if (users.getNext() != 0L) {
users.add(null);
}
notifyDataSetChanged();
}
// add items to the end of the list
else {
int end = users.size() - 1;
// remove placeholder if there isn't a next page
if (!newUsers.hasNext()) {
users.remove(end);
notifyItemRemoved(end);
} else {
users.addAll(index, newUsers);
if (users.getNext() != 0L && users.peekLast() != null) {
users.add(null);
notifyItemRangeInserted(index, newUsers.size() + 1);
} else if (users.getNext() == 0L && users.peekLast() == null) {
users.remove(users.size() - 1);
notifyItemRangeInserted(index, newUsers.size() - 1);
} else if (!newUsers.isEmpty()) {
notifyItemRangeInserted(index, newUsers.size());
}
users.addAt(newUsers, end);
notifyItemRangeInserted(end, newUsers.size());
}
}
@ -234,9 +222,10 @@ public class UserAdapter extends Adapter<ViewHolder> implements OnHolderClickLis
* handle placeholder click
*
* @param cursor next cursor of the list
* @param index index of the placeholder
* @return true if click was handled
*/
boolean onPlaceholderClick(long cursor);
boolean onPlaceholderClick(long cursor, int index);
/**
* remove user from a list

View File

@ -136,6 +136,11 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
*/
public static final int USER_FRAG_FOLLOW_OUTGOING = 0x72544f17;
/**
* "index" used to replace the whole list with new items
*/
public static final int CLEAR_LIST = -1;
private ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), this);
@ -163,14 +168,14 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
setAdapter(adapter);
setRefresh(true);
load(-1L);
load(-1L, CLEAR_LIST);
}
@Override
protected void onReset() {
setRefresh(true);
load(-1L);
load(-1L, CLEAR_LIST);
}
@ -196,7 +201,7 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
@Override
protected void onReload() {
load(-1L);
load(-1L, CLEAR_LIST);
}
@ -211,9 +216,9 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
@Override
public boolean onPlaceholderClick(long cursor) {
public boolean onPlaceholderClick(long cursor, int index) {
if (userLoader.isIdle()) {
load(cursor);
load(cursor, index);
return true;
}
return false;
@ -233,7 +238,7 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
@Override
public void onResult(UserResult result) {
if (result.users != null) {
adapter.addItems(result.users);
adapter.addItems(result.users, result.index);
} else if (getContext() != null) {
String message = ErrorHandler.getErrorMessage(getContext(), result.exception);
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
@ -257,51 +262,51 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
*
* @param cursor cursor of the list
*/
private void load(long cursor) {
private void load(long cursor, int index) {
UserParam param;
switch (mode) {
case USER_FRAG_FOLLOWER:
param = new UserParam(UserParam.FOLLOWS, id, cursor, search);
param = new UserParam(UserParam.FOLLOWS, index, id, cursor, search);
break;
case USER_FRAG_FOLLOWING:
param = new UserParam(UserParam.FRIENDS, id, cursor, search);
param = new UserParam(UserParam.FRIENDS, index, id, cursor, search);
break;
case USER_FRAG_REPOST:
param = new UserParam(UserParam.REPOST, id, cursor, search);
param = new UserParam(UserParam.REPOST, index, id, cursor, search);
break;
case USER_FRAG_FAVORIT:
param = new UserParam(UserParam.FAVORIT, id, cursor, search);
param = new UserParam(UserParam.FAVORIT, index, id, cursor, search);
break;
case USER_FRAG_SEARCH:
param = new UserParam(UserParam.SEARCH, id, cursor, search);
param = new UserParam(UserParam.SEARCH, index, id, cursor, search);
break;
case USER_FRAG_LIST_SUBSCRIBER:
param = new UserParam(UserParam.SUBSCRIBER, id, cursor, search);
param = new UserParam(UserParam.SUBSCRIBER, index, id, cursor, search);
break;
case USER_FRAG_LIST_MEMBERS:
param = new UserParam(UserParam.LISTMEMBER, id, cursor, search);
param = new UserParam(UserParam.LISTMEMBER, index, id, cursor, search);
break;
case USER_FRAG_BLOCKED_USERS:
param = new UserParam(UserParam.BLOCK, id, cursor, search);
param = new UserParam(UserParam.BLOCK, index, id, cursor, search);
break;
case USER_FRAG_MUTED_USERS:
param = new UserParam(UserParam.MUTE, id, cursor, search);
param = new UserParam(UserParam.MUTE, index, id, cursor, search);
break;
case USER_FRAG_FOLLOW_OUTGOING:
param = new UserParam(UserParam.REQUEST_OUT, id, cursor, search);
param = new UserParam(UserParam.REQUEST_OUT, index, id, cursor, search);
break;
case USER_FRAG_FOLLOW_INCOMING:
param = new UserParam(UserParam.REQUEST_IN, id, cursor, search);
param = new UserParam(UserParam.REQUEST_IN, index, id, cursor, search);
break;
default: