[Android] [PATCH] Async browser fragments loading
Geoffrey Métais
geoffrey.metais at gmail.com
Mon Dec 1 10:55:08 CET 2014
---
vlc-android/res/layout/audio_browser.xml | 23 ++++---
.../videolan/vlc/gui/DirectoryViewFragment.java | 15 ++++-
.../src/org/videolan/vlc/gui/HistoryFragment.java | 15 ++++-
.../src/org/videolan/vlc/gui/MainActivity.java | 14 +++-
.../vlc/gui/audio/AudioBrowserFragment.java | 72 +++++++++++++++------
.../vlc/gui/audio/AudioBrowserListAdapter.java | 4 +-
.../videolan/vlc/gui/video/VideoGridFragment.java | 74 +++++++++++++++-------
.../src/org/videolan/vlc/interfaces/IBrowser.java | 9 +++
8 files changed, 167 insertions(+), 59 deletions(-)
create mode 100644 vlc-android/src/org/videolan/vlc/interfaces/IBrowser.java
diff --git a/vlc-android/res/layout/audio_browser.xml b/vlc-android/res/layout/audio_browser.xml
index 27ef224..504e7db 100644
--- a/vlc-android/res/layout/audio_browser.xml
+++ b/vlc-android/res/layout/audio_browser.xml
@@ -1,12 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
+ android:layout_height="fill_parent">
<org.videolan.vlc.widget.HeaderScrollView
android:id="@+id/header"
android:scrollbars="none"
@@ -77,12 +73,20 @@
android:layout_alignRight="@+id/header"
android:layout_alignTop="@+id/header"
android:background="?attr/header_fadeout_overlay" />
- </RelativeLayout>
+ <ProgressBar
+ android:id="@+id/loading_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/header"
+ android:indeterminate="true"
+ android:layout_centerInParent="true"
+ android:visibility="gone"/>
<TextView
android:id="@+id/no_media"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:layout_below="@+id/header"
android:gravity="center"
android:text="@string/nomedia"
android:textSize="20sp"
@@ -91,7 +95,8 @@
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeLayout"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:layout_below="@+id/header">
<org.videolan.vlc.widget.FlingViewGroup
android:id="@+id/content"
android:layout_width="match_parent"
@@ -155,4 +160,4 @@
android:nextFocusRight="@+id/genres_list" />
</org.videolan.vlc.widget.FlingViewGroup>
</android.support.v4.widget.SwipeRefreshLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/vlc-android/src/org/videolan/vlc/gui/DirectoryViewFragment.java b/vlc-android/src/org/videolan/vlc/gui/DirectoryViewFragment.java
index 0743533..040b60f 100644
--- a/vlc-android/src/org/videolan/vlc/gui/DirectoryViewFragment.java
+++ b/vlc-android/src/org/videolan/vlc/gui/DirectoryViewFragment.java
@@ -28,6 +28,7 @@ import org.videolan.libvlc.LibVlcUtil;
import org.videolan.vlc.R;
import org.videolan.vlc.audio.AudioServiceController;
import org.videolan.vlc.gui.video.VideoPlayerActivity;
+import org.videolan.vlc.interfaces.IBrowser;
import org.videolan.vlc.interfaces.IRefreshable;
import org.videolan.vlc.interfaces.ISortable;
import org.videolan.vlc.util.Util;
@@ -59,11 +60,12 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
-public class DirectoryViewFragment extends ListFragment implements IRefreshable, ISortable, SwipeRefreshLayout.OnRefreshListener {
+public class DirectoryViewFragment extends ListFragment implements IBrowser, IRefreshable, ISortable, SwipeRefreshLayout.OnRefreshListener {
public final static String TAG = "VLC/DirectoryViewFragment";
private DirectoryAdapter mDirectoryAdapter;
private SwipeRefreshLayout mSwipeRefreshLayout;
+ private boolean mReady = true;
/* All subclasses of Fragment must include a public empty constructor. */
public DirectoryViewFragment() { }
@@ -292,4 +294,15 @@ public class DirectoryViewFragment extends ListFragment implements IRefreshable,
public void onRefresh() {
refresh();
}
+
+ @Override
+ public void setReadyToDisplay(boolean ready) {
+ mReady = ready;
+ }
+
+ @Override
+ public void display() {
+ refresh();
+ mReady = true;
+ }
}
diff --git a/vlc-android/src/org/videolan/vlc/gui/HistoryFragment.java b/vlc-android/src/org/videolan/vlc/gui/HistoryFragment.java
index f7dfc28..f9335be 100644
--- a/vlc-android/src/org/videolan/vlc/gui/HistoryFragment.java
+++ b/vlc-android/src/org/videolan/vlc/gui/HistoryFragment.java
@@ -24,6 +24,7 @@ import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.LibVlcUtil;
import org.videolan.vlc.R;
import org.videolan.vlc.audio.AudioServiceController;
+import org.videolan.vlc.interfaces.IBrowser;
import org.videolan.vlc.interfaces.IRefreshable;
import android.os.Bundle;
@@ -41,11 +42,12 @@ import android.widget.AbsListView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ListView;
-public class HistoryFragment extends ListFragment implements IRefreshable, SwipeRefreshLayout.OnRefreshListener {
+public class HistoryFragment extends ListFragment implements IBrowser, IRefreshable, SwipeRefreshLayout.OnRefreshListener {
public final static String TAG = "VLC/HistoryFragment";
private HistoryAdapter mHistoryAdapter;
private SwipeRefreshLayout mSwipeRefreshLayout;
+ private boolean mReady = true;
/* All subclasses of Fragment must include a public empty constructor. */
public HistoryFragment() { }
@@ -151,4 +153,15 @@ public class HistoryFragment extends ListFragment implements IRefreshable, Swipe
public void onRefresh() {
refresh();
}
+
+ @Override
+ public void setReadyToDisplay(boolean ready) {
+ mReady = ready;
+ }
+
+ @Override
+ public void display() {
+ refresh();
+ mReady = true;
+ }
}
diff --git a/vlc-android/src/org/videolan/vlc/gui/MainActivity.java b/vlc-android/src/org/videolan/vlc/gui/MainActivity.java
index 74540d9..c2e05c6 100644
--- a/vlc-android/src/org/videolan/vlc/gui/MainActivity.java
+++ b/vlc-android/src/org/videolan/vlc/gui/MainActivity.java
@@ -40,6 +40,7 @@ import org.videolan.vlc.gui.audio.EqualizerFragment;
import org.videolan.vlc.gui.video.MediaInfoFragment;
import org.videolan.vlc.gui.video.VideoGridFragment;
import org.videolan.vlc.gui.video.VideoListAdapter;
+import org.videolan.vlc.interfaces.IBrowser;
import org.videolan.vlc.interfaces.IRefreshable;
import org.videolan.vlc.interfaces.ISortable;
import org.videolan.vlc.util.AndroidDevices;
@@ -229,7 +230,13 @@ public class MainActivity extends ActionBarActivity {
/* Set up the sidebar click listener
* no need to invalidate menu for now */
- mDrawerToggle = new ActionBarDrawerToggle(this, mRootContainer, R.string.drawer_open, R.string.drawer_close);
+ mDrawerToggle = new ActionBarDrawerToggle(this, mRootContainer, R.string.drawer_open, R.string.drawer_close){
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ ((IBrowser) getSupportFragmentManager().findFragmentById(R.id.fragment_placeholder)).setReadyToDisplay(true);
+ }
+ };
// Set the drawer toggle as the DrawerListener
mRootContainer.setDrawerListener(mDrawerToggle);
@@ -267,8 +274,10 @@ public class MainActivity extends ActionBarActivity {
slideDownAudioPlayer();
/* Switch the fragment */
+ Fragment fragment = getFragment(entry.id);
+ ((IBrowser)fragment).setReadyToDisplay(false);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- ft.replace(R.id.fragment_placeholder, getFragment(entry.id), entry.id);
+ ft.replace(R.id.fragment_placeholder, fragment, entry.id);
ft.commit();
supportInvalidateOptionsMenu();
mCurrentFragment = entry.id;
@@ -291,7 +300,6 @@ public class MainActivity extends ActionBarActivity {
}else if (entry.attributeID == R.attr.ic_menu_preferences){
startActivityForResult(new Intent(mContext, PreferencesActivity.class), ACTIVITY_RESULT_PREFERENCES);
}
- mRootContainer.closeDrawer(mListView);
}
});
diff --git a/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserFragment.java b/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserFragment.java
index fd223f4..26f53ec 100644
--- a/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserFragment.java
+++ b/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserFragment.java
@@ -21,7 +21,6 @@
package org.videolan.vlc.gui.audio;
import android.annotation.TargetApi;
-import android.app.Activity;
import android.app.AlertDialog;
import android.os.Build;
import android.os.Bundle;
@@ -50,12 +49,14 @@ import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
+import android.widget.ProgressBar;
import org.videolan.libvlc.LibVlcUtil;
import org.videolan.libvlc.Media;
import org.videolan.vlc.MediaLibrary;
import org.videolan.vlc.R;
import org.videolan.vlc.audio.AudioServiceController;
+import org.videolan.vlc.interfaces.IBrowser;
import org.videolan.vlc.gui.CommonDialogs;
import org.videolan.vlc.gui.MainActivity;
import org.videolan.vlc.util.AndroidDevices;
@@ -69,7 +70,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-public class AudioBrowserFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
+public class AudioBrowserFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, IBrowser {
public final static String TAG = "VLC/AudioBrowserFragment";
private FlingViewGroup mFlingViewGroup;
@@ -84,6 +85,7 @@ public class AudioBrowserFragment extends Fragment implements SwipeRefreshLayout
private AudioBrowserListAdapter mArtistsAdapter;
private AudioBrowserListAdapter mAlbumsAdapter;
private AudioBrowserListAdapter mGenresAdapter;
+ private View mLoading;
private View mEmptyView;
@@ -93,6 +95,9 @@ public class AudioBrowserFragment extends Fragment implements SwipeRefreshLayout
public final static int MODE_SONG = 2;
public final static int MODE_GENRE = 3;
+ public final static int MSG_LOADING = 0;
+ private volatile boolean mReadyToDisplay = true;
+
/* All subclasses of Fragment must include a public empty constructor. */
public AudioBrowserFragment() { }
@@ -136,6 +141,7 @@ public class AudioBrowserFragment extends Fragment implements SwipeRefreshLayout
mHeader.setOnKeyListener(keyListener);
mEmptyView = v.findViewById(R.id.no_media);
+ mLoading = (ProgressBar) v.findViewById(R.id.loading_view);
ListView songsList = (ListView)v.findViewById(R.id.songs_list);
ListView artistList = (ListView)v.findViewById(R.id.artists_list);
@@ -470,6 +476,43 @@ public class AudioBrowserFragment extends Fragment implements SwipeRefreshLayout
updateLists();
}
+ @Override
+ public void setReadyToDisplay(boolean ready) {
+ if (mLoading != null && mLoading.getVisibility() == View.VISIBLE)
+ display();
+ else
+ mReadyToDisplay = ready;
+ }
+
+ @Override
+ public void display() {
+ mReadyToDisplay = true;
+ if (getActivity() != null)
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mSwipeRefreshLayout.setRefreshing(false);
+ mHandler.removeMessages(MSG_LOADING);
+ mLoading.setVisibility(View.GONE);
+ mArtistsAdapter.notifyDataSetChanged();
+ mSongsAdapter.notifyDataSetChanged();
+ mAlbumsAdapter.notifyDataSetChanged();
+ mGenresAdapter.notifyDataSetChanged();
+
+ // Refresh the fast scroll data, since SectionIndexer doesn't respect notifyDataSetChanged
+ int[] lists = {R.id.artists_list, R.id.albums_list, R.id.songs_list, R.id.genres_list};
+ if (getView() != null) {
+ ListView l;
+ for (int r : lists) {
+ l = (ListView) getView().findViewById(r);
+ l.setFastScrollEnabled(true);
+ }
+ }
+ focusHelper(false, R.id.artists_list);
+ }
+ });
+ }
+
private static class AudioBrowserHandler extends WeakHandler<AudioBrowserFragment> {
public AudioBrowserHandler(AudioBrowserFragment owner) {
super(owner);
@@ -484,22 +527,26 @@ public class AudioBrowserFragment extends Fragment implements SwipeRefreshLayout
case MediaLibrary.MEDIA_ITEMS_UPDATED:
fragment.updateLists();
break;
+ case MSG_LOADING:
+ if (!fragment.mReadyToDisplay)
+ fragment.mLoading.setVisibility(View.VISIBLE);
}
}
};
private void updateLists() {
- final Activity context = getActivity();
mSongsAdapter.clear();
mArtistsAdapter.clear();
mAlbumsAdapter.clear();
mGenresAdapter.clear();
final List<Media> audioList = MediaLibrary.getInstance().getAudioItems();
if (audioList.isEmpty()){
+ mSwipeRefreshLayout.setRefreshing(false);
mEmptyView.setVisibility(View.VISIBLE);
focusHelper(true, R.id.artists_list);
} else {
mEmptyView.setVisibility(View.GONE);
+ mHandler.sendEmptyMessageDelayed(MSG_LOADING, 300);
new Thread(new Runnable() {
@Override
@@ -517,23 +564,8 @@ public class AudioBrowserFragment extends Fragment implements SwipeRefreshLayout
Collections.sort(audioList, MediaComparators.byGenre);
mGenresAdapter.addAll(audioList, AudioBrowserListAdapter.TYPE_GENRES);
- context.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- // Refresh the fast scroll data, since SectionIndexer doesn't respect notifyDataSetChanged
- int[] lists = {R.id.artists_list, R.id.albums_list, R.id.songs_list, R.id.genres_list};
- if (getView() != null) {
- ListView l;
- for (int r : lists) {
- l = (ListView) getView().findViewById(r);
- l.setFastScrollEnabled(false);
- l.setFastScrollEnabled(true);
- }
- }
- focusHelper(false, R.id.artists_list);
- mSwipeRefreshLayout.setRefreshing(false);
- }
- });
+ if (mReadyToDisplay)
+ display();
}
}).start();
}
diff --git a/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserListAdapter.java b/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserListAdapter.java
index 082f343..9453b13 100644
--- a/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserListAdapter.java
+++ b/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserListAdapter.java
@@ -215,7 +215,7 @@ public class AudioBrowserListAdapter extends BaseAdapter implements SectionIndex
firstSeparator = false;
}
}
- notifyDataSetChanged();
+// notifyDataSetChanged();
}
public void addSeparator(String title, Media media) {
@@ -228,7 +228,7 @@ public class AudioBrowserListAdapter extends BaseAdapter implements SectionIndex
mSeparatorItemMap.put(title, item);
mItems.add(item);
}
- notifyDataSetChanged();
+// notifyDataSetChanged();
}
/**
diff --git a/vlc-android/src/org/videolan/vlc/gui/video/VideoGridFragment.java b/vlc-android/src/org/videolan/vlc/gui/video/VideoGridFragment.java
index 49a98f6..7294aaa 100644
--- a/vlc-android/src/org/videolan/vlc/gui/video/VideoGridFragment.java
+++ b/vlc-android/src/org/videolan/vlc/gui/video/VideoGridFragment.java
@@ -34,6 +34,7 @@ import org.videolan.vlc.MediaLibrary;
import org.videolan.vlc.R;
import org.videolan.vlc.Thumbnailer;
import org.videolan.vlc.audio.AudioServiceController;
+import org.videolan.vlc.interfaces.IBrowser;
import org.videolan.vlc.gui.CommonDialogs;
import org.videolan.vlc.gui.MainActivity;
import org.videolan.vlc.interfaces.ISortable;
@@ -74,7 +75,7 @@ import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.TextView;
-public class VideoGridFragment extends SherlockGridFragment implements ISortable, VideoBrowserInterface, SwipeRefreshLayout.OnRefreshListener {
+public class VideoGridFragment extends SherlockGridFragment implements IBrowser, ISortable, VideoBrowserInterface, SwipeRefreshLayout.OnRefreshListener {
public final static String TAG = "VLC/VideoListFragment";
@@ -101,6 +102,7 @@ public class VideoGridFragment extends SherlockGridFragment implements ISortable
private SwipeRefreshLayout mSwipeRefreshLayout;
private AudioServiceController mAudioController;
+ private boolean mReady = true;
// Gridview position saved in onPause()
private int mGVFirstVisiblePos;
@@ -397,38 +399,41 @@ public class VideoGridFragment extends SherlockGridFragment implements ISortable
public void updateList() {
if (!mSwipeRefreshLayout.isRefreshing())
mSwipeRefreshLayout.setRefreshing(true);
- List<Media> itemList = mMediaLibrary.getVideoItems();
+ final List<Media> itemList = mMediaLibrary.getVideoItems();
if (mThumbnailer != null)
mThumbnailer.clearJobs();
else
Log.w(TAG, "Can't generate thumbnails, the thumbnailer is missing");
+ mVideoAdapter.setNotifyOnChange(false);
mVideoAdapter.clear();
if (itemList.size() > 0) {
- if (mGroup != null || itemList.size() <= 10) {
- for (Media item : itemList) {
- if (mGroup == null || item.getTitle().startsWith(mGroup)) {
- mVideoAdapter.add(item);
- if (mThumbnailer != null)
- mThumbnailer.addJob(item);
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ if (mGroup != null || itemList.size() <= 10) {
+ for (Media item : itemList) {
+ if (mGroup == null || item.getTitle().startsWith(mGroup)) {
+ mVideoAdapter.add(item);
+ if (mThumbnailer != null)
+ mThumbnailer.addJob(item);
+ }
+ }
}
+ else {
+ List<MediaGroup> groups = MediaGroup.group(itemList);
+ for (MediaGroup item : groups) {
+ mVideoAdapter.add(item.getMedia());
+ if (mThumbnailer != null)
+ mThumbnailer.addJob(item);
+ }
+ }
+ if (mReady)
+ display();
}
- }
- else {
- List<MediaGroup> groups = MediaGroup.group(itemList);
- for (MediaGroup item : groups) {
- mVideoAdapter.add(item.getMedia());
- if (mThumbnailer != null)
- mThumbnailer.addJob(item);
- }
- }
- mVideoAdapter.sort();
- mGVFirstVisiblePos = mGridView.getFirstVisiblePosition();
- mGridView.setSelection(mGVFirstVisiblePos);
- mGridView.requestFocus();
- focusHelper(false);
+ }).start();
} else
focusHelper(true);
stopRefresh();
@@ -477,6 +482,29 @@ public class VideoGridFragment extends SherlockGridFragment implements ISortable
@Override
public void onRefresh() {
- updateList();
+ if (getActivity()!=null)
+ MediaLibrary.getInstance().loadMediaItems(getActivity(), true);
+ }
+
+ @Override
+ public void setReadyToDisplay(boolean ready) {
+ mReady = ready;
+ }
+
+ @Override
+ public void display() {
+ if (getActivity() != null)
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mVideoAdapter.sort();
+ mVideoAdapter.notifyDataSetChanged();
+ mGVFirstVisiblePos = mGridView.getFirstVisiblePosition();
+ mGridView.setSelection(mGVFirstVisiblePos);
+ mGridView.requestFocus();
+ focusHelper(false);
+ mReady = true;
+ }
+ });
}
}
diff --git a/vlc-android/src/org/videolan/vlc/interfaces/IBrowser.java b/vlc-android/src/org/videolan/vlc/interfaces/IBrowser.java
new file mode 100644
index 0000000..7d36c94
--- /dev/null
+++ b/vlc-android/src/org/videolan/vlc/interfaces/IBrowser.java
@@ -0,0 +1,9 @@
+package org.videolan.vlc.interfaces;
+
+/**
+ * Created by dekans on 11/28/14.
+ */
+public interface IBrowser {
+ void setReadyToDisplay(boolean ready);
+ void display();
+}
--
1.9.1
More information about the Android
mailing list