I am displaying comments on a post using a recycler adapter. The code is set to scroll the recycler view to the bottom when the edit text is clicked, and when a new comment is posted by the current user.
If the keyboard is shown and the recycler view still does not touches the keyboard (there is like 2 to 4 comments displayed), the app crashes when the comment is posted. If there are many items (enough to go under the keyboard), the recyclerview scrolls and nothing crashes.
This is my code:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// some code
scrollToBottom = true; // this is initially false
loadComments();
}
});
private void loadComments () {
Query query = firebaseFirestore.collection...;
FirestoreRecyclerOptions<Model> options = new FirestoreRecyclerOptions.Builder<Model>()
.setLifecycleOwner(this)
.setQuery(query, Model.class)
.build();
adapter = new Adapter(options, this);
recyclerview.setHasFixedSize(true);
recyclerview.setLayoutManager(new LinearLayoutManager(this));
recyclerview.setAdapter(adapter);
if (scrollToBottom) {
scrollToBottom = false;
scrollToTheBottom();
}
}
private void scrollToTheBottom() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
recyclerview.smoothScrollToPosition(adapter.getItemCount());
}
}, 600);
}
Adapter code:
public class Adapter extends FirestoreRecyclerAdapter<Model, Adapter.ViewHolder> {
Context context;
TimeAgo timeAgo;
public Adapter(#NonNull FirestoreRecyclerOptions<Model> options, Context context) {
super(options);
this.context = context;
}
#Override
protected void onBindViewHolder(#NonNull final ViewHolder holder, int position, #NonNull Model model) {
final String userID = model.getUser_id();
String image = model.getImage();
String username = model.getUsername();
String comment = model.getComment();
Timestamp commentTimeAgo = model.getTimestamp();
String timestampString = String.valueOf(commentTimeAgo);
String[] noOpeningParentheses = timestampString.split("\\(");
String[] noClosingParentheses = noOpeningParentheses[1].split("\\)");
String[] noCommaAndSpace = noClosingParentheses[0].split(", ");
String[] secondsFromTimestamp = noCommaAndSpace[0].split("seconds=");
String[] nanosecondsFromTimestamp = noCommaAndSpace[1].split("nanoseconds=");
long millis = TimeUnit.SECONDS.toMillis(Long.parseLong(secondsFromTimestamp[1])) + TimeUnit.NANOSECONDS.toMillis(Long.parseLong(nanosecondsFromTimestamp[1]));
// Applying
if (image.equals("default")) {
holder.userImage.setImageResource(R.mipmap.no_image);
} else {
Glide.with(context).load(image).into(holder.userImage);
}
holder.userUsername.setText(username);
holder.comment.setText(String.valueOf(comment));
holder.commentTimeAgo.setText(timeAgo.getTimeAgo(context, millis));
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem, parent, false);
context = parent.getContext();
timeAgo = new TimeAgo();
return new ViewHolder(view);
}
public class ViewHolder extends RecyclerView.ViewHolder {
CircleImageView userImage;
TextView userUsername, comment, commentTimeAgo;
public ViewHolder(#NonNull View itemView) {
super(itemView);
userImage = itemView.findViewById(R.id.userimage);
userUsername = itemView.findViewById(R.id.userUsername);
comment = itemView.findViewById(R.id.comment);
commentTimeAgo = itemView.findViewById(R.id.timeago);
}
}
}
When viewing the logcat, I get an error on the 3rd line:
String timestampString = String.valueOf(timestamp);
String[] noOpeningParentheses = timestampString.split("\\(");
String[] noClosingParentheses = noOpeningParentheses[1].split("\\)"); // error here
String[] noCommaAndSpace = noClosingParentheses[0].split(", ");
String[] secondsFromTimestamp = noCommaAndSpace[0].split("seconds=");
String[] nanosecondsFromTimestamp = noCommaAndSpace[1].split("nanoseconds=");
long millis = TimeUnit.SECONDS.toMillis(Long.parseLong(secondsFromTimestamp[1])) + TimeUnit.NANOSECONDS.toMillis(Long.parseLong(nanosecondsFromTimestamp[1]));
This is a code that I wrote for converting a firebase firestore timestamp field to milliseconds.
What I'm getting in logcat is something like java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
I do not know how to solve this. Any help please?
Replace:
recyclerview.smoothScrollToPosition(adapter.getItemCount());
with:
int lastIndex = adapter.getItemCount()-1;
if(lastIndex!=-1)
{recyclerview.smoothScrollToPosition(lastIndex);}
Related
I am designing a live quiz app that fetches data from server and question are displayed in a RecyclerView that contains a question and four options. Now when I select one option for a given question, it is selected properly but at the same time, the corresponding option for other question is selected automatically.
Screenshot of the item selection issue is the following.
I have designed Data Model Class and RecylerView Adapter (with the help of #Reaz Murshed) but have been stuck with the code
My Data Model Class is :
//DmLiveQuiz
public class DmLiveQuiz {
String testId;
int questionId;
String question;
String optA;
String optB;
String optC;
String optD;
String answer;
String explain;
...
}
My Adapter Class is //LiveTestAdapter
public class LiveTestAdapter extends RecyclerView.Adapter<LiveTestAdapter.CustomViewHolder> {
private List<DmLiveQuiz> questionList;
private int[] answerList; // Get a list of your answers here.
private DmLiveQuiz questionsList;
private Context context;
public List<Integer> myResponse = new ArrayList<Integer>();
public int qno;
public LiveTestAdapter(List<DmLiveQuiz> questionList, Context context) {
this.questionList = questionList;
this.context = context;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.live_quiz_display_format, parent, false);
return new CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull final CustomViewHolder holder, int position) {
questionsList = questionList.get(holder.getAdapterPosition());
holder.tvQNo.setText(questionsList.getQuestionId() + "");
holder.tvquestion.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
holder.tvquestion.setText(questionsList.getQuestion());
holder.optA.setText(questionsList.getOptA());
holder.optB.setText(questionsList.getOptB());
holder.optC.setText(questionsList.getOptC());
holder.optD.setText(questionsList.getOptD());
// Now you need to modify the backgrounds of your option buttons like the following.
if (answerList[position] == 1) holder.optA.setBackgroundResource(R.drawable.button_border);
else holder.optA.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 2) holder.optB.setBackgroundResource(R.drawable.button_border);
else holder.optB.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 3) holder.optC.setBackgroundResource(R.drawable.button_border);
else holder.optC.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 4) holder.optD.setBackgroundResource(R.drawable.button_border);
else holder.optD.setBackgroundResource(R.drawable.button_question_style);
holder.optA.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optA.setBackgroundResource(R.drawable.button_border);
answerList[position] = 1; // Selected first option which is A
});
holder.optB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optB.setBackgroundResource(R.drawable.button_border);
answerList[position] = 2; // Selected second option which is B
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.optC.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optC.setBackgroundResource(R.drawable.button_border);
answerList[position] = 3; // Selected third option which is C
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.optD.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optD.setBackgroundResource(R.drawable.button_border);
answerList[position] = 4; // Selected fourth option which is D
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.tvClear.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
holder.optA.setBackgroundResource(R.drawable.button_question_style);
holder.optB.setBackgroundResource(R.drawable.button_question_style);
holder.optC.setBackgroundResource(R.drawable.button_question_style);
holder.optD.setBackgroundResource(R.drawable.button_question_style);
answerList[position] = 0; // Clear the value in the answerList
}
});
}
// Use this function to set the question list in the adapter
public void setQuestionList(List<DmLiveQuiz> questionList) {
this.questionList = questionList;
this.answerList = new int[questionList.size()]; // This initializes the answer list having the same size as the question list
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return questionList.size();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
TextView tvquestion, tvClear, tvQNo;
Button optA, optB, optC, optD;
public CustomViewHolder(View itemView) {
super(itemView);
tvQNo = (TextView) itemView.findViewById(R.id.tvLiveQuizQuestionNo);
tvquestion = (TextView) itemView.findViewById(R.id.tvLiveQuizQuestion);
optA = (Button) itemView.findViewById(R.id.buttonOptionA);
...///
}
}
}
And The Activity where Recyclerview is implemented is
recyclerView = (RecyclerView) findViewById(R.id.recyclerViewLiveTest);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
quizList = new ArrayList<>();
adapter = new LiveTestAdapter(quizList, getApplicationContext());
linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
// recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setAdapter(adapter);
getData();
......
The method for fetching JSON data is getdata() as given below which fetches data from server correctly...
private void getData() {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(quiz_url, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
for (int i = 0; i < response.length(); i++) {
try {
JSONObject jsonObject = response.getJSONObject(i);
DmLiveQuiz liveQuiz = new DmLiveQuiz();
...
...
quizList.add(liveQuiz);
} catch (JSONException e) {
e.printStackTrace();
progressDialog.dismiss();
}
}
adapter.notifyDataSetChanged();
..........
}
Now When I run App, it shows index=0 i.e. ArrayOutOfIndexException is generated.. I am not able to call public void setQuestionList(List<DmLiveQuiz> questionList) method of LiveQuizAdapter class from my activity.. Please Help
Initially you are setting empty list in the adapter. After getting value from JsonArrayRequest then need to update adapter using new list.
Update onBindViewHolder:
#Override
public void onBindViewHolder(#NonNull final CustomViewHolder holder, int position) {
DmLiveQuiz dmLiveQuiz= questionList.get(position);
if(dmLiveQuiz!=null){
// do whatever you want. put all code here.}
}
Update your adapter:
#Override
public void onResponse(JSONArray response) {
for (int i = 0; i < response.length(); i++) {
// put all code here
quizList.add(liveQuiz);}
adapter.setQuestionList(quizList);
adapter.notifyDataSetChanged();
}
you have to add a boolean value in DmLiveQuiz model class :-
boolean isSelected ;
and then set a check in your adapter while your are showing the answer is selected or not :-
if(DmLiveQuiz.isSelectd){
// this is the selected answer
}else {
// in case don't selected
}
and change the boolean value on adapter item Click
I have created an app that keeps track of course information. At the moment the only field that Changing dynamically is the modcode, the rest of the fields are all hardcoded to input the number 1, for now.
This is the insert code:
public boolean insertData(String ModCode,String ModDesc,int UniID,int FacID,int EduID,int NoOfTest,int NoOfAss,int NoOfPrac,int NoOfExam)
{
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(Col_2,ModCode);
contentValues.put(Col_3,ModDesc);
contentValues.put(Col_4,UniID);
contentValues.put(Col_5,FacID);
contentValues.put(Col_6,EduID);
contentValues.put(Col_7,NoOfTest);
contentValues.put(Col_8,NoOfAss);
contentValues.put(Col_9,NoOfPrac);
contentValues.put(Col_10,NoOfExam);
long result = db.insert(Table_Name, null, contentValues);
if(result==-1)
return false;
else
return true;
}
and the front end side of insert:
db = new DatabaseHelper(this);
textModCode = (EditText)findViewById(R.id.textModCode);
button_add = (Button)findViewById(R.id.button_add);
AddData();
The button press:
public void AddData(){
button_add.setOnClickListener(
new View.OnClickListener(){
#Override
public void onClick(View v){
boolean isInserted = db.insertData(textModCode.getText().toString(),"1",1,1,1,1,1,1,1);
if(isInserted=true)
Toast.makeText(MainActivity.this,"Data in",Toast.LENGTH_LONG).show();
else
Toast.makeText(MainActivity.this,"Sorry",Toast.LENGTH_LONG).show();
refresh();
}
}
);
}
Refresh:
public void refresh()
{
Cursor res = db.getAllData();
moduleList = new ArrayList<>();
if (res != null ) {
if (res.moveToFirst()) {
do {
Module m = new Module(res.getInt(res.getColumnIndex("ModID")),res.getInt(res.getColumnIndex("NoOfTest")),res.getInt(res.getColumnIndex("NoOfAss")),res.getInt(res.getColumnIndex("NoOfPrac")),res.getInt(res.getColumnIndex("NoOfExam")),res.getString(res.getColumnIndex("ModCode")),res.getString(res.getColumnIndex("ModDesc")),res.getString(res.getColumnIndex("UniID")),res.getString(res.getColumnIndex("FacID")),res.getString(res.getColumnIndex("EduID")));
moduleList.add(m);
}while (res.moveToNext());
}
}
/*
*/
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
moduleAdapter = new ModuleAdapter(this, moduleList);
recyclerView.setAdapter(moduleAdapter);
}
The recycler view displays everything right at first, but after scrolling the numbers begin to change with each scroll up or down.
When first open
1st scroll down and up
2nd scroll down and up
did I do anything wrong or what is going on? Thank you or any help
ModuleAdapter Class code
public class ModuleAdapter extends RecyclerView.Adapter<ModuleAdapter.ModuleViewHolder>{
private Context mCtx;
private List<Module> moduleList;
public ModuleAdapter(Context mCtx, List<Module> moduleList) {
this.mCtx = mCtx;
this.moduleList = moduleList;
}
#NonNull
#Override
public ModuleViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.from(parent.getContext())
.inflate(R.layout.module_list, parent, false);
return new ModuleViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ModuleViewHolder holder, int position) {
Module module = moduleList.get(position);
holder.textModCodeView.setText(module.getModcode());
holder.textModuleDescView.setText(module.getModdesc());
holder.textEducatorView.setText(holder.textEducatorView.getText()+ module.getEducator());
holder.textNoOfTestView.setText(holder.textNoOfTestView.getText()+ String.valueOf(module.getNooftest()));
holder.textNoOfAssView.setText(holder.textNoOfAssView.getText()+ String.valueOf(module.getNoofass()));
holder.textNoOfPracView.setText(holder.textNoOfPracView.getText()+ String.valueOf(module.getNoofprac()));
holder.textNoOfExamView.setText(holder.textNoOfExamView.getText()+ String.valueOf(module.getNoofexam()));
Random r = new Random();
int red=r.nextInt(255 - 0 + 1)+0;
int green=r.nextInt(255 - 0 + 1)+0;
int blue=r.nextInt(255 - 0 + 1)+0;
GradientDrawable draw = new GradientDrawable();
draw.setShape(GradientDrawable.RECTANGLE);
draw.setColor(Color.rgb(red,green,blue));
holder.textModCodeView.setBackground(draw);
}
#Override
public int getItemCount() {
return moduleList.size();
}
class ModuleViewHolder extends RecyclerView.ViewHolder{
TextView textModCodeView,textModuleDescView,textEducatorView,textNoOfTestView,textNoOfAssView,textNoOfPracView,textNoOfExamView;
public ModuleViewHolder(View itemView) {
super(itemView);
textModCodeView = itemView.findViewById(R.id.textModCodeView);
textModuleDescView = itemView.findViewById(R.id.textModuleDescView);
textEducatorView = itemView.findViewById(R.id.textEducatorView);
textNoOfTestView = itemView.findViewById(R.id.textNoOfTestView);
textNoOfAssView = itemView.findViewById(R.id.textNoOfAssView);
textNoOfPracView = itemView.findViewById(R.id.textNoOfPracView);
textNoOfExamView = itemView.findViewById(R.id.textNoOfExamView);
}
}
}
Follow this steps
1.Clear you arraylist before adding all values moduleList.clear();
Refresh:
public void refresh()
{
moduleList.clear(); // add this line
Cursor res = db.getAllData();
moduleList = new ArrayList<>();
if (res != null ) {
if (res.moveToFirst()) {
do {
Module m = new Module(res.getInt(res.getColumnIndex("ModID")),res.getInt(res.getColumnIndex("NoOfTest")),res.getInt(res.getColumnIndex("NoOfAss")),res.getInt(res.getColumnIndex("NoOfPrac")),res.getInt(res.getColumnIndex("NoOfExam")),res.getString(res.getColumnIndex("ModCode")),res.getString(res.getColumnIndex("ModDesc")),res.getString(res.getColumnIndex("UniID")),res.getString(res.getColumnIndex("FacID")),res.getString(res.getColumnIndex("EduID")));
moduleList.add(m);
}while (res.moveToNext());
}
}
/*
*/
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
moduleAdapter = new ModuleAdapter(this, moduleList);
recyclerView.setAdapter(moduleAdapter);
}
2.change below code as i mention below (i think view get conflit)
holder.textEducatorView.setText("Educatore"+ module.getEducator());
holder.textNoOfTestView.setText("NoOfTestView"+ String.valueOf(module.getNooftest()));
holder.textNoOfAssView.setText("NoOfAssView"+ String.valueOf(module.getNoofass()));
holder.textNoOfPracView.setText("NoOfPracView"+ String.valueOf(module.getNoofprac()));
holder.textNoOfExamView.setText("textNoOfExamView"+ String.valueOf(module.getNoofexam()));
I'm getting strange behaviour when trying to update a item in my adapter.
Let me first explain:
For this question lets say that the TextView in my ViewHolder is (FirstText), I then update the text to (SecondText), it works perfectly, it is changed like expected. Then I change it again to (ThirdText), then it returns to (FirstText) and not to (ThirdText) like expected. If I close the Activity and open it again the text is (ThirdText).In other words the item is only updated correctly every second time.
I hope that makes sense. Here is my Adapter:
public class MainActivityVideoAdapter extends Adapter<RecyclerView.ViewHolder> {
Context context;
View myLayoutView;
ArrayList<PathModel> thumbPathList;
ArrayList<PathModel> videoPathList;
long _id;
class MenuViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView videoName;
CircularImageView videoThumb;
ImageButton viewholderOtions;
MenuViewHolder(View itemView) {
super(itemView);
viewholderOtions = myLayoutView.findViewById(R.id.viewholderOptions);
videoName = myLayoutView.findViewById(R.id.FilePath);
videoThumb = myLayoutView.findViewById(R.id.VideoThumbnail);
itemView.setOnClickListener(this);
viewholderOtions.setOnClickListener(this);
}
//Handling click events
#Override
public void onClick(View v) {
if (v == viewholderOtions) {
int position = (int) v.getTag();
showPopupMenu(viewholderOtions, position);
}
}
}
public MainActivityVideoAdapter(Context context, ArrayList<PathModel> thumbPathList, ArrayList<PathModel> videoPathList) {
this.context = context;
this.thumbPathList = thumbPathList;
this.videoPathList = videoPathList;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
myLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.video_list, parent, false);
return new MenuViewHolder(myLayoutView);
}
public void onBindViewHolder(final RecyclerView.ViewHolder myHolder, final int position) {
MenuViewHolder ad = new MenuViewHolder(myLayoutView);
PathModel videoPathModel = this.videoPathList.get(position);
PathModel thumbathModel = this.thumbPathList.get(position);
File file = new File(videoPathModel.getPath());
final String filename = file.getName();
ad.videoName.setText(filename);
ad.videoName.setTypeface(custom_font_desc);
ad.videoThumb.setImageURI(Uri.parse(thumbathModel.getPath()));
ad.viewholderOtions.setTag(position);
}
private void showPopupMenu(final View view, final int position) {
final PopupMenu popup = new PopupMenu(view.getContext(), view);
popup.setGravity(Gravity.END);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.popup_menu, popup.getMenu());
popup.show();
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.rename:
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/KelsonSansLight.otf");
final String[] Rename = {"newname.mp4"};
LayoutInflater layoutInflater = LayoutInflater.from(context);
View promptView = layoutInflater.inflate(R.layout.dialoginput, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setView(promptView);
final String[] nameExtention = new String[1];
final EditText editText = (EditText) promptView.findViewById(R.id.input_text);
final TextView title = (TextView) promptView.findViewById(R.id.title);
title.setTypeface(font);
editText.setTypeface(font);
alertDialogBuilder.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Rename[0] = editText.getEditableText().toString();
if (!Rename[0].endsWith(".mp4")) {
Rename[0] = Rename[0] + ".mp4";
}
nameExtention[0] = editText.getEditableText().toString();
if (!Rename[0].equalsIgnoreCase("newname.mp4")) {
String temporary = fileRename(videoPathList.get(position).getPath(), Rename[0]);
String temporary2 = fileRename(videoPathList.get(position).getPath().replace(".mp4", ".jpg"), Rename[0].replace(".mp4", ".jpg"));
if (temporary != null && temporary2 != null) {
SQLiteHelper helper = new SQLiteHelper(context);
PathModel path1 = new PathModel();
path1.setPath(temporary);
PathModel path2 = new PathModel();
path2.setPath(temporary2);
String id_of_thumbpath = helper.getMainThumbID(thumbPathList.get(position).getPath());
videoPathList.set(position, path1);
thumbPathList.set(position, path2);
helper.updateMainThumbPath(temporary2, temporary, id_of_thumbpath);
helper.updateMainVideoPath(videoPathList.get(position).getPath(), id_of_thumbpath);
helper.close();
MainActivityVideoAdapter.this.notifyItemChanged(position);
Toast.makeText(view.getContext(), "Video Renamed", Toast.LENGTH_LONG).show();
}
}
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = alertDialogBuilder.create();
alert.show();
return true;
default:
return true;
}
}
});
}
//Rename files
public String fileRename(String _path, String nameChange) {
Log.d("FilePath", _path);
File file = new File(_path);
Log.d("FileName", file.getName());
Log.d("FileDir", file.getParent());
File rename = new File(file.getParent() + "/" + nameChange);
if (file.renameTo(rename))
return rename.getPath();
else
return null;
}
So, after I update the specific item I call MainActivityVideoAdapter.this.notifyItemChanged(position);
I have placed a Log in onBindViewHolder and it gets called when I call the above.
Another thing I noticed is when I call ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); in my fragment then the items gets messed up, here is my fragment:
public class MyFragment extends Fragment {
RecyclerView recyclerView;
private DBManager dbManager;
private long _id;
ArrayList<PathModel> MAINVideoPathList = new ArrayList<>();
ArrayList<PathModel> MAINThumbPathList = new ArrayList<>();
SQLiteHelper sqLiteHelper;
MainActivityVideoAdapter videoAdapter;
View v;
LinearLayoutManager layoutManager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
v = View.inflate(getContext(),R.layout.fragment_my, null);
sqLiteHelper = new SQLiteHelper(getActivity());
dbManager = new DBManager(getActivity());
dbManager = dbManager.open();
_id = Long.parseLong("1");
this.MAINThumbPathList = this.sqLiteHelper.MAINGetAllThumbPath(String.valueOf(this._id));
this.MAINVideoPathList = this.sqLiteHelper.MAINGetAllVideoPath(String.valueOf(this._id));
recyclerView = (RecyclerView) v.findViewById(R.id.frag2recycler);
txtEmptyAdapter = (TextView) v.findViewById(R.id.txtEmptyAdapter);
txtEmptyAdapter.setTypeface(custom_font_desc);
((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
videoAdapter = new MainActivityVideoAdapter(getContext(), this.MAINThumbPathList, this.MAINVideoPathList);
layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(videoAdapter);
videoAdapter.notifyDataSetChanged();
dbManager.close();
sqLiteHelper.close();
return v;
}
}
}
#Override
public void onResume() {
super.onResume();
MAINThumbPathList.clear();
MAINVideoPathList.clear();
MAINThumbPathList.addAll(sqLiteHelper.MAINGetAllThumbPath(String.valueOf(this._id)));
MAINVideoPathList.addAll(sqLiteHelper.MAINGetAllVideoPath(String.valueOf(this._id)));
videoAdapter = new MainActivityVideoAdapter(getContext(), this.MAINThumbPathList, this.MAINVideoPathList);
videoAdapter.notifyDataSetChanged();
recyclerView.setAdapter(videoAdapter);
sqLiteHelper.close();
if (recyclerView.getAdapter().getItemCount() > 0){
txtEmptyAdapter.setVisibility(View.GONE);
}else {
txtEmptyAdapter.setVisibility(View.VISIBLE);
}
}
I'm not sure what I'm doing wrong. Any help would greatly be appreciated.
I think it is also worth mentioning that I tried removing a item at a particular position and it works fine using the following:
thumbPathList.remove(position);
videoPathList.remove(position);
MainActivityVideoAdapter.this.notifyItemRemoved(position);
MainActivityVideoAdapter.this.notifyItemRangeChanged(position, thumbPathList.size());
MainActivityVideoAdapter.this.notifyItemRangeChanged(position, videoPathList.size());
You don't seem to understand the ViewHolder pattern which is the core of RecyclerView. You're making a disaster out of the adapter by by storing mLayoutView in onCreateViewHolder and reusing it in onBindViewHolder.
onCreateViewHolder is called only enough times to get enough ViewHolders to fill your viewport (so if you can see 5 items it is called about 6-7 times).
onBindViewHolder is used to display data from your dataset in the ViewHolders. It's called multiple times as long as your views enter and leave the viewport (even if you see 5 items it will be called indefinitely while scrolling). You will notice that ViewHolders leaving the viewport are re-used in this method and bound to another item (you can log text of textviews in this method for learning purposes).
My suggestion is to delete mLayoutView, and have your onBindViewHolder actually bind data to the ViewHolder provided in function parameter. You cannot create new ViewHolders there.
Can I display random page when our recycleview apps?
I want to put a floatbutton on my detailactivity.javaclass and when I click it must display a page with my string data and image files.
mFlowerData = new FlowerData("Rose", getString(R.string.description_flower_rose),
R.drawable.rose);
mFlowerList.add(mFlowerData);
mFlowerData = new FlowerData("Carnation", getString(R.string.description_flower_carnation),
R.drawable.carnation);
How can I display it on the last page.
You can use something like this in your activity/fragment
private List<Simple> elements;
private String names[] = {
"Monk's Oartormow",
"Eldoth Nut",
"Eblurst",
"Poison Okule",
"Black Berry",
"Snake Eye",
"Witch's Root",
"White Burm",
"Yellow Pig Claw",
"Uchea Mint"
};
private String contents[] = {
"What if the adaptable injury ate the click?",
"The united chip stuffs into the babyish sad.",
"Did the interesting progress really argue the visual?",
"What if the chief sign ate the schedule?",
"Is the brush respect better than the raise?",
"It was then the inexperienced topic met the open period."
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flower);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
elements = new ArrayList<>();
adapter = new SimpleAdapter();
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Simple s = generateRandomElement();
elements.add(0,s);
adapter.updateElements(elements);
}
});
}
private Simple generateRandomElement() {
int posNames = (int) (Math.random() * names.length);
int posContent = (int) (Math.random() * contents.length);
String name = names[posNames];
String content = contents[posContent];
return new Simple(name, content);
}
and for updating the elements in the adapter:
private List<Simple> elements;
public SimpleAdapter() {
this.elements = new ArrayList<>();
}
#Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_simple_element, parent, false);
return new SimpleViewHolder(view);
}
#Override
public void onBindViewHolder(SimpleViewHolder holder, int position) {
Simple element = elements.get(position);
holder.title.setText(element.getTitle());
holder.content.setText(element.getContent());
}
#Override
public int getItemCount() {
return elements.size();
}
public void updateElements(List<Simple> elements) {
this.elements.clear();
this.elements.addAll(elements);
notifyDataSetChanged();
}
you can improve how the elements are updated implementing a DiffCallback for your Flower class (link)
I'm using recyclerview to show my list of ground machines. Also I have a check box widget. When check box is checked, I want to sort my list by brand of machine. In my adapter I have a method setMachine(List listMachines); which has a reference to my current list of machines. Also my sort method works fine, but when I checked my check box my list is not sorted, worst it's disappeared, and my current list of machines is zero. Can someone help me to understand why that is happening:
My RecyclerView Adapter:
public class ListMachineAdapter extends RecyclerView.Adapter<ListMachineAdapter.ViewHolder> {
private List<Machine> listOfMachines;
private ClickMachineItemListener selectMachine;
private View.OnClickListener showToast = new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewHolder vh = (ViewHolder) v.getTag();
int position = vh.getItemPosition();
selectMachine.onClick(position);
}
};
public ListMachineAdapter(List<Machine> listOfMachines) {
this.listOfMachines = listOfMachines;
}
#Override
public ListMachineAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_list_machine, parent, false);
view.setOnClickListener(showToast);
return new ViewHolder(view, viewType);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Machine machine = listOfMachines.get(position);
holder.setPosition(position);
holder.brandMachine.setText(machine.getTypeBrand());
holder.typeMachine.setText(machine.getTypeMachine());
}
#Override
public int getItemCount() {
return listOfMachines.size();
}
public void setMachine(List<Machine> listMachines){
this.listOfMachines = listMachines; // size = 0 ??
}
public void setSelectMachine(ClickMachineItemListener selectMachine){
this.selectMachine = selectMachine;
}
Also I using Singleton to store my sort method:
public class MachineManager {
private static MachineManager instance;
private List<Machine> listOfGroundMachines;
private MachineManager() {
listOfGroundMachines = new ArrayList<>();
}
public static MachineManager getInstance() {
return instance = (instance == null) ? new MachineManager() : instance;
}
public List<Machine> sortByTypeBrand() {
Collections.sort(listOfGroundMachines, new Comparator<Machine>() {
#Override
public int compare(Machine lhs, Machine rhs) {
return lhs.getTypeBrand().compareToIgnoreCase(rhs.getTypeBrand());
}
});
return listOfGroundMachines;
}
}
And this is my Activity:
public class ListGroundMachineActivity extends Activity {
private CheckBox sortByTypeMachine, sortByTypeEngine, sortByTypeBrand, sortByYear;
private List<Machine> listOfGroundMachines;
private ListMachineAdapter adapter;
private MachineManager manager;
private ClickMachineItemListener click = new ClickMachineItemListener() {
#Override
public void onClick(int position) {
Machine machine = listOfGroundMachines.get(position);
Intent intent = new Intent(ListGroundMachineActivity.this, MachineDetailsActivity.class);
intent.putExtra(Constants.TYPE, machine.getTypeMachine());
intent.putExtra(Constants.BRAND, machine.getTypeBrand());
intent.putExtra(Constants.YEAR, machine.getYear());
intent.putExtra(Constants.ENGINE, machine.getTypeEngine());
Toast.makeText(ListGroundMachineActivity.this, machine.getTypeBrand(), Toast.LENGTH_SHORT).show();
startActivity(intent);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_ground_machine);
manager = MachineManager.getInstance();
listOfGroundMachines = populateGroundListMachine();
Log.i("TAG", "List size is " + listOfGroundMachines.size());
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list_ground_machine);
adapter = new ListMachineAdapter(listOfGroundMachines);
sortByTypeMachine = (CheckBox) findViewById(R.id.sort_by_type_ground_machine);
adapter.setSelectMachine(click);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this)
.color(R.color.teal).build());
recyclerView.setAdapter(adapter);
sortByTypeMachine.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
adapter.setMachine(manager.sortByTypeBrand());
adapter.notifyDataSetChanged();
Log.i("TAG 1", "List size is " + manager.sortByTypeBrand());
}
});
}
private List<Machine> populateGroundListMachine() {
List<Machine> listOfGroundMachineOne = new ArrayList<>();
MachineDB machineDb = new MachineDB(this);
SQLiteDatabase sqLiteDatabase = machineDb.getReadableDatabase();
Cursor cursor = sqLiteDatabase.query(MachineDB.TABLE_GROUND_MACHINE, null, null, null, null, null, null);
while (cursor.moveToNext()) {
String typeBrand = cursor.getString(cursor.getColumnIndex(Constants.BRAND));
String typeMachine = cursor.getString(cursor.getColumnIndex(Constants.TYPE));
String typeEngine = cursor.getString(cursor.getColumnIndex(Constants.ENGINE));
String year = cursor.getString(cursor.getColumnIndex(Constants.YEAR));
Machine machine = new Machine(typeBrand, typeMachine, typeEngine, year);
listOfGroundMachineOne.add(machine);
}
sqLiteDatabase.close();
return listOfGroundMachineOne;
}
Your listOfGroundMachines in MachineManager is only an empty arraylist:
private MachineManager() {
listOfGroundMachines = new ArrayList<>();
}
You need to create setter for that and call the setter after this code:
manager = MachineManager.getInstance();
listOfGroundMachines = populateGroundListMachine();
// here
The MachineManager listOfGroundMachines is an empty list.
You call listOfGroundMachines = populateGroundListMachine(); in your Activity class.
The list being populated with the machines is a member of ListGroundMachineActivity and not of MachineManager.