Progressbar quickly removed from endlessrecycleview

Basically I use MVP with RxJava in my project, but due to the missing of Rx version of Youtube API I didn't use my MVP approach.

Currently I'm trying to make a classic implementation (using thread's) of endlessrecycleview that display youtube videos.

The problem with my current approach is that I can't figure out why the ProgressBar is quickly hidden from the 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");
  }

Answers


It doesn't work because you start a new thread and makes the UI thread wait for it to finish when you call join().

You're essentially blocking the UI thread, so adapter.getVideos().add(null); and adapter.getVideos().remove(size - 1); are called immediatly one after the other and it never gets properly draw on the screen.

what you have to do is to let that thread run free, DO NOT join() it and pass the videos back to the UI thread to then add them to the adapter. But of course it's easier said than done.

One "easy" way is to use an AsyncTask (https://developer.android.com/reference/android/os/AsyncTask.html) but those have it's own share of issues with potential memory leak if you don't know what your're doing.

The proper approach is to have the data from the adapter a thing that can be subscribed/unsusbribed and let the background thread add the data. But that is a bigger refactor and not scope of the answer.

I know it's not a complete answer, but I hope it points you to the direction.

Also, I suggest using this library https://github.com/eyeem/RecyclerViewTools (that I created). It has full support to heades/footers and EndlessScroll out of the box and should make some of your code easier.


Ok, Async is hell so I made a code refactor to use Rx version :

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);
          }
        }
      }
    });
  }

Need Your Help

Struts2 session management througout the application

session struts2

How to manage the session in struts2 application.

Lua pattern for guid

regex lua guid lua-patterns

I am trying to implement a pattern in Lua but no success