I am beginner in Android.
This is My Java file. I just want to show data is recycler view, but when i open it on emulator my app crashes.Help me to find out the fault in my code.
private RecyclerView rview;
private MyAdapter adapter;
private ArrayList<Student> list;
private DatabaseReference reference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_check_record);
reference = FirebaseDatabase.getInstance().getReference("Student");
rview = findViewById(R.id.recyclerview);
list = new ArrayList<>();
rview.setHasFixedSize(true);
rview.setLayoutManager(new LinearLayoutManager(this));
rview.addItemDecoration(new DividerItemDecoration(rview.getContext(),
DividerItemDecoration.VERTICAL));
adapter = new MyAdapter(this, list);
rview.setAdapter(adapter);
reference.addListenerForSingleValueEvent(listener);
}
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
list.clear();
for (DataSnapshot snapshot:dataSnapshot.getChildren()){
Student s =dataSnapshot.getValue(Student.class);
list.add(s);
}
adapter.notifyDataSetChanged();
}
else {
Toast.makeText(CheckRecordActivity.this, "No Record Found", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(CheckRecordActivity.this, databaseError.toString(), Toast.LENGTH_SHORT).show();
}
};
}
Set recyclerview manager on this way:-
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
rv.setLayoutManager(layoutManager);
You have to check 4 things,
you have to not initialize your firebase instance on your Application class like(FirebaseApp.initializeApp(this))
Check DatabaseReference refrence is null or not
DataSnapshot value is return or not
Check array value is null or not
if there four value is null,so app can be crash.
Related
I have a list which is coming from an API which I'm storing in db. Now I'm fetching list from db and showing it in recyclerview. Then removing all data one-by-one from recyclerview listing. This process is being repeated every 10 seconds using JobScheduler. While I'm scrolling, I'm getting this error. I've tried many solutions given in various SO posts like this but it didn't worked.
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionMessageViewHolder{c2276c4 position=31 id=-1, oldPos=-1, pLpos:-1 no parent} androidx.recyclerview.widget.RecyclerView{5223262 VFED..... .F...... 0,0-720,1120 #7f0900d4 app:id/recycler}, adapter:com.sam.testapp.MessageAdapter#4b57ff3, layout:androidx.recyclerview.widget.LinearLayoutManager#735b4b0, context:com.sam.testapp.MainActivity#e780e56
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MessageViewHolder> {
private List<Message> messageList;
public MessageAdapter(List<Message> messageList) {
this.messageList = messageList;
}
protected static class MessageViewHolder extends RecyclerView.ViewHolder {
private ConstraintLayout root;
private TextView umfiTXT, msgTXT;
MessageViewHolder(View view) {
super(view);
root = view.findViewById(R.id.root);
umfiTXT = view.findViewById(R.id.umfiTXT);
msgTXT = view.findViewById(R.id.msgTXT);
}
}
#NonNull
#Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MessageViewHolder((LayoutInflater.from(parent.getContext())).inflate(R.layout.row_msg_list, parent, false));
}
#Override
public void onBindViewHolder(#NonNull MessageViewHolder holder, int position) {
try {
holder.umfiTXT.setText("UMFI: " + messageList.get(position).getMessageUMFI());
holder.msgTXT.setText("Message: " + messageList.get(position).getMessageTxt());
}catch(Exception e) {
e.printStackTrace();
}
}
#Override
public int getItemCount() {
try {
if(messageList.isEmpty())
return 0;
else
return messageList.size();
}catch(Exception e) {
return 0;
}
}
private void clearData() {
this.messageList.clear();
notifyDataSetChanged();
}
public void setData(List<Message> data) {
clearData();
this.messageList.addAll(data);
notifyDataSetChanged();
}
}
public class MainActivity extends AppCompatActivity {
private ArrayList<Message> messageList;
private RecyclerView recycler;
private AppCompatTextView emptyTxt;
private MessageAdapter messageAdapter;
private SqliteDatabase database;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
messageList = new ArrayList<>();
recycler = findViewById(R.id.recycler);
emptyTxt = findViewById(R.id.emptyTxt);
database = new SqliteDatabase(MainActivity.this);
recycler.setLayoutManager(new LinearLayoutManager(this));
messageAdapter = new MessageAdapter(messageList);
recycler.setAdapter(messageAdapter);
recycler.setItemAnimator(null);
RxBus.subscribe((Consumer<Object>) o -> {
if (o instanceof RxEvent) {
RxEvent data = (RxEvent) o;
System.out.println("SAM: status: " + data.getStatus());
if (data.getStatus() == 1) {
fetchMessageList();
}
}
});
}
private void fetchMessageList(){
messageList.clear();
AndroidNetworking.get(Util.url)
.setPriority(Priority.IMMEDIATE)
.build()
.getAsJSONArray(new JSONArrayRequestListener() {
#Override
public void onResponse(JSONArray jsonArray) {
try{
System.out.println("SAM: fetchMessageList jsonArray: "+jsonArray);
ArrayList<Message> templist = new ArrayList<>();
for(int i=0; i<jsonArray.length(); i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
templist.add(new Message(jsonObject.getString("umfi"), jsonObject.getString("msg_to"), jsonObject.getString("msg_text")));
}
storeListinDB(templist);
}catch(Exception e){
e.printStackTrace();
}
}
#Override
public void onError(ANError error) {
System.out.println("SAM: fetchMessageList onError: "+error.getErrorBody());
}
});
}
private void storeListinDB(ArrayList<Message> templist){
database.insertArrayData(templist);
showList();
}
private void showList(){
try{
//recycler.getRecycledViewPool().clear();
if(messageList.size()>0){
emptyTxt.setVisibility(View.GONE);
messageAdapter.notifyDataSetChanged();
}else{
emptyTxt.setVisibility(View.VISIBLE);
ArrayList<Message> templist = new ArrayList<>();
templist = database.fetchMessageList();
messageAdapter.setData(templist);
System.out.println("SAM: templist size: "+templist.size());
}
System.out.println("SAM: messageList size: "+messageList.size());
//removeAll();
}catch(Exception e){
e.printStackTrace();
}
}
}
You pass your messageList to the adapter, so the messageList in the adapter and in the activity are the same object references. Then, as I understand, somehow method fetchMessageList is called, it's where the problem appears. You call .clear() on your list and start an asynchronous operation to fetch a new list, to then synchronously post it to your adapter.
The thing is, after you have cleared your list, your adapter keeps the reference to an empty list now, without being notified about the changes. The adapter still "thinks" that your list is the same size as it was before, so when you scroll the RecyclerView, it tries to call at least onBindViewHolder for new appearing items. But, as the list is empty, it throws IndexOutOfBoundsException.
You could try to notify the adapter about the changes immediately after calling messageList.clear(), but it seems to me that just deleting this clearing will solve the problem.
private void fetchMessageList(){
//messageList.clear(); <- delete this
AndroidNetworking.get(Util.url)
...
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
im new in android programing and i want to add JSON to my recyclerview i was getting the adapter not attetched skiping layout but my CustomAdapter is giving me NullPointerException too.
my CustomAdapter
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {
private List<RetroProduct> dataList;
private Context context;
CustomAdapter(Context context, List< RetroProduct > dataList){
this.context = context;
this.dataList = dataList;
}
class CustomViewHolder extends RecyclerView.ViewHolder {
final View mView;
TextView goodsId,categoryTitle,number,title1,title2;
CustomViewHolder(View itemView) {
super(itemView);
mView = itemView;
goodsId = mView.findViewById(R.id.tv_goodsId);
categoryTitle = mView.findViewById(R.id.tv_categoryTitle);
number = mView.findViewById(R.id.tv_number);
title1 = mView.findViewById(R.id.tv_title1);
title2 = mView.findViewById(R.id.tv_title2);
}
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.item_row, parent, false);
return new CustomViewHolder(view);
}
#Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
holder.goodsId.setText(dataList.get(position).getGoodsId());
holder.categoryTitle.setText(dataList.get(position).getCategoryTitle());
holder.title1.setText(dataList.get(position).getTitle1());
holder.title2.setText(dataList.get(position).getTitle2());
holder.number.setText(dataList.get(position).getNumber());
}
#Override
public int getItemCount() {
return dataList.size();
}
}
and im getting NullPointerException on
return dataList.size();
what should i do now? give it value or i dont know.
MainActivity
public class MainActivity extends AppCompatActivity {
private CustomAdapter adapter;
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GetDataService service =
RetrofitClientInstance.getRetrofitInstance()
.create(GetDataService.class);
Call< List<RetroProduct> > call = service.getAllProducts();
call.enqueue(new Callback<List<RetroProduct>>() {
#Override
public void onResponse(Call<List<RetroProduct>> call,
Response<List<RetroProduct>> response) {
generateDataList(response.body());
LinearLayoutManager manager = new
LinearLayoutManager(MainActivity.this);
recyclerView.setLayoutManager(manager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<List<RetroProduct>> call, Throwable t)
{
Toast.makeText(MainActivity.this, "null",
Toast.LENGTH_SHORT).show();
}
});
}
private void generateDataList(List<RetroProduct> productList) {
recyclerView = findViewById(R.id.recycler_view);
adapter = new CustomAdapter(this,productList);
}
}
#Override
public int getItemCount() {
if(dataList!=null)
return dataList.size();
else
return 0;
}
Add a null check before calling size() method of a Arraylist as above
I am creating simple image gallery app in which images are shown on MainActivity inside RecyclerView and on click of Any Image it will take us to SlideActivity in which I want to show images on ViewPager and then we swipe all images should be shown on ViewPager. For retrieving images i am using Glide. Images Load on RecyclerView Perfectly Fine but when i click on any Image i get this Exception "java.lang.ArrayIndexOutOfBoundsException: length=15; index=-1".
I know there are many same questions like this I saw all codes but did not understood so finally decided to ask question I am pasting code whatever i tried till now. Any Suggestion or advice will be helpful bcz I work alone I have no Mentor and I am Learning. Thank you!
Error :
java.lang.ArrayIndexOutOfBoundsException: length=15; index=-1
at java.util.ArrayList.get(ArrayList.java:439)
at com.starmoonsolutions.imagegallery.RecycleViewAdapter$ViewHolder$1.onClick(RecycleViewAdapter.java:63)
at android.view.View.performClick(View.java:6256)
at android.view.View$PerformClick.run(View.java:24697)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
ImageUrl.java
public class ImageUrl {
String imageUrl;
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
RecyclerView recyclerView;
GridLayoutManager gridLayoutManager;
ArrayList<ImageUrl> imageUrlList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
recyclerView = findViewById(R.id.recyclerView);
gridLayoutManager = new GridLayoutManager(getApplicationContext(), 2);
recyclerView.setLayoutManager(gridLayoutManager);
imageUrlList = prepareData();
RecycleViewAdapter galleryAdapter = new RecycleViewAdapter(getApplicationContext(), imageUrlList);
recyclerView.setAdapter(galleryAdapter);
}
private ArrayList prepareData(){
// here you should give your image URLs and that can be a link from the Internet
String imageUrls[] = {
"https://images.pexels.com/photos/358457/pexels-photo-358457.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
"https://images.pexels.com/photos/934964/pexels-photo-934964.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/1202887/pexels-photo-1202887.jpeg?auto=compress&cs=tinysrgb&h=650&w=940",
"https://images.pexels.com/photos/337909/pexels-photo-337909.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/894443/pexels-photo-894443.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/951325/pexels-photo-951325.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/1534411/pexels-photo-1534411.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/266436/pexels-photo-266436.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/1894350/pexels-photo-1894350.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/87009/earth-soil-creep-moon-lunar-surface-87009.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/1820563/pexels-photo-1820563.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/1274260/pexels-photo-1274260.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
};
imageUrlList = new ArrayList<>();
for (int i = 0; i < imageUrls.length; i++) {
ImageUrl imageUrl = new ImageUrl();
imageUrl.setImageUrl(imageUrls[i]);
imageUrlList.add(imageUrl);
}
Log.d("MainActivity", "List count: " + imageUrlList.size());
return imageUrlList;
}
}
RecyclerViewAdapter:
public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.ViewHolder>{
private ArrayList<ImageUrl> imageUrls;
private Context context;
public RecycleViewAdapter(Context context, ArrayList<ImageUrl> imageUrls) {
this.imageUrls = imageUrls;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.image_layout, viewGroup, false);
return new ViewHolder(view);
}
/**
* gets the image url from adapter and passes to Glide API to load the image
*
* #param viewHolder
* #param i
*/
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
Glide.with(context).load(imageUrls.get(i).getImageUrl()).into(viewHolder.img);
}
#Override
public int getItemCount() {
return imageUrls.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
RecyclerView recyclerView;
ImageView img;
public ViewHolder(#NonNull final View itemView) {
super(itemView);
img = itemView.findViewById(R.id.imageView);
recyclerView = itemView.findViewById(R.id.recyclerView);
final int pos = getAdapterPosition();
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, SlideActivity.class);
error point here-> intent.putExtra("image", String.valueOf(imageUrls.get(pos).getImageUrl())); <- error point here
intent.putExtra("position", pos);
intent.putExtra("list", imageUrls.get(pos).imageUrl);
context.startActivity(intent);
}
});
}
}
}
SlideActivity(ViewPager):
public class SlideActivity extends AppCompatActivity {
private ViewPager viewPager;
private Context context = SlideActivity.this;
private ViewPagerAdapter adapter;
private ArrayList<String> list;
String image;
private int position;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slide_activity);
viewPager = findViewById(R.id.viewPager);
getIntentInfo();
adapter = new ViewPagerAdapter(list,context);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem((position));
}
private void getIntentInfo() {
image = getIntent().getStringExtra("image");
list = getIntent().getStringArrayListExtra("list");
position = getIntent().getIntExtra("position",0);
}
}
ViewPagerAdapter:
public class ViewPagerAdapter extends PagerAdapter {
private ArrayList<String> imageUrls;
private android.content.Context context;
private LayoutInflater inflater;
private ImageView wallpaper;
public ViewPagerAdapter() {
}
public ViewPagerAdapter(ArrayList<String> imageUrls, android.content.Context context) {
this.imageUrls = imageUrls;
this.context = context;
}
#Override
public int getCount() {
return imageUrls.size();
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object o) {
return view.equals(o);
}
#NonNull
#Override
public Object instantiateItem(#NonNull final ViewGroup container, final int position) {
inflater = LayoutInflater.from(container.getContext());
View view = inflater.inflate(R.layout.pager_item, container, false);
wallpaper = view.findViewById(R.id.walpaperImage);
Glide.with(context).asBitmap().load(imageUrls.get(position)).into(wallpaper);
container.addView(view, 0);
return view;
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
container.removeView((View) object);
}
}
The problem is actually in getting the adapter position.
public ViewHolder(#NonNull final View itemView) {
super(itemView);
img = itemView.findViewById(R.id.imageView);
recyclerView = itemView.findViewById(R.id.recyclerView);
// remove the below line
//final int pos = getAdapterPosition();
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, SlideActivity.class);
// you need to freshly get the adapter position here.
int pos = getAdapterPosition();
error point here-> intent.putExtra("image", String.valueOf(imageUrls.get(pos).getImageUrl())); <- error point here
intent.putExtra("position", pos);
intent.putExtra("list", imageUrls.get(pos).imageUrl);
context.startActivity(intent);
}
});
}
Since ViewHolder gets recycled, adapter position can change therefore you need to get the latest adapter position inside your click listener.
And regarding the Bundle data, pass the list of URLs of 'String' type instead of the custom object,
public void onClick(View v) {
Intent intent = new Intent(context, SlideActivity.class);
error point here-> intent.putExtra("image", String.valueOf(imageUrls.get(pos).getImageUrl())); <- error point here
intent.putExtra("position", pos);
// imageUrls is of type ArrayList<String>
intent.putStringArrayListExtra("list", imageUrls);
context.startActivity(intent); }
or else use the Parcelable library to serialize the custom object.
I've found only a few articles related to this issue on StackOverflow tried all of their solutions in various combinations but can't get the RecyclerView to display my RecyclerView.Adapter that is populated with data which a I can verify and see the list in debug mode but it simply won't show the information.
My code (I struggled to paste the XML Layout files):
public class RecipeDetailActivity extends AppCompatActivity {
private RecipeModel mRecipe;
private ArrayList<IngredientModel> mIngredientList = new ArrayList<>();
private IngredientListAdapter ingredientListAdapter;
private RecyclerView rvIngredientList;
private boolean mTwoPane;
private ListView listView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recipe_detail);
rvIngredientList = (RecyclerView)findViewById(R.id.rv_ingredient_list);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rvIngredientList.setLayoutManager(layoutManager);
SampleRecycler sampleRecycler = new SampleRecycler(); // empty RecyclerView.Adapter
rvIngredientList.setAdapter(sampleRecycler);
mRecipe = getIntent().getParcelableExtra("com.wernerraubenheimer.bakingapp.data.RecipeModel");
mIngredientList = mRecipe.getIngredients();
ingredientListAdapter = new IngredientListAdapter(mIngredientList);
ingredientListAdapter.notifyDataSetChanged();
// Up until this point the RecyclerVie.Adapter is populated with data - debug mode I can see the list
rvIngredientList.swapAdapter(ingredientListAdapter, false);
}
}
public class IngredientListAdapter extends RecyclerView.Adapter<IngredientListAdapter.IngredientViewHolder> {
private ArrayList<IngredientModel> mIngredientList;
private Context mContext;
private boolean mTwoPane;
public IngredientListAdapter(ArrayList<IngredientModel> ingredientList) {
mIngredientList = ingredientList;
}
#Override
public IngredientViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mContext = parent.getContext();
int layoutIdForListItem = R.layout.ingredient_list_item;
LayoutInflater inflater = LayoutInflater.from(mContext);
boolean attachImmediatelyToParent = false;
View view = inflater.inflate(layoutIdForListItem, parent, attachImmediatelyToParent);
IngredientViewHolder viewHolder = new IngredientViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(IngredientViewHolder holder, int position) {
IngredientModel ingredient = mIngredientList.get(position);
holder.bind(mContext, ingredient);
}
#Override
public int getItemCount() {
if (mIngredientList != null) {
return 0;
} else {
return mIngredientList.size();
}
}
static class IngredientViewHolder extends RecyclerView.ViewHolder {
private CardView cardviewContainer;
private TextView tvIngredientName;
private TextView tvIngredientQuantity;
private TextView tvIngredientMeasure;
private Context mContext;
private IngredientModel mIngredient;
IngredientViewHolder(View itemView) {
super(itemView);
//cardviewContainer = (CardView)itemView.findViewById(R.id.card_view_ingredient);
tvIngredientName = (TextView)itemView.findViewById(R.id.text_view_ingredient_name);
tvIngredientQuantity =(TextView)itemView.findViewById(R.id.text_view_quantity);
tvIngredientMeasure = (TextView)itemView.findViewById(R.id.text_view_measure);
}
void bind(Context context, IngredientModel ingredientModel) {
mContext = context;
mIngredient = ingredientModel;
tvIngredientName.setText(mIngredient.getIngredient());
tvIngredientQuantity.setText(mIngredient.getQuantity());
tvIngredientMeasure.setText(mIngredient.getMeasure());
}
}
}
Although, it is difficult to decipher from the code you have pasted,
it looks like the problem is with the following function:
#Override
public int getItemCount() {
if (mIngredientList != null) {
return 0;
} else {
return mIngredientList.size();
}
}
Changing condition to if (mIngredientList == null) { should solve the problem.
Also, in the RecipeDetailActivity.onCreate() method, only following code should be enough to display the list:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recipe_detail);
rvIngredientList = (RecyclerView) findViewById(R.id.rv_ingredient_list);
rvIngredientList.setLayoutManager(new LinearLayoutManager(this));
mRecipe = getIntent().getParcelableExtra("com.wernerraubenheimer.bakingapp.data.RecipeModel");
mIngredientList = mRecipe.getIngredients();
ingredientListAdapter = new IngredientListAdapter(mIngredientList);
rvIngredientList.setAdapter(ingredientListAdapter);
}
I have a simple fragment which retrieve data from Firebase database.
I use firebase recycler view to display retrieving data. And after scrolling or screen rotation I can't force recycler view (or linear layout manager) restore scroll position.
I found here some answers but they don't work.
My code is:
public class NewsListFragment extends ParentNewsFragment {
static int color_naval, color_black;
private boolean mProcessLikes = false;
private DatabaseReference mDatabaseLikes;
private DatabaseReference mDatabaseViews;
private FirebaseAuth mAuth;
private int position = 0;
public static NewsListFragment getInstance() {
return new NewsListFragment();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDatabaseReference = FirebaseDatabase.getInstance().getReference()
.child("App_news");
mDatabaseLikes = FirebaseDatabase.getInstance().getReference().child("news_likes");
mDatabaseViews = FirebaseDatabase.getInstance().getReference().child("news_views");
mAuth = FirebaseAuth.getInstance();
mQuery = mDatabaseReference.orderByChild("pos").startAt("100");
color_naval = getResources().getColor(R.color.colorPrimary);
color_black = getResources().getColor(R.color.colorBlack);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.rv_choose, container, false);
rv = (RecyclerView) rootView.findViewById(R.id.rv_choose);
lm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(lm);
rv.setHasFixedSize(true);
return rootView;
}
#Override
public void onPause() {
super.onPause();
position = lm.findFirstVisibleItemPosition();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("position", position);
}
#Override
public void onViewStateRestored(#Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if(savedInstanceState != null) {
position = savedInstanceState.getInt("position");
}
}
#Override
public void onResume() {
super.onResume();
if (position != 0) {
lm.scrollToPosition(position);
showToast(position+"");
}
}
#Override
public void onStart() {
super.onStart();
FirebaseRecyclerAdapter<NewsList, NewsListViewHolder> adapter =
new FirebaseRecyclerAdapter<NewsList, NewsListViewHolder>(
NewsList.class,
R.layout.frag_newslist_card_view,
NewsListViewHolder.class,
mQuery
) {
#Override
protected void populateViewHolder(NewsListViewHolder viewHolder, final NewsList model, int position) {
final String post_key = getRef(position).getKey();
viewHolder.setDate(model.getDate()+",");
viewHolder.setTime(model.getTime());
viewHolder.setTitle(model.getTitle());
viewHolder.setImage(getContext(), model.getImage());
viewHolder.setEye(model.getCode());
viewHolder.setThumb(post_key);
viewHolder.thumb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mProcessLikes = true;
mDatabaseLikes.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (mProcessLikes){
if (dataSnapshot.child(post_key).hasChild(mAuth.getCurrentUser().getUid())){
mDatabaseLikes.child(post_key).child(mAuth.getCurrentUser().getUid())
.removeValue();
mProcessLikes = false;
}
else {
mDatabaseLikes.child(post_key).child(mAuth.getCurrentUser().getUid())
.setValue("like");
mProcessLikes = false;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
viewHolder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mDatabaseViews.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.child(post_key).hasChild(mAuth.getCurrentUser().getUid())) {
mDatabaseViews.child(post_key).child(mAuth.getCurrentUser().getUid())
.setValue("view");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mChooserListener.chooseNews(model.getCode());
}
});
}
};
rv.setAdapter(adapter);
}
public static class NewsListViewHolder extends RecyclerView.ViewHolder {
//some text here
}
}
method showToast in the end shows real number of position but recyclerview starts from the beginning.
any ideas?
Make sure you are not reloading data from the server or wherever you are retrieving data.
Add is not null check in your fragment's onCreateView or activity's onCreate like:
if(savedInstanceState != null){
...
}else{
loadData();
}
Replace your linear layout manager with something similar to the following. I have used this implementation many times when using RecyclerView in fragments. Let me know how it goes
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
yourItem.setLayoutManager(mLayoutManager);