Skip to content

Commit

Permalink
fix(android): improve pre-loading optimization of ListView and TableV…
Browse files Browse the repository at this point in the history
…iew (#12870)

Fixes TIMOB-28439
  • Loading branch information
build committed Jun 7, 2021
1 parent f8610c9 commit 35d2b16
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,6 @@ public void call(Object data)
final KrollDict childTemplate = new KrollDict((HashMap) o);
final TiViewProxy childView = generateViewFromTemplate(null, childTemplate);
if (childView != null) {
childView.setActivity(parent.getActivity());
parent.add(childView);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ public void bind(final ListItemProxy proxy, final boolean selected)
// Only set header on first row in section.
setHeaderFooter(listViewProxy, sectionProperties, true, false);
}
if ((indexInSection >= section.getItems().length - 1)
if ((indexInSection >= section.getItemCount() - 1)
|| (filteredIndex >= section.getFilteredItemCount() - 1)
|| proxy.isPlaceholder()) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.os.Handler;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;

Expand All @@ -42,8 +44,8 @@ public class TiListView extends TiSwipeRefreshLayout implements OnSearchChangeLi
{
private static final String TAG = "TiListView";

private static final int CACHE_SIZE = 8;
private static final int PRELOAD_SIZE = CACHE_SIZE / 2;
private static final int CACHE_SIZE = 32;
private static final int PRELOAD_INTERVAL = 800;

private final ListViewAdapter adapter;
private final DividerItemDecoration decoration;
Expand Down Expand Up @@ -573,12 +575,33 @@ public void update()

// Pre-load items of empty list.
if (shouldPreload) {
final int preloadSize = Math.min(this.items.size(), PRELOAD_SIZE);
final Handler handler = new Handler();
final long startTime = SystemClock.elapsedRealtime();

for (int i = 0; i < preloadSize; i++) {
for (int i = 0; i < Math.min(this.items.size(), PRELOAD_INTERVAL / 8); i++) {
final ListItemProxy item = this.items.get(i);

// Pre-load views for smooth initial scroll.
this.items.get(i).getOrCreateView();
// Fill event queue with pre-load attempts.
handler.postDelayed(new Runnable()
{
@Override
public void run()
{
final long currentTime = SystemClock.elapsedRealtime();
final long delta = currentTime - startTime;

// Only pre-load views for a maximum period of time.
// This prevents over-taxing older devices.
if (delta <= PRELOAD_INTERVAL
&& recyclerView.getLastTouchX() == 0
&& recyclerView.getLastTouchY() == 0) {

// While there is no user interaction;
// pre-load views for smooth initial scroll.
item.getOrCreateView();
}
}
}, 8); // Pre-load at 120Hz to prevent noticeable UI blocking.
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.os.Handler;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;

Expand Down Expand Up @@ -47,8 +49,8 @@ public class TiTableView extends TiSwipeRefreshLayout implements OnSearchChangeL
{
private static final String TAG = "TiTableView";

private static final int CACHE_SIZE = 8;
private static final int PRELOAD_SIZE = CACHE_SIZE / 2;
private static final int CACHE_SIZE = 32;
private static final int PRELOAD_INTERVAL = 800;

private final TableViewAdapter adapter;
private final DividerItemDecoration decoration;
Expand Down Expand Up @@ -529,13 +531,35 @@ public void update()
this.proxy.fireEvent(TiC.EVENT_NO_RESULTS, null);
}

// Pre-load items of empty list.
if (shouldPreload) {
final int preloadSize = Math.min(this.rows.size(), PRELOAD_SIZE);
final Handler handler = new Handler();
final long startTime = SystemClock.elapsedRealtime();

for (int i = 0; i < preloadSize; i++) {
for (int i = 0; i < Math.min(this.rows.size(), PRELOAD_INTERVAL / 8); i++) {
final TableViewRowProxy row = this.rows.get(i);

// Pre-load views for smooth initial scroll.
this.rows.get(i).getOrCreateView();
// Fill event queue with pre-load attempts.
handler.postDelayed(new Runnable()
{
@Override
public void run()
{
final long currentTime = SystemClock.elapsedRealtime();
final long delta = currentTime - startTime;

// Only pre-load views for a maximum period of time.
// This prevents over-taxing older devices.
if (delta <= PRELOAD_INTERVAL
&& recyclerView.getLastTouchX() == 0
&& recyclerView.getLastTouchY() == 0) {

// While there is no user interaction;
// pre-load views for smooth initial scroll.
row.getOrCreateView();
}
}
}, 8); // Pre-load at 120Hz to prevent noticeable UI blocking.
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public final class ReferenceTable
* A simple Map used to hold strong/weak reference to the Java objects we have paired/wrapped in native
* titanium::Proxy/JavaObject instances.
*/
private static final HashMap<Long, Object> references = new HashMap<>();
private static final HashMap<Long, Object> references = new HashMap<>(1024);

/**
* Incrementing key, used to generate new keys when a new strong reference is created. FIXME Handle "wrapping" the
Expand Down Expand Up @@ -77,7 +77,6 @@ public static void makeWeakReference(long key)
{
Log.d(TAG, "Downgrading to weak reference for key: " + key, Log.DEBUG_MODE);
Object ref = getReference(key);
references.remove(key);
references.put(key, new WeakReference<>(ref));
}

Expand All @@ -90,7 +89,6 @@ public static void makeSoftReference(long key)
{
Log.d(TAG, "Downgrading to soft reference for key: " + key, Log.DEBUG_MODE);
Object ref = getReference(key);
references.remove(key);
references.put(key, new SoftReference<>(ref));
}

Expand All @@ -105,7 +103,6 @@ public static Object clearReference(long key)
{
Log.d(TAG, "Upgrading reference to strong for key: " + key, Log.DEBUG_MODE);
Object ref = getReference(key);
references.remove(key);
references.put(key, ref);
return ref;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
Expand All @@ -42,8 +45,8 @@ public class TiDownloadManager implements Handler.Callback
protected static TiDownloadManager _instance;
public static final int THREAD_POOL_SIZE = 2;

protected HashMap<String, ArrayList<SoftReference<TiDownloadListener>>> listeners = new HashMap<>();
protected ArrayList<String> downloadingURIs = new ArrayList<>();
protected Map<String, List<SoftReference<TiDownloadListener>>> listeners = new HashMap<>();
protected List<String> downloadingURIs = Collections.synchronizedList(new ArrayList<>());
protected ExecutorService threadPool;
protected Handler handler;

Expand Down Expand Up @@ -242,42 +245,53 @@ private void sendMessage(URI uri, int what)
protected void startDownload(URI uri, TiDownloadListener listener)
{
String key = uri.toString();
ArrayList<SoftReference<TiDownloadListener>> listenerList = null;
List<SoftReference<TiDownloadListener>> listenerList;

synchronized (listeners)
{
if (!listeners.containsKey(key)) {
listenerList = new ArrayList<SoftReference<TiDownloadListener>>();
listenerList = listeners.get(key);

if (listenerList == null) {
listenerList = new ArrayList<>();
listeners.put(key, listenerList);
} else {
listenerList = listeners.get(key);
}
// We only allow a listener once per URI
for (SoftReference<TiDownloadListener> l : listenerList) {
if (l.get() == listener) {
}

synchronized (listenerList)
{
for (Iterator<SoftReference<TiDownloadListener>> i = listenerList.iterator(); i.hasNext(); ) {
TiDownloadListener downloadListener = i.next().get();

if (downloadListener == listener) {
return;
}
}
listenerList.add(new SoftReference<TiDownloadListener>(listener));
listenerList.add(new SoftReference<>(listener));
}
synchronized (downloadingURIs)
{
if (!downloadingURIs.contains(key)) {
downloadingURIs.add(key);
threadPool.execute(new DownloadJob(uri));
}

if (downloadingURIs.add(key)) {
threadPool.execute(new DownloadJob(uri));
}
}

protected void handleFireDownloadMessage(URI uri, int what)
{
ArrayList<SoftReference<TiDownloadListener>> listenerList;
List<SoftReference<TiDownloadListener>> listenerList;

synchronized (listeners)
{
listenerList = listeners.get(uri.toString());
}
if (listenerList != null) {
for (Iterator<SoftReference<TiDownloadListener>> i = listenerList.iterator(); i.hasNext();) {

if (listenerList == null) {
return;
}

synchronized (listenerList)
{
for (Iterator<SoftReference<TiDownloadListener>> i = listenerList.iterator(); i.hasNext(); ) {
TiDownloadListener downloadListener = i.next().get();

if (downloadListener != null) {
if (what == MSG_FIRE_DOWNLOAD_FINISHED) {
downloadListener.downloadTaskFinished(uri);
Expand Down Expand Up @@ -310,20 +324,25 @@ public void run()
}
}

synchronized (downloadingURIs)
{
downloadingURIs.remove(uri.toString());
}
downloadingURIs.remove(uri.toString());

// If there is additional background task, run it here.
ArrayList<SoftReference<TiDownloadListener>> listenerList;

List<SoftReference<TiDownloadListener>> listenerList;

synchronized (listeners)
{
listenerList = listeners.get(uri.toString());

if (listenerList != null) {
listenerList = new ArrayList<>(listenerList);
}
}

if (listenerList != null) {
for (Iterator<SoftReference<TiDownloadListener>> i = listenerList.iterator(); i.hasNext();) {
TiDownloadListener downloadListener = i.next().get();
for (SoftReference<TiDownloadListener> listener : listenerList) {
TiDownloadListener downloadListener = listener.get();

if (downloadListener != null) {
downloadListener.postDownload(uri);
}
Expand All @@ -333,10 +352,7 @@ public void run()
sendMessage(uri, MSG_FIRE_DOWNLOAD_FINISHED);
} catch (Exception e) {

synchronized (downloadingURIs)
{
downloadingURIs.remove(uri.toString());
}
downloadingURIs.remove(uri.toString());

// fire a download fail event if we are unable to download
sendMessage(uri, MSG_FIRE_DOWNLOAD_FAILED);
Expand Down

0 comments on commit 35d2b16

Please sign in to comment.