Optimize UserProfileImagesBatchLoader.

This commit is contained in:
Docile-Alligator
2026-06-03 12:41:16 -04:00
parent 25362b64b2
commit 741af41234

View File

@ -19,6 +19,7 @@ import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
import ml.docilealligator.infinityforreddit.apis.RedditAPI;
@ -37,15 +38,15 @@ public class UserProfileImagesBatchLoader {
private final RedditDataRoomDatabase mRedditDataRoomDatabase;
private final Retrofit mRetrofit;
private final Retrofit mOauthRetrofit;
private final Map<String, String> mAuthorFullNameToImageMap;
private final Queue<Comment> mCommentQueue;
private final Map<String, ViewPostDetailActivityViewModel.LoadIconListener> mAuthorFullNameToListenerMap;
private final List<Comment> mCallingComments;
private final Set<String> mLoadingAuthorFullNames;
private final Map<String, String> mUserFullNameToImageMap;
private final Queue<String> mUserFullnameQueue;
private final Map<String, ViewPostDetailActivityViewModel.LoadIconListener> mUserFullNameToListenerMap;
private final List<String> mCallingUserFullnames;
private final Set<String> mLoadingUserFullNames;
private final Object mImageMapLock = new Object();
private final Object mCommentQueueLock = new Object();
private final Object mUserFullnameQueueLock = new Object();
private final Object mListenerMapLock = new Object();
private final Object mCallingCommentsLock = new Object();
private final Object mCallingUserFullnamesLock = new Object();
private final Object mLoadingSetLock = new Object();
private boolean mIsLoadingBatch = false;
@ -56,33 +57,33 @@ public class UserProfileImagesBatchLoader {
mRedditDataRoomDatabase = redditDataRoomDatabase;
mRetrofit = retrofit;
mOauthRetrofit = oauthRetrofit;
mAuthorFullNameToImageMap = new HashMap<>();
mCommentQueue = new LinkedList<>();
mAuthorFullNameToListenerMap = new HashMap<>();
mCallingComments = new LinkedList<>();
mLoadingAuthorFullNames = new HashSet<>();
mUserFullNameToImageMap = new HashMap<>();
mUserFullnameQueue = new LinkedList<>();
mUserFullNameToListenerMap = new HashMap<>();
mCallingUserFullnames = new LinkedList<>();
mLoadingUserFullNames = new HashSet<>();
}
public void loadAuthorImages(@Nullable String accessToken, List<Comment> comments,
@NonNull ViewPostDetailActivityViewModel.LoadIconListener loadIconListener) {
String authorFullName = comments.get(0).getAuthorFullName();
synchronized (mImageMapLock) {
if (mAuthorFullNameToImageMap.containsKey(authorFullName)) {
loadIconListener.loadIconSuccess(authorFullName, mAuthorFullNameToImageMap.get(authorFullName));
if (mUserFullNameToImageMap.containsKey(authorFullName)) {
loadIconListener.loadIconSuccess(authorFullName, mUserFullNameToImageMap.get(authorFullName));
return;
}
}
synchronized (mListenerMapLock) {
mAuthorFullNameToListenerMap.put(authorFullName, loadIconListener);
mUserFullNameToListenerMap.put(authorFullName, loadIconListener);
}
synchronized (mCommentQueueLock) {
mCommentQueue.addAll(comments);
synchronized (mUserFullnameQueueLock) {
mUserFullnameQueue.addAll(comments.stream().map(Comment::getAuthorFullName).collect(Collectors.toList()));
}
synchronized (mCallingCommentsLock) {
mCallingComments.add(comments.get(0));
synchronized (mCallingUserFullnamesLock) {
mCallingUserFullnames.add(comments.get(0).getAuthorFullName());
}
if (!mIsLoadingBatch) {
@ -91,8 +92,8 @@ public class UserProfileImagesBatchLoader {
}
private void loadNextBatch(String accessToken) {
synchronized (mCommentQueueLock) {
if (mCommentQueue.isEmpty()) {
synchronized (mUserFullnameQueueLock) {
if (mUserFullnameQueue.isEmpty()) {
return;
}
}
@ -100,35 +101,34 @@ public class UserProfileImagesBatchLoader {
mIsLoadingBatch = true;
mExecutor.execute(() -> {
synchronized (mCallingCommentsLock) {
Iterator<Comment> iterator = mCallingComments.iterator();
synchronized (mCallingUserFullnamesLock) {
Iterator<String> iterator = mCallingUserFullnames.iterator();
while (iterator.hasNext()) {
Comment c = iterator.next();
String authorFullName = c.getAuthorFullName();
String userFullname = iterator.next();
ViewPostDetailActivityViewModel.LoadIconListener loadIconListener;
synchronized (mListenerMapLock) {
loadIconListener = mAuthorFullNameToListenerMap.get(authorFullName);
loadIconListener = mUserFullNameToListenerMap.get(userFullname);
}
if (loadIconListener != null) {
synchronized (mImageMapLock) {
if (mAuthorFullNameToImageMap.containsKey(authorFullName)) {
String url = mAuthorFullNameToImageMap.get(authorFullName);
mHandler.post(() -> loadIconListener.loadIconSuccess(authorFullName, url));
if (mUserFullNameToImageMap.containsKey(userFullname)) {
String url = mUserFullNameToImageMap.get(userFullname);
mHandler.post(() -> loadIconListener.loadIconSuccess(userFullname, url));
iterator.remove();
continue;
}
}
UserData userData = mRedditDataRoomDatabase.userDao().getUserData(c.getAuthor());
UserData userData = mRedditDataRoomDatabase.userDao().getUserData(userFullname.substring(3));
if (userData != null) {
String iconImageUrl = userData.getIconUrl();
synchronized (mImageMapLock) {
mAuthorFullNameToImageMap.put(authorFullName, iconImageUrl == null ? "" : iconImageUrl);
mUserFullNameToImageMap.put(userFullname, iconImageUrl == null ? "" : iconImageUrl);
}
mHandler.post(() -> loadIconListener.loadIconSuccess(authorFullName, iconImageUrl));
mHandler.post(() -> loadIconListener.loadIconSuccess(userFullname, iconImageUrl));
synchronized (mListenerMapLock) {
mAuthorFullNameToListenerMap.remove(authorFullName);
mUserFullNameToListenerMap.remove(userFullname);
}
iterator.remove();
}
@ -140,43 +140,42 @@ public class UserProfileImagesBatchLoader {
StringBuilder stringBuilder = new StringBuilder();
synchronized (mCommentQueueLock) {
for (int i = 0; i < BATCH_SIZE && !mCommentQueue.isEmpty(); i++) {
Comment comment = mCommentQueue.poll();
if (comment == null || comment.getAuthorFullName() == null || comment.getAuthorFullName().isEmpty()) {
synchronized (mUserFullnameQueueLock) {
for (int i = 0; i < BATCH_SIZE && !mUserFullnameQueue.isEmpty(); i++) {
String userFullname = mUserFullnameQueue.poll();
if (userFullname == null || userFullname.isEmpty()) {
i--;
continue;
}
String authorFullName = comment.getAuthorFullName();
boolean alreadyCached;
synchronized (mImageMapLock) {
alreadyCached = mAuthorFullNameToImageMap.containsKey(authorFullName);
alreadyCached = mUserFullNameToImageMap.containsKey(userFullname);
}
if (!alreadyCached) {
stringBuilder.append(authorFullName).append(",");
stringBuilder.append(userFullname).append(",");
synchronized (mLoadingSetLock) {
mLoadingAuthorFullNames.add(authorFullName);
mLoadingUserFullNames.add(userFullname);
}
} else if (i == 0) {
ViewPostDetailActivityViewModel.LoadIconListener loadIconListener;
synchronized (mListenerMapLock) {
loadIconListener = mAuthorFullNameToListenerMap.get(authorFullName);
loadIconListener = mUserFullNameToListenerMap.get(userFullname);
}
if (loadIconListener != null) {
String url;
synchronized (mImageMapLock) {
url = mAuthorFullNameToImageMap.get(authorFullName);
url = mUserFullNameToImageMap.get(userFullname);
}
mHandler.post(() -> {
loadIconListener.loadIconSuccess(authorFullName, url);
loadIconListener.loadIconSuccess(userFullname, url);
});
synchronized (mListenerMapLock) {
mAuthorFullNameToListenerMap.remove(authorFullName);
mUserFullNameToListenerMap.remove(userFullname);
}
}
for (int j = 0; j < BATCH_SIZE - 1 && !mCommentQueue.isEmpty(); j++) {
mCommentQueue.poll();
for (int j = 0; j < BATCH_SIZE - 1 && !mUserFullnameQueue.isEmpty(); j++) {
mUserFullnameQueue.poll();
}
break;
}
@ -215,11 +214,11 @@ public class UserProfileImagesBatchLoader {
try {
JSONObject jsonResponse = new JSONObject(response);
synchronized (mLoadingSetLock) {
for (String s : mLoadingAuthorFullNames) {
for (String s : mLoadingUserFullNames) {
try {
String imageUrl = jsonResponse.getJSONObject(s).getString(JSONUtils.PROFILE_IMG_KEY).replaceAll("&amp;","&");
synchronized (mImageMapLock) {
mAuthorFullNameToImageMap.put(s, imageUrl);
mUserFullNameToImageMap.put(s, imageUrl);
}
} catch (JSONException e) {
e.printStackTrace();
@ -233,33 +232,33 @@ public class UserProfileImagesBatchLoader {
private void callListenerAndLoadNextBatch(String accessToken, boolean loadSuccessful) {
synchronized (mLoadingSetLock) {
for (String s : mLoadingAuthorFullNames) {
for (String s : mLoadingUserFullNames) {
ViewPostDetailActivityViewModel.LoadIconListener loadIconListener;
synchronized (mListenerMapLock) {
loadIconListener = mAuthorFullNameToListenerMap.get(s);
loadIconListener = mUserFullNameToListenerMap.get(s);
}
if (loadIconListener != null) {
String imageUrl;
synchronized (mImageMapLock) {
imageUrl = mAuthorFullNameToImageMap.get(s);
imageUrl = mUserFullNameToImageMap.get(s);
}
mHandler.post(() -> {
loadIconListener.loadIconSuccess(s, imageUrl);
});
synchronized (mListenerMapLock) {
mAuthorFullNameToListenerMap.remove(s);
mUserFullNameToListenerMap.remove(s);
}
}
if (!loadSuccessful) {
synchronized (mImageMapLock) {
if (!mAuthorFullNameToImageMap.containsKey(s)) {
mAuthorFullNameToImageMap.put(s, "");
if (!mUserFullNameToImageMap.containsKey(s)) {
mUserFullNameToImageMap.put(s, "");
}
}
}
}
mLoadingAuthorFullNames.clear();
mLoadingUserFullNames.clear();
}
mIsLoadingBatch = false;