Progressbar 快速从 endlessrecycleview 中移除
Progressbar quickly removed from endlessrecycleview
基本上我在我的项目中使用 MVP 和 RxJava,但是由于缺少 Youtube 的 Rx 版本API 我没有使用我的 MVP 方法。
目前我正在尝试制作 endlessrecycleview
的经典实现(使用 thread 的 )来显示 youtube 视频。
我当前方法的问题是我无法弄清楚为什么 ProgressBar
很快被 endlessrecyleview
隐藏了。
private void setupRecyclerView() {
mYoutubeVideoRecyclerView.setAdapter(adapter);
mYoutubeVideoRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mYoutubeVideoRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (true && !(hasFooter())) {
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
//position starts at 0
if (layoutManager.findLastCompletelyVisibleItemPosition()
== layoutManager.getItemCount() - 2) {
Log.d(TAG, "ProgressBar - item INSERTED At index = " + adapter.getItemCount());
adapter.getVideos().add(null);
recyclerView.getAdapter().notifyItemInserted(adapter.getItemCount() - 1);
// TODO: 9/20/16 the bellow 2 lines make the progressbar not being displayed
getYoutubeVideos();
displayDataOrShowMessage();
}
}
}
});
}
...
private void getYoutubeVideos() {
Thread thread = new Thread(new Runnable() {
@Override public void run() {
try {
videoEntries = videoPresenter.getYoutubeVideoList(getActivity());
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
...
private void displayDataOrShowMessage() {
if (videoEntries != null) {
showVideos(videoEntries);
showSelectedVideo((videoEntries.get(0)).getVideoId());
} else {
showMessage(R.string.probleme_connection);
((VideoPlayerFragment) (getActivity()).getFragmentManager().findFragmentByTag("video_player"))
.pause();
}
}
...
public void showVideos(List<VideoEntry> videos) {
Log.d(TAG, "ProgressBar - Adapter data size before adding items = " + adapter.getItemCount());
try {
int size = adapter.getItemCount();
Log.d(TAG, "ProgressBar - item REMOVED from index = " + adapter.getItemCount());
adapter.getVideos().remove(size - 1);//removes footer
adapter.addVideos(videos);
adapter.notifyItemRangeChanged(size - 1, adapter.getItemCount() - size);
} catch (ArrayIndexOutOfBoundsException e) {
adapter.addVideos(videos);
adapter.notifyDataSetChanged();
}
Log.d(TAG, "ProgressBar - Adapter data size after adding items = " + adapter.getItemCount());
mYoutubeVideoRecyclerView.requestFocus();
progressBar.setVisibility(View.INVISIBLE);
infoTextView.setVisibility(View.INVISIBLE);
mYoutubeVideoRecyclerView.setVisibility(View.VISIBLE);
Log.d(TAG, "showVideos -- data is set to list");
}
它不起作用,因为您启动了一个新线程并使 UI 线程在您调用 join()
.
时等待它完成
您实际上是在阻塞 UI 线程,因此 adapter.getVideos().add(null);
和 adapter.getVideos().remove(size - 1);
会一个接一个地被立即调用,并且永远无法在屏幕上正确绘制。
你要做的是让那个线程 运行 空闲,不要 join()
它并将 videos
传回 UI 线程然后添加他们到适配器。当然,说起来容易做起来难。
一种 "easy" 方法是使用 AsyncTask
(https://developer.android.com/reference/android/os/AsyncTask.html),但如果您不知道自己的内存是什么,它们也有自己的潜在内存泄漏问题正在做。
正确的方法是让来自适配器的数据成为一个可以subscribed/unsusbribed
的东西,然后让后台线程添加数据。但这是一个更大的重构,而不是答案的范围。
我知道这不是一个完整的答案,但我希望它能为您指明方向。
此外,我建议使用这个库 https://github.com/eyeem/RecyclerViewTools(我创建的)。它完全支持开箱即用的 heades/footers 和 EndlessScroll,应该可以使您的一些代码更容易。
好吧,异步是地狱所以我做了一个代码重构来使用 Rx 版本:
public void getYoutubeVideoList(final Context context, Boolean isRefresh) {
MalitelApplication application = MalitelApplication.get(videoMvpView.getContext());
MalitelService malitelService = application.getMalitelService(Constants.malitelYoutubeUrl);
subscription = application.getYoutubeConnector().getYoutubeVideosObservable(isRefresh)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(application.defaultSubscribeScheduler())
.subscribe(new Observer<List<VideoEntry>>() {
@Override public void onCompleted() {
}
@Override public void onError(Throwable e) {
videoMvpView.showMessage(R.string.probleme_connection);
}
@Override public void onNext(List<VideoEntry> videos) {
videoMvpView.showVideos(videos);
videoMvpView.showSelectedVideo((videos.get(0)).getText());
}
});
}
..
public Observable<List<VideoEntry>> getYoutubeVideosObservable(final Boolean isRefresh) {
return Observable.create(new Observable.OnSubscribe<List<VideoEntry>>() {
@Override public void call(Subscriber<? super List<VideoEntry>> subscriber) {
try {
search =
youtube.search().list("id,snippet").setChannelId(Constants.malitelYoutubeChannelId);
search.setKey(DeveloperKey.DEVELOPER_KEY);
search.setType("video");
search.setMaxResults(NUMBER_OF_VIDEOS_RETURNED);
search.setFields(
"items(id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url),"
+ "nextPageToken,pageInfo,prevPageToken");
if (!isRefresh) {
search.setPageToken(nextPageToken);
} else {
totalResults = 0;
}
} catch (IOException e) {
Log.d(TAG, "Could not initialize: " + e);
}
// Call the API and print results.
SearchListResponse searchResponse = null;
List<SearchResult> searchResultList = null;
try {
searchResponse = search.execute();
if (searchResponse != null) {
searchResultList = searchResponse.getItems();
nextPageToken = searchResponse.getNextPageToken();
if (nextPageToken != null) Log.d(TAG, nextPageToken);
}
if (searchResultList != null) {
fillVideoEntry(searchResultList.iterator());
}
if (mVideoEntries != null) {
totalResults += mVideoEntries.size();
Log.d(TAG, "totalResults : " + totalResults);
}
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(mVideoEntries);
subscriber.onCompleted();
}
} catch (IOException e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
}
});
}
基本上我在我的项目中使用 MVP 和 RxJava,但是由于缺少 Youtube 的 Rx 版本API 我没有使用我的 MVP 方法。
目前我正在尝试制作 endlessrecycleview
的经典实现(使用 thread 的 )来显示 youtube 视频。
我当前方法的问题是我无法弄清楚为什么 ProgressBar
很快被 endlessrecyleview
隐藏了。
private void setupRecyclerView() {
mYoutubeVideoRecyclerView.setAdapter(adapter);
mYoutubeVideoRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mYoutubeVideoRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (true && !(hasFooter())) {
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
//position starts at 0
if (layoutManager.findLastCompletelyVisibleItemPosition()
== layoutManager.getItemCount() - 2) {
Log.d(TAG, "ProgressBar - item INSERTED At index = " + adapter.getItemCount());
adapter.getVideos().add(null);
recyclerView.getAdapter().notifyItemInserted(adapter.getItemCount() - 1);
// TODO: 9/20/16 the bellow 2 lines make the progressbar not being displayed
getYoutubeVideos();
displayDataOrShowMessage();
}
}
}
});
}
...
private void getYoutubeVideos() {
Thread thread = new Thread(new Runnable() {
@Override public void run() {
try {
videoEntries = videoPresenter.getYoutubeVideoList(getActivity());
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
...
private void displayDataOrShowMessage() {
if (videoEntries != null) {
showVideos(videoEntries);
showSelectedVideo((videoEntries.get(0)).getVideoId());
} else {
showMessage(R.string.probleme_connection);
((VideoPlayerFragment) (getActivity()).getFragmentManager().findFragmentByTag("video_player"))
.pause();
}
}
...
public void showVideos(List<VideoEntry> videos) {
Log.d(TAG, "ProgressBar - Adapter data size before adding items = " + adapter.getItemCount());
try {
int size = adapter.getItemCount();
Log.d(TAG, "ProgressBar - item REMOVED from index = " + adapter.getItemCount());
adapter.getVideos().remove(size - 1);//removes footer
adapter.addVideos(videos);
adapter.notifyItemRangeChanged(size - 1, adapter.getItemCount() - size);
} catch (ArrayIndexOutOfBoundsException e) {
adapter.addVideos(videos);
adapter.notifyDataSetChanged();
}
Log.d(TAG, "ProgressBar - Adapter data size after adding items = " + adapter.getItemCount());
mYoutubeVideoRecyclerView.requestFocus();
progressBar.setVisibility(View.INVISIBLE);
infoTextView.setVisibility(View.INVISIBLE);
mYoutubeVideoRecyclerView.setVisibility(View.VISIBLE);
Log.d(TAG, "showVideos -- data is set to list");
}
它不起作用,因为您启动了一个新线程并使 UI 线程在您调用 join()
.
您实际上是在阻塞 UI 线程,因此 adapter.getVideos().add(null);
和 adapter.getVideos().remove(size - 1);
会一个接一个地被立即调用,并且永远无法在屏幕上正确绘制。
你要做的是让那个线程 运行 空闲,不要 join()
它并将 videos
传回 UI 线程然后添加他们到适配器。当然,说起来容易做起来难。
一种 "easy" 方法是使用 AsyncTask
(https://developer.android.com/reference/android/os/AsyncTask.html),但如果您不知道自己的内存是什么,它们也有自己的潜在内存泄漏问题正在做。
正确的方法是让来自适配器的数据成为一个可以subscribed/unsusbribed
的东西,然后让后台线程添加数据。但这是一个更大的重构,而不是答案的范围。
我知道这不是一个完整的答案,但我希望它能为您指明方向。
此外,我建议使用这个库 https://github.com/eyeem/RecyclerViewTools(我创建的)。它完全支持开箱即用的 heades/footers 和 EndlessScroll,应该可以使您的一些代码更容易。
好吧,异步是地狱所以我做了一个代码重构来使用 Rx 版本:
public void getYoutubeVideoList(final Context context, Boolean isRefresh) {
MalitelApplication application = MalitelApplication.get(videoMvpView.getContext());
MalitelService malitelService = application.getMalitelService(Constants.malitelYoutubeUrl);
subscription = application.getYoutubeConnector().getYoutubeVideosObservable(isRefresh)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(application.defaultSubscribeScheduler())
.subscribe(new Observer<List<VideoEntry>>() {
@Override public void onCompleted() {
}
@Override public void onError(Throwable e) {
videoMvpView.showMessage(R.string.probleme_connection);
}
@Override public void onNext(List<VideoEntry> videos) {
videoMvpView.showVideos(videos);
videoMvpView.showSelectedVideo((videos.get(0)).getText());
}
});
}
..
public Observable<List<VideoEntry>> getYoutubeVideosObservable(final Boolean isRefresh) {
return Observable.create(new Observable.OnSubscribe<List<VideoEntry>>() {
@Override public void call(Subscriber<? super List<VideoEntry>> subscriber) {
try {
search =
youtube.search().list("id,snippet").setChannelId(Constants.malitelYoutubeChannelId);
search.setKey(DeveloperKey.DEVELOPER_KEY);
search.setType("video");
search.setMaxResults(NUMBER_OF_VIDEOS_RETURNED);
search.setFields(
"items(id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url),"
+ "nextPageToken,pageInfo,prevPageToken");
if (!isRefresh) {
search.setPageToken(nextPageToken);
} else {
totalResults = 0;
}
} catch (IOException e) {
Log.d(TAG, "Could not initialize: " + e);
}
// Call the API and print results.
SearchListResponse searchResponse = null;
List<SearchResult> searchResultList = null;
try {
searchResponse = search.execute();
if (searchResponse != null) {
searchResultList = searchResponse.getItems();
nextPageToken = searchResponse.getNextPageToken();
if (nextPageToken != null) Log.d(TAG, nextPageToken);
}
if (searchResultList != null) {
fillVideoEntry(searchResultList.iterator());
}
if (mVideoEntries != null) {
totalResults += mVideoEntries.size();
Log.d(TAG, "totalResults : " + totalResults);
}
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(mVideoEntries);
subscriber.onCompleted();
}
} catch (IOException e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
}
});
}