I am developing android app for Android Tv. I have a RecyclerView in which there are items that can be iterated over using the remote control (D-pad). When I reach the end of the RecyclerView, the focus (the stroke around the item in the RecyclerView) jumps or flies off the RecyclerView. I want the focus to stop at the end. Thanks in advance
My fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TV.TvPopularFragment">
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateDrawable="#drawable/progress_circle_style"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/moviesRecyclerView"
android:layout_width="match_parent"
android:nextFocusDown="#+id/moviesRecyclerView"
android:descendantFocusability="afterDescendants"
android:layout_height="match_parent"/>
</RelativeLayout>
My fragment.java
package org.vitaliy.moziapp.TV;
public class TvPopularFragment extends Fragment {
FragmentTvPopularBinding binding;
static public boolean isPopularOnTop = false;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentTvPopularBinding.inflate(inflater, container, false);
View root = binding.getRoot();
RecyclerView moviesRecycerView = binding.moviesRecyclerView;
ProgressBar progressBar = binding.progressBar;
Display display = getActivity().getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
float density = getResources().getDisplayMetrics().density;
float dpWidth = outMetrics.widthPixels / density;
int columns = Math.round(dpWidth/133);
GridLayoutManager mLayoutManager = new GridLayoutManager(getActivity(),columns);
moviesRecycerView.setLayoutManager(mLayoutManager);
PopularAdapter popularAdapter = new PopularAdapter(getActivity(),popular_posters,
popular_title, popular_id, popular_categories, popular_votes_pos, popular_votes_neg,
popular_last_episode);
new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
if(AppActivity.isPopularCategoryLoaded) {
moviesRecycerView.setAdapter(popularAdapter);
progressBar.setVisibility(View.GONE);
cancel();
}
}
public void onFinish() {
}
}.start();
moviesRecycerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int totalItemCount = mLayoutManager.getItemCount();
int lastVisible = mLayoutManager.findLastVisibleItemPosition();
boolean endHasBeenReached = lastVisible + 15 >= totalItemCount;
isPopularOnTop = dy == 0;
if (totalItemCount > 0 && endHasBeenReached) {
if(AppActivity.popularHasNextPage) {
AppActivity.popularPage += 1;
AppActivity.loadPopularCategory();
new CountDownTimer(5000, 1000) {
public void onTick(long millisUntilFinished) {
if(AppActivity.isPopularCategoryLoaded) {
progressBar.setVisibility(View.GONE);
popularAdapter.notifyDataSetChanged();
}
}
public void onFinish() {
}
}.start();
AppActivity.popularHasNextPage = false;
}
}
}
});
return root;
}
}
My adapter.java:
package org.vitaliy.moziapp.PopularFragment;
public class PopularAdapter extends RecyclerView.Adapter<PopularViewHolder> {
static public String current_id;
static public String current_category;
ArrayList<String> movies_posters;
ArrayList<String> movies_title;
ArrayList<String> movies_id;
ArrayList<String> movies_categories;
ArrayList<String> movies_votes_pos;
ArrayList<String> movies_votes_neg;
ArrayList<String> movies_last_episode;
LayoutInflater inflater;
Context context;
public PopularAdapter(Context context, ArrayList<String> movies_posters,
ArrayList<String> movies_title,
ArrayList<String> movies_id,
ArrayList<String> movies_categories,
ArrayList<String> movies_votes_pos,
ArrayList<String> movies_votes_neg,
ArrayList<String> movies_last_episode){
this.movies_posters = movies_posters;
this.movies_title = movies_title;
this.movies_id = movies_id;
this.movies_categories = movies_categories;
this.movies_votes_pos = movies_votes_pos;
this.movies_votes_neg = movies_votes_neg;
this.movies_last_episode = movies_last_episode;
this.context = context;
this.inflater = LayoutInflater.from(context);
}
#NonNull
#Override
public PopularViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.item_movie, parent, false);
return new PopularViewHolder(view);
}
#SuppressLint({"SetTextI18n", "NotifyDataSetChanged"})
#Override
public void onBindViewHolder(#NonNull PopularViewHolder holder, #SuppressLint("RecyclerView") int position) {
if(movies_categories.get(position).equals("s7")||
movies_categories.get(position).equals("s93")) {
holder.movie_last_episode.setVisibility(View.VISIBLE);
holder.movie_last_episode.setText(movies_last_episode.get(position));
} else {
holder.movie_last_episode.setVisibility(View.GONE);
}
Picasso.with(context).load(movies_posters.get(position))
.into(holder.movie_poster, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
holder.movie_icon.setVisibility(View.VISIBLE);
}
});
holder.movie_title.setText(Html.fromHtml(movies_title.get(position)));
holder.movie_btn.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean b) {
holder.movie_title.setSelected(b);
}
});
holder.movie_votes_pos.setText(movies_votes_pos.get(position));
holder.movie_votes_neg.setText(movies_votes_neg.get(position));
holder.movie_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
current_id = movies_id.get(position);
current_category = movies_categories.get(position);
AppActivity.current_id = current_id;
MovieVideosFragment.category = current_category;
VideosAdapter.category = current_category;
if (current_category.equals("s7") || current_category.equals("s93"))
AppActivity.loadSeriesAudio(current_id);
else
AppActivity.loadMoviesAudio(current_id);
AppActivity.isMoviesLoaded = false;
AppActivity.isSeriesLoaded = false;
MovieFragment.year = null;
MovieFragment.actors = null;
MovieFragment.genres = null;
MovieFragment.countries = null;
MovieFragment.short_story = null;
AppActivity.loadMovieDescription(current_id);
AppActivity.loadSimilar(current_id);
MovieFragment.poster = movies_posters.get(position);
MovieFragment.title = movies_title.get(position);
context.startActivity(new Intent(context, MovieTab.class));
}
});
}
#Override
public int getItemCount() {
return movies_posters.size();
}
}
Related
I have an issue with Recyclerview item selection , which is set up in a fragment , the problem is each page which is created by ViewVager has its own instance of the Recyclerview so the output is that selecting Recyclerview items will reset the scroll state of the Recyclerview, so I'm looking for a solution to to save scroll state of a Recyclerview when an item is clicked.
Fragment onViewCreated
// setting RecyclerView
mEpisodesList = (CustomRecyclerView) view.findViewById(R.id.episodesLIST);
// getting episodeslist
ArrayList<PlanetModel> episodeslist = new ArrayList<>();
for (TvShowEpisode e : mEpisodes) {
episodeslist.add(new PlanetModel(e.mEpisode));
}
// Setting LinearLayoutManager
LinearLayoutManager layoutManager
= new LinearLayoutManager(mContext.getApplicationContext(), LinearLayoutManager.HORIZONTAL, false);
//mEpisodesList.setLayoutManager(new LinearLayoutManager(mContext));
mEpisodesList.setLayoutManager(layoutManager);
// Setting RecyclerView Adapter
int currentPosition = getArguments().getInt("position");
planetAdapter = new PlanetAdapter(episodeslist, currentPosition, new PlanetAdapter.OnItemClickListener() {
#Override
public void onItemClick(final int pos) {
int scrollValue = mEpisodesList.getHorizontalScrollOffset();
mCallback.sendText(pos, scrollValue);
}
});
mEpisodesList.setAdapter(planetAdapter);
int scrollValue = getArguments().getInt("scrollValue");
new Handler().postDelayed(() -> mEpisodesList.scrollBy(scrollValue, 0), 100);
activity
public class TvShowEpisodeDetails extends MizActivity implements TvShowEpisodeDetailsFragment.TextClicked {
#Override
protected int getLayoutResource() {
return R.layout.viewpager_with_toolbar_overlay;
}
#Override
public void onCreate(Bundle savedInstanceState) {
mBus = MizuuApplication.getBus();
super.onCreate(savedInstanceState);
// Set theme
setTheme(R.style.Mizuu_Theme_NoBackground);
ViewUtils.setupWindowFlagsForStatusbarOverlay(getWindow(), true);
ViewUtils.setProperToolbarSize(this, mToolbar);
mShowId = getIntent().getExtras().getString(SHOW_ID);
mSeason = getIntent().getExtras().getInt("season");
mEpisode = getIntent().getExtras().getInt("episode");
mDatabaseHelper = MizuuApplication.getTvEpisodeDbAdapter();
Cursor cursor = mDatabaseHelper.getEpisodes(mShowId);
try {
while (cursor.moveToNext()) {
mEpisodes.add(new TvShowEpisode(this, mShowId,
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_TITLE)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_PLOT)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_SEASON)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_AIRDATE)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_DIRECTOR)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_WRITER)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_GUESTSTARS)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_RATING)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_HAS_WATCHED)),
cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_FAVOURITE))
));
}
} catch (Exception e) {
} finally {
cursor.close();
}
final ArrayList<PlanetModel> episodeslist = new ArrayList<>();
for (TvShowEpisode e : mEpisodes) {
episodeslist.add(new PlanetModel(e.mEpisode));
}
mShowTitle = MizuuApplication.getTvDbAdapter().getShowTitle(mShowId);
setTitle(mShowTitle);
mViewPager = (ViewPager) findViewById(R.id.awesomepager);
mViewPager.setAdapter(new TvShowEpisodeDetailsAdapter(getSupportFragmentManager()));
for (int i = 0; i < mEpisodes.size(); i++)
fragments.add(TvShowEpisodeDetailsFragment
.newInstance(mShowId, Integer.parseInt(mEpisodes.get(i).getSeason()), Integer.parseInt(mEpisodes.get(i).getEpisode()), i, mScrollValue));
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
for (int i = 0; i < episodeslist.size(); i++) {
episodeslist.get(i).setPlanetSelected(false);
}
episodeslist.get(position).setPlanetSelected(true);
//notify your recycler views adaper
ViewUtils.updateToolbarBackground(TvShowEpisodeDetails.this, mToolbar, 0, mEpisodes.get(position).getTitle(), Color.TRANSPARENT);
}
});
if (savedInstanceState != null) {
mViewPager.setCurrentItem(savedInstanceState.getInt("tab", 0));
} else {
for (int i = 0; i < mEpisodes.size(); i++) {
if (mEpisodes.get(i).getSeason().equals(MizLib.addIndexZero(mSeason)) && mEpisodes.get(i).getEpisode().equals(MizLib.addIndexZero(mEpisode))) {
mViewPager.setCurrentItem(i);
SharedPreferences setPref = this.getSharedPreferences("TvShowEpisodeDetails", Context.MODE_PRIVATE);
setPref.edit().putInt("i", i).apply();
break;
}
}
}
}
private class TvShowEpisodeDetailsAdapter extends FragmentPagerAdapter {
public TvShowEpisodeDetailsAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
// return TvShowEpisodeDetailsFragment.newInstance(mShowId, Integer.parseInt(mEpisodes.get(index).getSeason()), Integer.parseInt(mEpisodes.get(index).getEpisode()));
return fragments.get(index);
}
#Override
public int getCount() {
return mEpisodes.size();
}
}
Recyclerview adapter
public class PlanetAdapter extends RecyclerView.Adapter<PlanetAdapter.PlanetViewHolder> {
public interface OnItemClickListener {
void onItemClick(int item);
}
private final ArrayList<PlanetModel> episodeslist;
private final OnItemClickListener listener;
SharedPreferences getPref = getContext().getSharedPreferences("TvShowEpisodeDetails", Context.MODE_PRIVATE);
int pos = getPref.getInt("i", 0);
int isPlanetSelected = pos;
private final int highlightedPos;
public PlanetAdapter(ArrayList<PlanetModel> episodeslist, int highlightedPosition, OnItemClickListener listener) {
this.episodeslist = episodeslist;
this.listener = listener;
this.highlightedPos = highlightedPosition;
}
#NonNull
#Override
public PlanetAdapter.PlanetViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.planet_row, parent, false);
return new PlanetViewHolder(v);
}
#Override
public void onBindViewHolder(PlanetAdapter.PlanetViewHolder vh, final int position) {
TextView tv = (TextView) vh.itemView;
PlanetModel planetModel = episodeslist.get(position);
tv.setText(planetModel.getPlanetName());
tv.setCompoundDrawablesWithIntrinsicBounds(R.drawable.bg, 0, 0, 0);
if (highlightedPos == position) {
vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryLight));
} else {
vh.itemView.setBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryDark));
}
//holder.image.setImageResource(R.drawable.planetimage);
//vh.text.setText(episodeslist.get(position).toString());
}
#Override
public int getItemCount() {
return episodeslist.size();
}
public class PlanetViewHolder extends RecyclerView.ViewHolder {
protected TextView text;
public PlanetViewHolder(View itemView) {
super(itemView);
text = (TextView) itemView.findViewById(R.id.text_id);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("LOG_TAG", "onClick: current item: " + highlightedPos);
final int previousItem = isPlanetSelected;
isPlanetSelected = getPosition();
SharedPreferences setPref = v.getContext().getSharedPreferences("PlanetAdapter", Context.MODE_PRIVATE);
setPref.edit().putInt("newPosition", getPosition()).apply();
listener.onItemClick(getPosition());
}
});
}
// public void bind(final PlanetModel item, final OnItemClickListener listener) {
// }
}
You can solve this by tracking the current scroll value of the RecyclerView, and whenever you hit an a ReyclerView item; add a new parameter to the listener callback with this tracked scroll value to update the new fragment that will be shown on the ViewPager.
Track the scroll value:
mEpisodesList.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
scrollValue += dx;
}
});
Pass it as interface callback:
planetAdapter = new PlanetAdapter(episodeslist, currentPosition, new PlanetAdapter.OnItemClickListener() {
#Override
public void onItemClick(final int pos) {
mCallback.sendText(pos, scrollValue);
}
});
And update that in the list of ViewPager fragments before scrolling to the new page:
#Override
public void sendText(int position, int scrollValue) {
mScrollValue = scrollValue;
TvShowEpisodeDetailsFragment frag = fragments.get(position);
Bundle arguments = frag.getArguments();
arguments.putInt("scrollValue", scrollValue);
mViewPager.setCurrentItem(position, false);
}
try this
// save
recyclerViewState = binding.mainList.layoutManager?.onSaveInstanceState()
// restore
recyclerViewState?.let {
binding.mainList.layoutManager?.onRestoreInstanceState(it)
}
I down know if made it right. I have a RecyclerView with 2 ViewHolders. ProgramHolder and CountDownTimerHolder. In the CountDownTimerHolder is the time where the countdown starts predifined.
If you click on the Settings Button, I start a new Activity where I set Minutes and Seconds for the Timer.
My question is: Can I pass the data that I get from the Activity to change the predifined starting time in the CountDownTimerHolder?
Sry but I am still a noob at Programming. If there are any questions let me know.
CountDownTimerHolder
public class CountdownTimerHolder extends RecyclerView.ViewHolder {
private static final String TAG = "CountdownTimerHolder";
Context context;
private TextView mTextViewCountdown;
private Button btnStartPauseTimer, btnStopTimer, btnSetTimerSettings;
private CountDownTimer countDownTimer;
private boolean timerRunning;
//THIS ARE THE VARIABLES TO BE UPDATED
public long START_TIME_IN_MILLI_SEC = 1000000;
private long timeLeftInMilliSec = START_TIME_IN_MILLI_SEC;
public CountdownTimerHolder(#NonNull View itemView) {
super(itemView);
Log.d(TAG, "CountdownTimerHolder: IT IS CALLED");
context = itemView.getContext();
mTextViewCountdown = itemView.findViewById(R.id.timer);
btnStartPauseTimer = itemView.findViewById(R.id.playBtn);
btnStopTimer = itemView.findViewById(R.id.stopBtn);
btnSetTimerSettings = itemView.findViewById(R.id.btnSetTimerSettings);
btnStartPauseTimer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (timerRunning) {
pauseTimer();
}else {
startTimer();
}
}
});
btnStopTimer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
resetTimer();
}
});
btnSetTimerSettings.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, SettingCountdownTimer.class);
context.startActivity(intent);
}
});
updateCountDownText();
}
private void startTimer() {
countDownTimer = new CountDownTimer(timeLeftInMilliSec, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timeLeftInMilliSec = millisUntilFinished;
updateCountDownText();
}
#Override
public void onFinish() {
timerRunning = false;
btnStartPauseTimer.setBackgroundResource(R.drawable.ic_play_arrow_black_24dp);
}
}.start();
timerRunning = true;
btnStartPauseTimer.setBackgroundResource(R.drawable.ic_pause_black_24dp);
}
private void pauseTimer() {
countDownTimer.cancel();
timerRunning = false;
btnStartPauseTimer.setBackgroundResource(R.drawable.ic_play_arrow_black_24dp);
}
private void resetTimer() {
countDownTimer.cancel();
timeLeftInMilliSec = START_TIME_IN_MILLI_SEC;
updateCountDownText();
btnStartPauseTimer.setBackgroundResource(R.drawable.ic_play_arrow_black_24dp);
}
private void updateCountDownText() {
int minutes = (int) (timeLeftInMilliSec / 1000) /60;
int seconds = (int) (timeLeftInMilliSec /1000) % 60;
String timeLeftFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
mTextViewCountdown.setText(timeLeftFormatted);
}
}
SettingCountdownTimerActivity
public class SettingCountdownTimer extends AppCompatActivity {
EditText editTextMinutes, editTextSeconds;
Button btnSetTimer;
public long minutesToMillisInput;
public long secondsToMillisInput;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.countdown_timer_settings);
editTextMinutes = findViewById(R.id.editTextMinutes);
editTextSeconds = findViewById(R.id.editTextSeconds);
btnSetTimer = findViewById(R.id.btnSetTimer);
btnSetTimer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String inputMinutes = editTextMinutes.getText().toString();
String inputSeconds = editTextSeconds.getText().toString();
if (inputMinutes.length() == 0 && inputSeconds.length() == 0) {
Toast.makeText(SettingCountdownTimer.this, "Minuten und Sekunden koennen nicht leer sein",
Toast.LENGTH_SHORT).show();
return;
}
minutesToMillisInput = Long.parseLong(inputMinutes) * 60000;
secondsToMillisInput = Long.parseLong(inputSeconds) * 1000;
if (minutesToMillisInput == 0 && secondsToMillisInput == 0) {
Toast.makeText(SettingCountdownTimer.this, "Minuten und Sekunden koennen nicht 0 sein",
Toast.LENGTH_SHORT).show();
return;
}
//HERE I WANT TO PASS THE NEW VARIABLES TO VIEWHOLDER
finish();
}
});
}
}
Adapter
public class PickedExercisesAdapter extends RecyclerView.Adapter {
OnItemClickListener mlistener;
private static final String TAG = "PickedExercisesRecycler started";
private ArrayList<ExerciseModel> mlist;
private static int EXERCISE_CARD_TYPE = 0;
private static int COUNTDOWN_TIMER_TYPE = 1;
public PickedExercisesAdapter(ArrayList<ExerciseModel> list) {
this.mlist = list;
}
#Override
public int getItemViewType(int position) {
if (position % 2 == 0) {
return EXERCISE_CARD_TYPE;
}
return COUNTDOWN_TIMER_TYPE;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view;
if (viewType == EXERCISE_CARD_TYPE) {
view = layoutInflater.inflate(R.layout.exercise_card_view, parent, false);
return new ProgramHolder(view);
} else {
view = layoutInflater.inflate(R.layout.countdown_timer, parent, false);
return new CountdownTimerHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
ExerciseModel exerciseModel = null;
if (position % 2 == EXERCISE_CARD_TYPE) {
if (position == 0) {
exerciseModel = mlist.get(0);
} else {
int listposition = position / 2;
exerciseModel = mlist.get(listposition);
}
ProgramHolder programHolder = (ProgramHolder) holder;
Glide.with(programHolder.itemView.getContext())
.load(exerciseModel.getExerciseImage())
.placeholder(R.drawable.ic_launcher_foreground)
.into(programHolder.exerciseImage);
programHolder.exerciseTitle.setText(exerciseModel.getExerciseTitle());
programHolder.exerciseTitle.setText(exerciseModel.getExerciseTitle());
programHolder.exerciseBodyPart.setText(exerciseModel.getExerciseBodyPart());
programHolder.exerciseDifficulty.setText(String.valueOf(exerciseModel.getDifficulty()));
programHolder.exerciseDescription.setText(exerciseModel.getExerciseDescription());
} else {
CountdownTimerHolder countDownTimerHolder = (CountdownTimerHolder) holder;
}
}
#Override
public int getItemCount() {
int listsizedouble = mlist.size() * 2;
return listsizedouble;
}
class ProgramHolder extends RecyclerView.ViewHolder {
OnItemClickListener mlistener;
TextView exerciseTitle, exerciseDifficulty, exerciseBodyPart, exerciseDescription;
ConstraintLayout expandableLayout;
Button arrowBtn;
ImageView exerciseImage;
CardView cardView;
public ProgramHolder(final View itemView) {
super(itemView);
arrowBtn = itemView.findViewById(R.id.arrowBtn);
expandableLayout = itemView.findViewById(R.id.constraintExpendable);
exerciseTitle = itemView.findViewById(R.id.exerciseTitle);
exerciseDifficulty = itemView.findViewById(R.id.exerciseDifficulty);
exerciseBodyPart = itemView.findViewById(R.id.exerciseBodyPart);
exerciseImage = itemView.findViewById(R.id.exerciseImage);
exerciseDescription = itemView.findViewById(R.id.exerciseDescription);
cardView = itemView.findViewById(R.id.cardView);
arrowBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION && mlistener != null) {
mlistener.onItemClick(position);
}
}
});
}
private void setExerciseDetails(ExerciseModel exerciseModel) {
exerciseTitle.setText(exerciseModel.getExerciseTitle());
}
}
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.mlistener = listener;
}
}
RecyclerViewFragment
public class PickedExerciseRecyclerViewFragment extends Fragment {
private static final String TAG = "PickedExerciseRecyclerV";
RecyclerView recyclerView;
PickedExercisesAdapter adapter;
RecyclerView.LayoutManager manager;
View view;
private ArrayList<ExerciseModel> list;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.picked_exercise_recycler_view, container, false);
list = getArguments().getParcelableArrayList("exerciseProgram");
recyclerView = view.findViewById(R.id.pickedExerciseRecyclerView);
manager = new LinearLayoutManager(getContext());
adapter = new PickedExercisesAdapter(list);
recyclerView.setLayoutManager(manager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(new PickedExercisesAdapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
Log.d(TAG, "onItemClick: clicked " + position);
View view1 = recyclerView.getLayoutManager().findViewByPosition(position);
ConstraintLayout constraintLayout = view1.findViewById(R.id.constraintExpendable);
Button arrowBtn = view1.findViewById(R.id.arrowBtn);
CardView cardView = view1.findViewById(R.id.cardView);
if (constraintLayout.getVisibility() == View.GONE) {
cardView.getMaxCardElevation();
TransitionManager.beginDelayedTransition(cardView, new AutoTransition());
constraintLayout.setVisibility(View.VISIBLE);
arrowBtn.setBackgroundResource(R.drawable.ic_keyboard_arrow_up_black_24dp);
} else {
TransitionManager.beginDelayedTransition(cardView, new AutoTransition());
constraintLayout.setVisibility(View.GONE);
arrowBtn.setBackgroundResource(R.drawable.ic_keyboard_arrow_down_black_24dp);
}
}
});
return view;
}
}
I am creating a movie app using TMDB api, Retrofit, Gson and Glide. I have two recyclerView and two layout to inflate. But I am unable to inflate 2 layout in recyclerView adapter.
I have already implemented popular and upcoming movie list in 2 different recyclerView. But they are showing using 1 single layout. I want to inflate popular movies in one layout and upcoming movies in another layout. I can't set the condition for getItemViewType() method. How can I check for popular and upcoming movies list in getItemViewType() method and implement it on onCreateViewHolder() method of recyclerView.
MovieAdapter class:
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MovieViewHolder> {
private Context context;
private ArrayList<Movie> movieArrayList;
public MovieAdapter(Context context, ArrayList<Movie> movieArrayList) {
this.context = context;
this.movieArrayList = movieArrayList;
}
#NonNull
#Override
public MovieViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_list_item, parent, false);
return new MovieViewHolder(view);
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
#Override
// Set values to the list item components
public void onBindViewHolder(#NonNull MovieViewHolder holder, int position) {
holder.movieTitle.setText(movieArrayList.get(position).getOriginalTitle());
holder.rating.setText(String.valueOf(movieArrayList.get(position).getVoteAverage()));
String imagePath = "https://image.tmdb.org/t/p/w500" + movieArrayList.get(position).getPosterPath();
Glide.with(context)
.load(imagePath)
.placeholder(R.drawable.loading)
.into(holder.movieImage);
}
#Override
public int getItemCount() {
return movieArrayList == null ? 0 : movieArrayList.size();
}
public class MovieViewHolder extends RecyclerView.ViewHolder {
TextView movieTitle, rating;
ImageView movieImage;
public MovieViewHolder(#NonNull View itemView) {
super(itemView);
movieImage = itemView.findViewById(R.id.ivMovieImage);
movieTitle = itemView.findViewById(R.id.tvTitle);
rating = itemView.findViewById(R.id.tvRating);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
Movie selectedMovie = movieArrayList.get(position);
Intent intent = new Intent(context, MovieActivity.class);
intent.putExtra("movie", selectedMovie);
context.startActivity(intent);
}
}
});
}
}
}
MainActivity class:
public class MainActivity extends AppCompatActivity {
private ArrayList<Movie> popularMovie, topRatedMovie;
private RecyclerView recyclerViewPopular, recyclerViewUpcoming;
private MovieAdapter movieAdapter, upcomingAdapter;
private SwipeRefreshLayout swipeRefreshLayout;
private static ViewPager mPager;
private static int currentPage = 0;
private static int NUM_PAGES = 0;
String[] urls = new String[] {
"https://image.tmdb.org/t/p/w500/udDclJoHjfjb8Ekgsd4FDteOkCU.jpg",
"https://image.tmdb.org/t/p/w500//2bXbqYdUdNVa8VIWXVfclP2ICtT.jpg",
"https://image.tmdb.org/t/p/w500//zfE0R94v1E8cuKAerbskfD3VfUt.jpg",
"https://image.tmdb.org/t/p/w500//lcq8dVxeeOqHvvgcte707K0KVx5.jpg",
"https://image.tmdb.org/t/p/w500//w9kR8qbmQ01HwnvK4alvnQ2ca0L.jpg"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initSlider();
getPopularMovies();
getUpcomingMovies();
swipeRefreshLayout = findViewById(R.id.swipe_layout);
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimaryDark);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
getPopularMovies();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
swipeRefreshLayout.setRefreshing(false);
}
}, 4000);
}
});
}
public void getPopularMovies() {
MovieDataService movieDataService = RetrofitInstance.getService();
Call<MovieDBResponse> callPopular = movieDataService.getPopularMovies(this.getString(R.string.apiKey));
callPopular.enqueue(new Callback<MovieDBResponse>() {
#Override
public void onResponse(Call<MovieDBResponse> call, Response<MovieDBResponse> response) {
MovieDBResponse movieDBResponse = response.body();
if(movieDBResponse!=null && movieDBResponse.getMovies()!=null) {
popularMovie = (ArrayList<Movie>) movieDBResponse.getMovies();
showOnRecyclerView();
}
}
#Override
public void onFailure(Call<MovieDBResponse> call, Throwable t) { }
});
}
public void getUpcomingMovies() {
MovieDataService movieDataService = RetrofitInstance.getService();
Call<MovieDBResponse> callUpcoming = movieDataService.getUpcomingMovies(this.getString(R.string.apiKey));
callUpcoming.enqueue(new Callback<MovieDBResponse>() {
#Override
public void onResponse(Call<MovieDBResponse> call, Response<MovieDBResponse> response) {
MovieDBResponse movieDBResponse = response.body();
if(movieDBResponse!=null && movieDBResponse.getMovies()!=null) {
topRatedMovie = (ArrayList<Movie>) movieDBResponse.getMovies();
showOnRecyclerView();
}
}
#Override
public void onFailure(Call<MovieDBResponse> call, Throwable t) { }
});
}
private void showOnRecyclerView() {
recyclerViewPopular = findViewById(R.id.rvMovies);
recyclerViewUpcoming = findViewById(R.id.rvTopMovies);
RecyclerView.LayoutManager popularLayoutManager = new LinearLayoutManager(this);
RecyclerView.LayoutManager upcomingLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerViewUpcoming.setLayoutManager(upcomingLayoutManager);
recyclerViewPopular.setLayoutManager(popularLayoutManager);
movieAdapter = new MovieAdapter(this, popularMovie);
upcomingAdapter = new MovieAdapter(this, topRatedMovie);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
recyclerViewPopular.setLayoutManager(new GridLayoutManager(this, 2));
}else {
recyclerViewPopular.setLayoutManager(new GridLayoutManager(this, 4));
}
recyclerViewPopular.setItemAnimator(new DefaultItemAnimator());
recyclerViewUpcoming.setItemAnimator(new DefaultItemAnimator());
recyclerViewPopular.setAdapter(movieAdapter);
recyclerViewUpcoming.setAdapter(upcomingAdapter);
movieAdapter.notifyDataSetChanged();
upcomingAdapter.notifyDataSetChanged();
}
}
I want to inflate 2 different layout "movie_list_item.xml" and "upcoming_movie_list_item.xml" in onCreateViewHolder() method.
With in your adapter class(MovieAdapter) create a new constructor and add extra params of Int or enum whatever simple for you i am just giving you simple example:-
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MovieViewHolder> {
private Context context;
private ArrayList<Movie> movieArrayList;
private int viewType;
public MovieAdapter(Context context, ArrayList < Movie > movieArrayList, int viewType) {
this.context = context;
this.movieArrayList = movieArrayList;
this.viewType=viewType;
}
#NonNull
#Override
public MovieViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view;
if (viewType == 1) {
//Popular movie layout
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_list_item, parent, false);
} else {
//upcoming movie layout
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_list_item, parent, false);
}
return new MovieViewHolder(view);
}
#Override
public int getItemViewType(int position) {
if (viewType == 1)
return 1; //Popular Movie Layout
else
return 2; //Upcoming Movie Layout
// return super.getItemViewType(position);
}
#Override
// Set values to the list item components
public void onBindViewHolder(#NonNull MovieViewHolder holder, int position) {
holder.movieTitle.setText(movieArrayList.get(position).getOriginalTitle());
holder.rating.setText(String.valueOf(movieArrayList.get(position).getVoteAverage()));
String imagePath = "https://image.tmdb.org/t/p/w500" + movieArrayList.get(position).getPosterPath();
Glide.with(context)
.load(imagePath)
.placeholder(R.drawable.loading)
.into(holder.movieImage);
}
#Override
public int getItemCount() {
return movieArrayList == null ? 0 : movieArrayList.size();
}
public class MovieViewHolder extends RecyclerView.ViewHolder {
TextView movieTitle, rating;
ImageView movieImage;
public MovieViewHolder(#NonNull View itemView) {
super(itemView);
movieImage = itemView.findViewById(R.id.ivMovieImage);
movieTitle = itemView.findViewById(R.id.tvTitle);
rating = itemView.findViewById(R.id.tvRating);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
Movie selectedMovie = movieArrayList.get(position);
Intent intent = new Intent(context, MovieActivity.class);
intent.putExtra("movie", selectedMovie);
context.startActivity(intent);
}
}
});
}
}
and within your activity change on this method only
private void showOnRecyclerView() {
recyclerViewPopular = findViewById(R.id.rvMovies);
recyclerViewUpcoming = findViewById(R.id.rvTopMovies);
RecyclerView.LayoutManager popularLayoutManager = new LinearLayoutManager(this);
RecyclerView.LayoutManager upcomingLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerViewUpcoming.setLayoutManager(upcomingLayoutManager);
recyclerViewPopular.setLayoutManager(popularLayoutManager);
movieAdapter = new MovieAdapter(this, popularMovie,1);
upcomingAdapter = new MovieAdapter(this, topRatedMovie,2);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
recyclerViewPopular.setLayoutManager(new GridLayoutManager(this, 2));
} else {
recyclerViewPopular.setLayoutManager(new GridLayoutManager(this, 4));
}
recyclerViewPopular.setItemAnimator(new DefaultItemAnimator());
recyclerViewUpcoming.setItemAnimator(new DefaultItemAnimator());
recyclerViewPopular.setAdapter(movieAdapter);
recyclerViewUpcoming.setAdapter(upcomingAdapter);
movieAdapter.notifyDataSetChanged();
upcomingAdapter.notifyDataSetChanged();
}
Create layout for movie_empty_item
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MovieViewHolder> {
private Context context;
private ArrayList<Movie> movieArrayList;
//add this two line
private static final int EMPTY_VIEW_TYPE = 0;
private static final int NORMAL_VIEW_TYPE = 1;
public MovieAdapter(Context context, ArrayList<Movie> movieArrayList) {
this.context = context;
this.movieArrayList = movieArrayList;
}
#NonNull
#Override
public MovieViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//return viewholder replace like this
if(viewType == NORMAL_VIEW_TYPE) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_list_item, parent, false);
return new MovieViewHolder(view);
}else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_empty_item, parent, false);
return new EmptyViewHolder(view);
};
}
//getItemViewType return replace like this
#Override
public int getItemViewType(int position) {
return movieArrayList.size()>0?NORMAL_VIEW_TYPE:EMPTY_VIEW_TYPE;
}
#Override
// Set values to the list item components
public void onBindViewHolder(#NonNull MovieViewHolder holder, int position) {
holder.movieTitle.setText(movieArrayList.get(position).getOriginalTitle());
holder.rating.setText(String.valueOf(movieArrayList.get(position).getVoteAverage()));
String imagePath = "https://image.tmdb.org/t/p/w500" + movieArrayList.get(position).getPosterPath();
Glide.with(context)
.load(imagePath)
.placeholder(R.drawable.loading)
.into(holder.movieImage);
}
#Override
public int getItemCount() {
return movieArrayList.size() ? movieArrayList.size():1 ;
}
public class MovieViewHolder extends RecyclerView.ViewHolder {
TextView movieTitle, rating;
ImageView movieImage;
public MovieViewHolder(#NonNull View itemView) {
super(itemView);
movieImage = itemView.findViewById(R.id.ivMovieImage);
movieTitle = itemView.findViewById(R.id.tvTitle);
rating = itemView.findViewById(R.id.tvRating);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
Movie selectedMovie = movieArrayList.get(position);
Intent intent = new Intent(context, MovieActivity.class);
intent.putExtra("movie", selectedMovie);
context.startActivity(intent);
}
}
});
}
}
public class EmptyViewHolder extends RecyclerView.ViewHolder {
public EmptyViewHolder(#NonNull View itemView) {
super(itemView);
}
}
}
When back to previous activity or I get out the app is closed and show this error:
E/RecyclerView: No adapter attached; skipping layout
Within a asycntask in his method onPostExecute I declare a recycleview and RecyclerView.LayoutManager but no have idea what it's wrong. I need your help to solve this problem. Below is my code:
#Override
public void onPostExecute(List<Modules> result) {
if (pDialog.isShowing()){
RecyclerView.LayoutManager Manager =new LinearLayoutManager(DepartureModule.this);
RecyclerView.Adapter adapter = new ModuleAdapter(result);
RecyclerView RVODetails = (RecyclerView) findViewById(R.id.RVODetails);
RVODetails.setLayoutManager(Manager);
RVODetails.setAdapter(adapter);
pDialog.dismiss();
}
and this is my adapter class:
public class ModuleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ItemClickListener itemClickListener;
public final ImageButton Actions;
public final ImageView Image;
public final TextView ModuleCode;
public final TextView ModuleDescription;
public final TextView ModuleDate;
public String ModuleIds;
public ModuleViewHolder(View itemView) {
super(itemView);
Image = (ImageView)itemView.findViewById(R.id.logo);
Actions = (ImageButton)itemView.findViewById(R.id.Actions);
//TitleModuleCode = (TextView)itemView.findViewById(R.id.TitleModuleCode);
ModuleCode = (TextView)itemView.findViewById(R.id.ModuleCode);
//TitleModuleDescription = (TextView)itemView.findViewById(R.id.TitleModuleDescription);
ModuleDescription = (TextView)itemView.findViewById(R.id.ModuleDescription);
ModuleDate = (TextView)itemView.findViewById(R.id.ModuleDate);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
this.itemClickListener.OnItemClick(view,getLayoutPosition());
// Toast.makeText(view.getContext(), "POS" + getLayoutPosition()
// , Toast.LENGTH_LONG).show();
}
public void setItemClickListener(ItemClickListener ItemClick){
this.itemClickListener = ItemClick;
}
}
public ModuleAdapter(List<Modules> Items){
this.Items = Items;
}
#Override
public int getItemCount() {
return Items.size();
}
#Override
public ModuleViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.layout_cardview,viewGroup,false);
return new ModuleViewHolder(view);
}
#Override
public void onBindViewHolder(final ModuleViewHolder ViewHolder, final int position) {
context = ViewHolder.itemView.getContext();
Typeface typeface = Typeface.createFromAsset(context.getAssets(),
"fonts/CaviarDreams.ttf");
ViewHolder.Image.setImageResource(Items.get(position).getImages());
ViewHolder.Actions.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ShowPopupMenu(ViewHolder.Actions,position,ViewHolder);
}
});
ViewHolder.ModuleCode.setText(Items.get(position).getModule());
ViewHolder.ModuleCode.setTypeface(typeface); ViewHolder.ModuleDescription.setText(Items.get(position).getDescription());
ViewHolder.ModuleDescription.setTypeface(typeface);
ViewHolder.ModuleDate.setText(Items.get(position).getDate());
ViewHolder.ModuleDate.setTypeface(typeface);
ViewHolder.ModuleIds = Items.get(position).getModuleIds();
ViewHolder.setItemClickListener(new ItemClickListener() {
#Override
public void OnItemClick(View view, int Pos) {
//Toast.makeText(context, "POSITION :" + Pos, Toast.LENGTH_SHORT).show();
}
});
}
private void ShowPopupMenu (final View view, final int position,final ModuleViewHolder holder){
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
case R.id.action_modify:
final Connection connectionupdate = new Connection(context,Connection.DATABASE_NAME,null,
Connection.DATABASE_VERSION);
final SQLiteDatabase dbUpdate = connectionupdate.getWritableDatabase();
Typeface typeface = Typeface.createFromAsset(context.getAssets(),"fonts/CaviarDreams.ttf");
AlertDialog.Builder ModifyModule = new AlertDialog.Builder(context);
LayoutInflater modifyinflater = (LayoutInflater)context.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
final View viewmodify = modifyinflater.inflate(R.layout.layout_custom_dialog_create_modules,null);
TILM = (TextInputLayout)viewmodify.findViewById(R.id.TILM);
TILM.setTypeface(typeface);
TILD = (TextInputLayout)viewmodify.findViewById(R.id.TILD);
TILD.setTypeface(typeface);
ModuleCodeE = (EditText)viewmodify.findViewById(R.id.ModuleCode);
ModuleCodeE.setTypeface(typeface);
ModuleDescE = (EditText)viewmodify.findViewById(R.id.ModuleDesc);
ModuleDescE.setTypeface(typeface);
ModuleCodeE.setText(Items.get(position).getModule());
ModuleDescE.setText(Items.get(position).getDescription());
final String Id = Items.get(position).getModuleIds();
ModifyModule.setView(viewmodify);
ModifyModule.setIcon(R.drawable.logomini);
ModifyModule.setTitle("Construmuebles FM");
ModifyModule.setMessage(" Modifica los valores en los siguientes campos :");
ModifyModule.setPositiveButton("Actualizar", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialogInterface, int i) {
ContentValues VUpdate = new ContentValues();
VUpdate.put(Database.CamposModuloDetails.KEY_MODULE_CODE,ModuleCodeE.getText().toString()); VUpdate.put(Database.CamposModuloDetails.KEY_MODULE_DESC,ModuleDescE.getText().toString());
long IdUpdate = dbUpdate.update(Database.MODULE_DETAILS_TABLE,VUpdate,Database.CamposModuloDetails
.KEY_MODULE_DETAILS_ID + " = ?",new String []{Id});
new UpdateCardView(context,IdUpdate).execute();
dialogInterface.dismiss();
}
});
ModifyModule.setNegativeButton("Cancelar", new DialogInterface
.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
ModifyModule.show();
return true;
case R.id.action_delete:
new DeleteCardView(context,holder,position).execute();
return true;
}
return false;
}
});
menu.show();
}
class DeleteCardView extends AsyncTask<Void,Void,Long>{
private ProgressDialog pDialog;
ModuleViewHolder holder;
int position;
public DeleteCardView(Context context,ModuleViewHolder holder,int position) {
pDialog = new ProgressDialog(context);
this.holder = holder;
this.position = position;
}
#Override
protected void onPreExecute() {
pDialog.setMessage(" Eliminado registro...");
pDialog.show();
}
#Override
protected Long doInBackground(Void... voids) {
String ModuleIdCardView = holder.ModuleIds;
Connection connection = new Connection(context, Connection.DATABASE_NAME, null,
Connection.DATABASE_VERSION);
long i = connection.DeleteByIdCardView(ModuleIdCardView);
if (i != 0) {
return i;
} else {
return i;
}
}
#Override
protected void onPostExecute(Long Result) {
if (pDialog.isShowing()){
pDialog.dismiss();
Items.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position,Items.size());
if (Items.size()==0){ /**viewPager.setCurrentItem(0);**/ }
}
}
}
}
Rearrange your code as follows
recyclerView = (RecyclerView) findViewById(R.id.RVODetails);
mAdapter = new ModuleAdapter(result);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
}
I took this tutorial as reference.
Despite of checking everything, no data is appearing on screen ie. main_activity. I've already referred to other pages on stackoverflow regarding this issue. Can't find a viable solution.
NOTE: There is no warning or error while I deploy app on the device.
This is the source code.
MainActivity.java:
public class MainActivity extends Activity
{
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new MyRecyclerViewAdapter(getDataSet());
mRecyclerView.setAdapter(mAdapter);
RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, LinearLayoutManager.VERTICAL);
mRecyclerView.addItemDecoration(itemDecoration);
// Code to Add an item with default animation
DataObject obj = new DataObject("red", "foo");
((MyRecyclerViewAdapter) mAdapter).addItem(obj, 0);
// Code to remove an item with default animation
//((MyRecyclerViewAdapter) mAdapter).deleteItem(index);
}
#Override
protected void onResume() {
super.onResume();
((MyRecyclerViewAdapter) mAdapter).setOnItemClickListener(new MyRecyclerViewAdapter.MyClickListener()
{
#Override
public void onItemClick(int position, View v) {
Toast.makeText(MainActivity.this, "Clicked item: " + position, Toast.LENGTH_SHORT).show();
}
});
}
private ArrayList<DataObject> getDataSet() {
ArrayList results = new ArrayList<DataObject>();
for (int index = 0; index < 20; index++){
DataObject obj = new DataObject("Some Primary Text " + index, "Secondary " + index);
results.add(index, obj);
}
return results;
}
}
DataObject.java:
public class DataObject {
private String mText1;
private String mText2;
DataObject (String text1, String text2){
mText1 = text1;
mText2 = text2;
}
public String getmText1() {
return mText1;
}
public void setmText1(String mText1) {
this.mText1 = mText1;
}
public String getmText2() {
return mText2;
}
public void setmText2(String mText2) {
this.mText2 = mText2;
}
}
MyRecyclerViewAdapter.java:
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.DataObjectHolder>
{
private static String LOG_TAG = "MyRecyclerViewAdapter";
private ArrayList<DataObject> mDataset;
private static MyClickListener myClickListener;
public static class DataObjectHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
TextView label;
TextView dateTime;
public DataObjectHolder(View itemView)
{
super(itemView);
label = (TextView) itemView.findViewById(R.id.textView);
dateTime = (TextView) itemView.findViewById(R.id.textView2);
Log.i(LOG_TAG, "Adding Listener");
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
myClickListener.onItemClick(getPosition(), v);
}
}
public void setOnItemClickListener(MyClickListener myClickListener) {
this.myClickListener = myClickListener;
}
public MyRecyclerViewAdapter(ArrayList<DataObject> myDataset) {
mDataset = myDataset;
}
#Override
public DataObjectHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item, parent, false);
DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
return dataObjectHolder;
}
#Override
public void onBindViewHolder(DataObjectHolder holder, int position) {
holder.label.setText(mDataset.get(position).getmText1());
holder.dateTime.setText(mDataset.get(position).getmText2());
}
public void addItem(DataObject dataObj, int index) {
mDataset.add(dataObj);
notifyItemInserted(index);
}
public void deleteItem(int index) {
mDataset.remove(index);
notifyItemRemoved(index);
}
#Override
public int getItemCount()
{
return mDataset.size();
}
public interface MyClickListener {
public void onItemClick(int position, View v);
}
}
DividerIconDecoration.java
public class DividerItemDecoration extends RecyclerView.ItemDecoration{
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
#Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
#Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</RelativeLayout>
</ScrollView>
recyclerview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingTop="5dp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:text="Small Text"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
The problem is in activity_main.xml. You should remove ScrollView and it will work (There's no reason to have one since the recyclerview has an implicit one). There is no scrollview in the tutorial either: check activity_recycler_view.xml.