From 30600b3ff9d18badc9f34d109433fbd260750996 Mon Sep 17 00:00:00 2001 From: Janne Koschinski <janne@kuschku.de> Date: Wed, 21 Sep 2016 23:37:21 +0200 Subject: [PATCH] Improved performance a lot, changed settings UI a bit --- .../de/kuschku/libquassel/QuasselClient.java | 10 +-- .../libquassel/localtypes/BacklogFilter.java | 64 +++++++++++++++---- .../backlogstorage/HybridBacklogStorage.java | 10 ++- .../syncables/types/impl/IrcChannel.java | 12 +++- .../types/interfaces/QIrcChannel.java | 4 +- .../ui/chat/fragment/ChatFragment.java | 2 +- .../ui/chat/nicklist/NickListAdapter.java | 63 +++--------------- app/src/main/res/layout/activity_settings.xml | 2 +- 8 files changed, 87 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/de/kuschku/libquassel/QuasselClient.java b/app/src/main/java/de/kuschku/libquassel/QuasselClient.java index 7a40061d6..bcfc9b11f 100644 --- a/app/src/main/java/de/kuschku/libquassel/QuasselClient.java +++ b/app/src/main/java/de/kuschku/libquassel/QuasselClient.java @@ -72,10 +72,12 @@ public class QuasselClient { } this.client.bufferManager().bufferIds().clear(); this.client.bufferManager().buffers().clear(); - for (QBufferViewConfig config : client.bufferViewManager().bufferViewConfigs()) { - config.networkList().clear(); + if (client.bufferViewManager() != null) { + for (QBufferViewConfig config : client.bufferViewManager().bufferViewConfigs()) { + config.networkList().clear(); + } + client.bufferViewManager().bufferViewConfigs().clear(); + client.bufferViewManager().bufferViewConfigMap().clear(); } - client.bufferViewManager().bufferViewConfigs().clear(); - client.bufferViewManager().bufferViewConfigMap().clear(); } } diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java b/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java index af6edeae3..441cdabdf 100644 --- a/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java +++ b/app/src/main/java/de/kuschku/libquassel/localtypes/BacklogFilter.java @@ -24,6 +24,8 @@ package de.kuschku.libquassel.localtypes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.raizlabs.android.dbflow.sql.language.SQLite; + import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -34,6 +36,7 @@ import java.util.List; import de.kuschku.libquassel.client.Client; import de.kuschku.libquassel.message.Message; +import de.kuschku.libquassel.message.Message_Table; import de.kuschku.libquassel.primitives.types.BufferInfo; import de.kuschku.libquassel.syncables.types.interfaces.QNetwork; import de.kuschku.util.observables.callbacks.ElementCallback; @@ -82,6 +85,10 @@ public class BacklogFilter implements UICallback { updateDayChangeMessages(); } + public void loadBackload() { + bus.post(new LoadBacklogEvent()); + } + private Message createMarkerlineMessage(int id) { return Message.create( id, @@ -193,20 +200,24 @@ public class BacklogFilter implements UICallback { @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(UpdateAddEvent event) { + List<Message> filteredMessages = new ArrayList<>(); for (Message message : unfiltered) { - if (!filterItem(message)) { - bus.post(new MessageInsertEvent(message)); - } + if (!filterItem(message)) + filteredMessages.add(message); } + + bus.post(new MessageInsertEvent(filteredMessages)); } @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(UpdateRemoveEvent event) { + List<Message> removedMessages = new ArrayList<>(); for (Message message : unfiltered) { - if (filterItem(message)) { - bus.post(new MessageRemoveEvent(message)); - } + if (filterItem(message)) + removedMessages.add(message); } + + bus.post(new MessageRemoveEvent(removedMessages)); } @Subscribe(threadMode = ThreadMode.ASYNC) @@ -227,7 +238,18 @@ public class BacklogFilter implements UICallback { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(@NonNull MessageRemoveEvent event) { - filtered.remove(event.msg); + filtered.removeAll(event.msgs); + } + + @Subscribe(threadMode = ThreadMode.ASYNC) + public void onEventAsync(@NonNull LoadBacklogEvent event) { + List<Message> messageList = SQLite.select().from(Message.class).where(Message_Table.bufferInfo_id.eq(bufferId)).queryList(); + bus.post(new BacklogLoadedEvent(messageList)); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(@NonNull BacklogLoadedEvent event) { + unfiltered.addAll(event.messageList); } @Override @@ -249,8 +271,8 @@ public class BacklogFilter implements UICallback { @Override public void notifyItemRangeInserted(int position, int count) { - List<Message> message = unfiltered.subList(position, position + count); - bus.post(new MessageFilterEvent(message)); + List<Message> messages = unfiltered.subList(position, position + count); + bus.post(new MessageFilterEvent(messages)); } @Override @@ -262,9 +284,8 @@ public class BacklogFilter implements UICallback { @Override public void notifyItemRangeRemoved(int position, int count) { - for (int i = position; i < position + count; i++) { - notifyItemRemoved(i); - } + List<Message> messages = unfiltered.subList(position, position + count); + bus.post(new MessageRemoveEvent(messages)); } public void onDestroy() { @@ -286,10 +307,14 @@ public class BacklogFilter implements UICallback { } private class MessageRemoveEvent { - public final Message msg; + public final List<Message> msgs; public MessageRemoveEvent(Message msg) { - this.msg = msg; + this.msgs = Collections.singletonList(msg); + } + + public MessageRemoveEvent(List<Message> msgs) { + this.msgs = msgs; } } @@ -310,4 +335,15 @@ public class BacklogFilter implements UICallback { private class UpdateRemoveEvent { } + + private class LoadBacklogEvent { + } + + private class BacklogLoadedEvent { + private final List<Message> messageList; + + public BacklogLoadedEvent(List<Message> messageList) { + this.messageList = messageList; + } + } } diff --git a/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/HybridBacklogStorage.java b/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/HybridBacklogStorage.java index a902a2068..0779ed071 100644 --- a/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/HybridBacklogStorage.java +++ b/app/src/main/java/de/kuschku/libquassel/localtypes/backlogstorage/HybridBacklogStorage.java @@ -33,6 +33,8 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import de.kuschku.libquassel.client.Client; import de.kuschku.libquassel.localtypes.BacklogFilter; @@ -55,6 +57,8 @@ public class HybridBacklogStorage implements BacklogStorage { @NonNull private final Set<BacklogFilter> filterSet = new HashSet<>(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private Client client; @NonNull @@ -233,10 +237,12 @@ public class HybridBacklogStorage implements BacklogStorage { } messages.addCallback(backlogFilter); synchronized (backlogs) { - List<Message> messageList = SQLite.select().from(Message.class).where(Message_Table.bufferInfo_id.eq(bufferId)).queryList(); - messages.addAll(messageList); backlogs.put(bufferId, messages); } + executor.submit((Runnable) () -> { + List<Message> messageList = SQLite.select().from(Message.class).where(Message_Table.bufferInfo_id.eq(bufferId)).queryList(); + messages.addAll(messageList); + }); filteredBacklogs.put(bufferId, filteredMessages); synchronized (filterSet) { filters.put(bufferId, backlogFilter); diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java index fcabcef88..aea9713ec 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/impl/IrcChannel.java @@ -48,7 +48,7 @@ import de.kuschku.libquassel.syncables.types.interfaces.QIrcChannel; import de.kuschku.libquassel.syncables.types.interfaces.QIrcUser; import de.kuschku.libquassel.syncables.types.interfaces.QNetwork; import de.kuschku.util.irc.ModeUtils; -import de.kuschku.util.observables.lists.ObservableSet; +import de.kuschku.util.observables.lists.ObservableSortedList; import static de.kuschku.util.AndroidAssert.assertEquals; @@ -62,13 +62,19 @@ public class IrcChannel extends AIrcChannel { private final String name; @NonNull private final Map<String, Set<Character>> userModes = new HashMap<>(); - private final ObservableSet<String> users = new ObservableSet<>(); @NonNull public Set<Character> D_channelModes = new HashSet<>(); private String topic; private String password; private boolean encrypted; private WeakReference<QNetwork> network = new WeakReference<>(null); + private final ObservableSortedList<String> users = new ObservableSortedList<>((o1, o2) -> { + if (userModes(o1).equals(userModes(o2))) { + return o1.compareToIgnoreCase(o2); + } else { + return network().lowestModeIndex(userModes(o1)) - network().lowestModeIndex(userModes(o2)); + } + }); private String codecForEncoding; private String codecForDecoding; // Because we don’t have networks at the beginning yet @@ -516,7 +522,7 @@ public class IrcChannel extends AIrcChannel { } @NonNull - public ObservableSet<String> users() { + public ObservableSortedList<String> users() { return users; } diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcChannel.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcChannel.java index 5e3d1d8c3..e210f60c8 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcChannel.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/interfaces/QIrcChannel.java @@ -28,7 +28,7 @@ import java.util.List; import de.kuschku.libquassel.client.Client; import de.kuschku.libquassel.syncables.Synced; -import de.kuschku.util.observables.lists.ObservableSet; +import de.kuschku.util.observables.lists.ObservableSortedList; public interface QIrcChannel extends QObservable<QIrcChannel> { boolean isKnownUser(QIrcUser ircuser); @@ -153,7 +153,7 @@ public interface QIrcChannel extends QObservable<QIrcChannel> { String getObjectName(); @NonNull - ObservableSet<String> users(); + ObservableSortedList<String> users(); void _ircUserNickChanged(String oldNick, String newNick); diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/fragment/ChatFragment.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/fragment/ChatFragment.java index 84d9bfa68..e70c56769 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/fragment/ChatFragment.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/fragment/ChatFragment.java @@ -111,7 +111,7 @@ public class ChatFragment extends BoundFragment { }; messages.addOnScrollListener(listener); - scrollDown.setOnClickListener(view1 -> messages.smoothScrollToPosition(0)); + scrollDown.setOnClickListener(view1 -> messages.scrollToPosition(0)); return view; } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicklist/NickListAdapter.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicklist/NickListAdapter.java index f5102ad57..f17b57e14 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicklist/NickListAdapter.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicklist/NickListAdapter.java @@ -28,8 +28,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import java.util.Comparator; - import butterknife.Bind; import butterknife.ButterKnife; import de.kuschku.libquassel.syncables.types.interfaces.QIrcChannel; @@ -37,71 +35,26 @@ import de.kuschku.libquassel.syncables.types.interfaces.QIrcUser; import de.kuschku.quasseldroid_ng.R; import de.kuschku.quasseldroid_ng.ui.theme.AppContext; import de.kuschku.util.CompatibilityUtils; -import de.kuschku.util.observables.callbacks.ElementCallback; import de.kuschku.util.observables.callbacks.wrappers.AdapterUICallbackWrapper; -import de.kuschku.util.observables.lists.ObservableSortedList; public class NickListAdapter extends RecyclerView.Adapter<NickListAdapter.NickViewHolder> { public static final int TYPE_NORMAL = 0; public static final int TYPE_AWAY = 1; private final AppContext context; + private final AdapterUICallbackWrapper callback; QIrcChannel channel; - ObservableSortedList<QIrcUser> users = new ObservableSortedList<>(new Comparator<QIrcUser>() { - @Override - public int compare(QIrcUser o1, QIrcUser o2) { - if (channel.userModes(o1).equals(channel.userModes(o2))) { - return o1.nick().compareToIgnoreCase(o2.nick()); - } else { - return channel.network().lowestModeIndex(channel.userModes(o1)) - channel.network().lowestModeIndex(channel.userModes(o2)); - } - } - }); - private ElementCallback<String> callback = new ElementCallback<String>() { - @Override - public void notifyItemInserted(String element) { - QIrcUser qIrcUser = channel.network().ircUser(element); - users.add(qIrcUser); - } - - @Override - public void notifyItemRemoved(String element) { - for (int i = 0; i < users.size(); i++) { - QIrcUser user = users.get(i); - if (user.nick().equals(element)) { - users.remove(i); - } - } - } - - @Override - public void notifyItemChanged(String element) { - QIrcUser user = channel.network().ircUser(element); - if (user != null) { - users.notifyItemChanged(user); - } - } - }; - public NickListAdapter(AppContext context) { this.context = context; - users.addCallback(new AdapterUICallbackWrapper(this)); + callback = new AdapterUICallbackWrapper(this); } public void setChannel(QIrcChannel channel) { if (this.channel != null) this.channel.users().removeCallback(callback); this.channel = channel; - this.users.clear(); - if (this.channel != null) { - for (String nick : channel.users()) { - QIrcUser ircUser = channel.network().ircUser(nick); - if (ircUser != null) { - users.add(ircUser); - } - } + if (this.channel != null) this.channel.users().addCallback(callback); - } notifyDataSetChanged(); } @@ -124,12 +77,16 @@ public class NickListAdapter extends RecyclerView.Adapter<NickListAdapter.NickVi @Override public void onBindViewHolder(NickViewHolder holder, int position) { - holder.bind(users.get(position)); + holder.bind(getItem(position)); } @Override public int getItemCount() { - return users.size(); + return this.channel != null ? this.channel.users().size() : 0; + } + + public QIrcUser getItem(int position) { + return this.channel != null ? this.channel.network().ircUser(this.channel.users().get(position)) : null; } @NonNull @@ -143,7 +100,7 @@ public class NickListAdapter extends RecyclerView.Adapter<NickListAdapter.NickVi @Override public int getItemViewType(int position) { - return users.get(position).isAway() ? TYPE_AWAY : TYPE_NORMAL; + return getItem(position).isAway() ? TYPE_AWAY : TYPE_NORMAL; } class NickViewHolder extends RecyclerView.ViewHolder { diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 099972e36..e40c9bbf8 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -44,5 +44,5 @@ <FrameLayout android:id="@+id/content_host" android:layout_width="match_parent" - android:layout_height="wrap_content"/> + android:layout_height="match_parent"/> </LinearLayout> -- GitLab