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.
Related
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);}
My custom listview row has remove button. I'm trying to delete specific item in listview with this remove button. (Remove from favorites action). I can delete selected item but rest of the list (items under the selected item) deleting with it. Top part still stay. How can I fix this? Thanks in advance.
FavoriteListAdapter :
public class FavoritesListAdapter extends ArrayAdapter<String> {
private Activity context;
private List<String> radioName;
private List<String> listenerNumbers;
public FavoritesListAdapter(Activity context, List<String> radioName, List<String> listenerNumbers) {
super(context, R.layout.custom_favorites_listview, radioName);
this.context=context;
this.radioName=radioName;
this.listenerNumbers=listenerNumbers;
}
#NonNull
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View r= convertView;
FavoritesViewHolder viewHolder = null;
if (r == null) {
LayoutInflater layoutInflater= context.getLayoutInflater();
r= layoutInflater.inflate(R.layout.custom_favorites_listview,null,true);
viewHolder = new FavoritesViewHolder(r);
r.setTag(viewHolder);
}
else {
viewHolder = (FavoritesViewHolder) r.getTag();
}
viewHolder.row_tv_favorites_radio_name.setText(radioName.get(position));
viewHolder.row_img_favorites_radio_icon.setImageResource(R.drawable.radio_logo_renkli);
viewHolder.row_tv_favorites_listener_numbers.setText("Listeners : " + listenerNumbers.get(position));
viewHolder.button_remove_from_favorites_list.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listenerNumbers.remove(position);
radioName.remove(position);
SharedPreferences settings = context.getSharedPreferences("PREFS", 0);
final SharedPreferences.Editor editor = settings.edit();
editor.remove("radio_link"+ position);
editor.remove("radio_name" + position);
editor.remove("listener_number" + position);
// editor.clear();
editor.commit();
// FavoritesFragment.radio_name_list.remove(position);
// FavoritesFragment.radio_link_list.remove(position);
// FavoritesFragment.listener_numbers.remove(position);
notifyDataSetChanged();
}
});
return r;
}
class FavoritesViewHolder {
TextView row_tv_favorites_radio_name;
TextView row_tv_favorites_listener_numbers;
ImageView row_img_favorites_radio_icon;
Button button_remove_from_favorites_list;
FavoritesViewHolder(View v) {
row_tv_favorites_radio_name= (TextView) v.findViewById(R.id.txt_radio_name_favorites);
row_tv_favorites_listener_numbers = (TextView) v.findViewById(R.id.txt_listener_numbers_favorites);
row_img_favorites_radio_icon = (ImageView) v.findViewById(R.id.img_radio_icon_favorites);
button_remove_from_favorites_list = (Button) v.findViewById(R.id.remove_favorites_from_list_button);
}
}
}
In my PlayRadioFragment, users have add favorite button, and values sent FavoritesFragment with unique keys
public static int incrementedValue = 0;
SharedPreferences settings = getActivity().getSharedPreferences("PREFS", 0);
final SharedPreferences.Editor editor = settings.edit();
add_favorites_button= (Button) view.findViewById(R.id.add_favorites_button);
add_favorites_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
editor.putString("radio_link"+ incrementedValue, radio_play_link);
editor.putString("radio_name" + incrementedValue, radio_name);
editor.putString("listener_number" + incrementedValue, listener_number);
// editor.clear();
editor.commit();
incrementedValue++;
}
});
And this is my FavoritesFragment :
public class FavoritesFragment extends Fragment {
public static FavoritesListAdapter adapter_2;
public FavoritesFragment() {
// Required empty public constructor
}
TextView radio_name_txt, radio_link_txt;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.fragment_favorites, container, false);
final List<String> radio_name_list = new ArrayList<>();
final List<String> radio_link_list = new ArrayList<>();
final List<String> listener_numbers = new ArrayList<>();
for (int i=0; i<Integer.MAX_VALUE; i++) {
SharedPreferences settings = getActivity().getSharedPreferences("PREFS",0);
String radio_name = settings.getString("radio_name" +i, "");
String radio_link = settings.getString("radio_link" +i, "");
String listener_number = settings.getString("listener_number" +i, "");
if (TextUtils.isEmpty(radio_name)){break;}
else {radio_name_list.add(radio_name);}
if (TextUtils.isEmpty(radio_link)){break;}
else {radio_link_list.add(radio_link);}
listener_numbers.add(listener_number);
}
PlayRadioFragment.incrementedValue = radio_name_list.size();
ListView listView_favorites = (ListView) view.findViewById(R.id.listview_favorites);
adapter_2 = new FavoritesListAdapter(getActivity(), radio_name_list, listener_numbers);
listView_favorites.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
PlayRadioFragment fragment= new PlayRadioFragment();
Bundle bundle= new Bundle();
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
bundle.putString("radio_play_links", radio_link_list.get(position));
bundle.putString("radio_name", radio_name_list.get(position));
bundle.putString("listener_number", listener_numbers.get(position));
fragment.setArguments(bundle);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.frame_layout,fragment);
fragmentTransaction.commit();
}
});
listView_favorites.setAdapter(adapter_2);
return view;
}
Create Your Object class As:
public class DemoGson {
private String radio_link,radio_name,listener_number;
public String getRadio_link() {
return radio_link;
}
public void setRadio_link(String radio_link) {
this.radio_link = radio_link;
}
public String getRadio_name() {
return radio_name;
}
public void setRadio_name(String radio_name) {
this.radio_name = radio_name;
}
public String getListener_number() {
return listener_number;
}
public void setListener_number(String listener_number) {
this.listener_number = listener_number;
}
}
While Adding data to it create new object and add data then insert that particular object to arraylist and pass arraylist to your adapter
ArrayList<DemoGson> arrayList = new ArrayList<>();
DemoGson demoGson = new DemoGson();
demoGson.setRadio_link("yourlink");
demoGson.setRadio_name("yourname");
demoGson.setListener_number("2");
arrayList.add(demoGson);
and then
adapter_2 = new FavoritesListAdapter(getActivity(),arrayList);
and in adapter just remove position from your arraylist
This doesn't not remove element from the adapter, only from your custom arrays:
listenerNumbers.remove(position);
radioName.remove(position);
In additional, you need to remove the item from the internal ArrayList of the adapter. Do it like this:
remove(getItem(position));
Generally, it is not good approach to manage 2 parallel custom arrays in the adapter (listenerNumbers, radioName in your case). Better to define Item class, containing both those fields, and provide ArrayList of the objects of this class to adapter as parameter (instead of array of Strings like in your case). And also o implement supporting XML for the item, that will have both items (TextView and RadioButton).
This app have a fragment that does CRUD operations on a single table database.
It is done on an class that draws a FAB and a recyclerview.
The FAB open an alertDialog with a insert form.
The recyclerview shows the database rows as cardviews. Each cardview have an edit button and a delete button.
The edit button open a alertdialog with the edit form in it.
The database stores journeys that each have a starting point and an ending point.
When entering or editing the places, user get suggestions.
For this I was using Google Places Web Service API but got to my attention that I must use Google Places API for Android and hence GoogleApiClient
Note that the app is working fine, doing the CRUD successfully and even getting the directions suggestions from Web Services.
I was able to make the insert form use the correct API, but not the edit form.
Here is the fragment code:
public class RecyclerFragment extends Fragment
implements AlertDialog.OnClickListener,
GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks {
private static final String TAG = "RecyclerFragment";
RunDbHelper runDbHelper; // Database helper class
RecyclerView recyclerView;
RecyclerViewAdapter recyclerViewAdapter;
private OnOkButtonListener mCallback;
private GoogleApiClient mGoogleApiClient;
private PlaceArrayAdapter mPlaceArrayAdapter;
private static final int GOOGLE_API_CLIENT_ID = 0;
private static final LatLngBounds BOUNDS_MOUNTAIN_VIEW = new LatLngBounds(
new LatLng(37.398160, -122.180831), new LatLng(37.430610, -121.972090));
private static LatLngBounds BOUNDS_AUTOCOMPLETE;
public RecyclerFragment() {
this.mCallback = null;
}
// main activity calls this method to pass the location so it can calculate bounds for the direction suggestions
public void setAutocompleteBounds(LatLng centerLatLng){
if (centerLatLng!= null && !centerLatLng.toString().isEmpty()){
Double latSW, lngSW, lngNE, latNE;
latSW = centerLatLng.latitude-.5;
lngSW = centerLatLng.latitude-.5;
lngNE = centerLatLng.latitude+.5;
latNE = centerLatLng.latitude+.5;
BOUNDS_AUTOCOMPLETE = new LatLngBounds(
new LatLng(latSW, lngSW), new LatLng(latNE, lngNE));
} else {
BOUNDS_AUTOCOMPLETE = BOUNDS_MOUNTAIN_VIEW;
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recycler, container, false);
try {
mGoogleApiClient = new GoogleApiClient.Builder(getContext())
.addApi(Places.GEO_DATA_API)
.enableAutoManage(getActivity(), GOOGLE_API_CLIENT_ID, this)
.addConnectionCallbacks(this)
.build();
} catch ( Exception e) {
Log.i(TAG, "onCreateView: " + e);
}
mPlaceArrayAdapter = new PlaceArrayAdapter(getContext(), android.R.layout.simple_list_item_1,
BOUNDS_AUTOCOMPLETE, null);
runDbHelper = RunDbHelper.getInstance(getContext());
List<RunData> mList = runDbHelper.getAllRuns();
recyclerViewAdapter = new RecyclerViewAdapter(getContext(), mList);
recyclerView = (RecyclerView) view.findViewById(R.id.rvRunList);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(recyclerViewAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.fabAdd);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Data entry dialog to insert new runs into database
dialogInsertRun();
}
});
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
public void dialogInsertRun() {
// Get the Activity for layout inflater as this dialog runs inside a fragment
LayoutInflater inflater = LayoutInflater.from(getActivity());
final View view = inflater.inflate(R.layout.dialog_new_run, null);
// Dialog Builder
AlertDialog.Builder addRunDialog = new AlertDialog.Builder(getActivity());
addRunDialog.setTitle(R.string.dialog_insert_run_title)
.setView(view);
// Data entry field objects
final EditText runParcelEditText = (EditText) view.findViewById(R.id.new_run_parcel);
final AutoCompleteTextView collectAddressACTV = (AutoCompleteTextView) view.findViewById(R.id.actv_new_collect_address);
final EditText collectPersonEditText = (EditText) view.findViewById(R.id.new_collect_person);
final AutoCompleteTextView deliveryAddressACTV = (AutoCompleteTextView) view.findViewById(R.id.actv_new_delivery_address);
final EditText deliveryPersonEditText = (EditText) view.findViewById(R.id.new_delivery_person);
collectAddressACTV.setThreshold(3);
collectAddressACTV.setOnItemClickListener(mAutocompleteClickListener);
collectAddressACTV.setAdapter(mPlaceArrayAdapter);
deliveryAddressACTV.setThreshold(3);
deliveryAddressACTV.setOnItemClickListener(mAutocompleteClickListener);
deliveryAddressACTV.setAdapter(mPlaceArrayAdapter);
addRunDialog.setPositiveButton(R.string.button_positive, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
RunData runData = new RunData(); // POJO that holds data from database
runData.run_parcel = getStringOrEmpty(runParcelEditText);
runData.collect_person = getStringOrEmpty(collectPersonEditText);
runData.collect_address = getStringOrEmpty(collectAddressACTV);
runData.delivery_person = getStringOrEmpty(deliveryPersonEditText);
runData.delivery_address = getStringOrEmpty(deliveryAddressACTV);
// must insert at least one of the places (starting or ending point) or both
if (!(runData.collect_address.isEmpty() && runData.delivery_address.isEmpty())) {
runData = runDbHelper.insertRun(runData, getActivity());
if (runData != null) {
cardViewMessageIsEmpty.setVisibility(View.INVISIBLE);
recyclerViewAdapter = new RecyclerViewAdapter(getActivity(), runDbHelper.getAllRuns());
recyclerView.setAdapter(recyclerViewAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mCallback.addMarkersToMap(runData);
}
} else {
Toast.makeText(getActivity(), R.string.dialog_insert_run_toast_nowhere, Toast.LENGTH_LONG).show();
}
}
});
addRunDialog.setNegativeButton(R.string.button_negative, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.cancel();
}
});
addRunDialog.create();
addRunDialog.show();
}
private String getStringOrEmpty(EditText editText) {
String mString = editText.getText().toString();
mString = (mString == null || mString.isEmpty() ? "" : mString);
return mString;
}
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//Log.d(TAG, "onClick: ");
}
#Override
public void onAttach(Context context) {
if (context instanceof OnOkButtonListener) {
mCallback = (OnOkButtonListener) context; // keep a reference to eula activity for interface
} else {
throw new ClassCastException(context.toString()
+ getString(R.string.exception_onokbutton_listener));
}
super.onAttach(context);
}
public void setCustomObjectListener(OnOkButtonListener listener) {
this.mCallback = listener;
}
#Override
public void onConnected(#Nullable Bundle bundle) {
mPlaceArrayAdapter.setGoogleApiClient(mGoogleApiClient);
Log.i(TAG, "Google Places API connected.");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(TAG, "Google Places API connection failed with error code: "
+ connectionResult.getErrorCode());
Toast.makeText(getContext(),
"Google Places API connection failed with error code:" +
connectionResult.getErrorCode(),
Toast.LENGTH_LONG).show();
}
#Override
public void onConnectionSuspended(int i) {
mPlaceArrayAdapter.setGoogleApiClient(null);
Log.e(TAG, "Google Places API connection suspended.");
}
public interface OnOkButtonListener {
void addMarkersToMap(RunData runData);
}
private AdapterView.OnItemClickListener mAutocompleteClickListener
= new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final PlaceArrayAdapter.PlaceAutocomplete item = mPlaceArrayAdapter.getItem(position);
final String placeId = String.valueOf(item.placeId);
Log.i(TAG, "Selected: " + item.description);
PendingResult<PlaceBuffer> placeResult = Places.GeoDataApi
.getPlaceById(mGoogleApiClient, placeId);
placeResult.setResultCallback(mUpdatePlaceDetailsCallback);
Log.i(TAG, "Fetching details for ID: " + item.placeId);
}
};
#Override
public void onDestroyView() {
super.onDestroyView();
if(mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.stopAutoManage(getActivity());
mGoogleApiClient.disconnect();
}
}
private ResultCallback<PlaceBuffer> mUpdatePlaceDetailsCallback
= new ResultCallback<PlaceBuffer>() {
#Override
public void onResult(PlaceBuffer places) {
if (!places.getStatus().isSuccess()) {
Log.e(TAG, "Place query did not complete. Error: " +
places.getStatus().toString());
return;
}
// Selecting the first object buffer.
}
};
}
And here is the adapter code:
class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {
private static final String TAG = "RecyclerViewAdapter";
private Context context;
private List<RunData> dataList = new ArrayList<>();
private LayoutInflater inflater;
private RunDbHelper runDbHelper;
RecyclerViewAdapter(Context context, List<RunData> dataList1) {
this.context = context;
this.dataList = dataList1;
this.runDbHelper = RunDbHelper.getInstance(this.context);
inflater = LayoutInflater.from(context);
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View inflateView = inflater.inflate(R.layout.fragment_recycler_row, parent, false);
return new RecyclerViewHolder(inflateView);
}
#Override
public void onBindViewHolder(final RecyclerViewHolder holder, final int position) {
holder.runID.setText(dataList.get(position).run_id);
holder.collectAddress.setText(dataList.get(position).collect_address);
holder.deliveryAddress.setText(dataList.get(position).delivery_address);
holder.ivEdit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RunData runData = new RunData();
runData.run_id = holder.runID.getText().toString();
runData.collect_address = holder.collectAddress.getText().toString();
runData.delivery_address = holder.deliveryAddress.getText().toString();
dialogEditRun(runData, position);
}
});
}
#Override
public int getItemCount() {
return dataList.size();
}
public void dialogEditRun(RunData runData, int position) {
// Get the Activity for layout inflater as this dialog runs inside a fragment
LayoutInflater inflater = LayoutInflater.from(context);
final View inflaterView = inflater.inflate(R.layout.dialog_edit_run, null);
// Data entry field objects
final String mRunID;
final AutoCompleteTextView collectAddressACTV = (AutoCompleteTextView) inflaterView.findViewById(R.id.actv_edit_collect_address);
final AutoCompleteTextView deliveryAddressACTV = (AutoCompleteTextView) inflaterView.findViewById(R.id.actv_edit_delivery_address);
mRunID = runData.run_id;
collectAddressACTV.setText(runData.collect_address);
deliveryAddressACTV.setText(runData.delivery_address);
// HERE THE FIELDS AND THE SUGGESTIONS ARE LINKED
// Set directions into recyclerViewAdapter for autocomplete
// here is still using G. Places WebService API. Should be G. Places API for Android, using GoogleApiClient
collectAddressACTV.setAdapter(new GooglePlacesAutocompleteAdapter(context, R.layout.dialog_new_run_autocomplete));
deliveryAddressACTV.setAdapter(new GooglePlacesAutocompleteAdapter(context, R.layout.dialog_new_run_autocomplete));
// Dialog Builder
AlertDialog.Builder editRunDialog = new AlertDialog.Builder(context);
editRunDialog.setTitle(R.string.dialog_update_run_title).setView(inflaterView);
editRunDialog.setPositiveButton(R.string.button_positive, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
RunData runData = new RunData();
int position = (int) run_date.getTag();
runData.run_id = mRunID;
runData.collect_address = getStringOrEmpty(collectAddressACTV);
runData.delivery_address = getStringOrEmpty(deliveryAddressACTV);
if (!(runData.collect_address.isEmpty() && runData.delivery_address.isEmpty())){
// try to update, if success update recycler.
if (runDbHelper.updateRun(runData, context)){
// atualiza o recyclerview
dataList.remove(position);
notifyItemRemoved(position);
dataList.add(position,runData);
notifyItemRangeChanged(position, dataList.size());
notifyItemInserted(position);
} else {
Toast.makeText(context, "No record updated", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(context, "Inform at least one direction", Toast.LENGTH_SHORT).show();
}
}
});
editRunDialog.setNegativeButton(R.string.button_negative, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.cancel();
}
});
editRunDialog.create();
editRunDialog.show();
}
private String getStringOrEmpty(EditText editText) {
String mString = editText.getText().toString();
mString = (mString.isEmpty() ? "" : mString);
return mString;
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
TextView runID, collectAddress, deliveryAddress;
ImageView ivEdit;
RecyclerViewHolder(View rowView) {
super(rowView);
runID = (TextView) rowView.findViewById(R.id.runId);
collectAddress = (TextView) rowView.findViewById(R.id.collectAddress);
deliveryAddress = (TextView) rowView.findViewById(R.id.deliveryAddress);
ivEdit = (ImageView) rowView.findViewById(R.id.ivEdit);
}
}
}
When I try to add the code to instantiate the GoogleApiClient inside the reclycler adapter, at onCreateViewHolder(ViewGroup parent, int viewType), Android Studio wont let me. I cannot find the right reference for enableAutoManage
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(Places.GEO_DATA_API)
.enableAutoManage(HEREISTHEERROR, GOOGLE_API_CLIENT_ID, this) // nada do que tentei colocar aqui no lugar do XXXXXXX funcionou!
.addConnectionCallbacks(this)
.build();
In summary, what I want accomplished is to receive suggestions when adding or editing directions data into forms that are shown inside alertDialog.
Must use Google Places API for android, hence GoogleApiClient.
Not sure that this is the right approach, so... Any suggestions or workarounds are welcome.
I have solved the question.
There can be only one GoogleApiClient with enableAutoManage(). The other calls to the API have to deal with life cicle.
Accessing Google APIs
this is my code:
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_add_aircraft, container, false);
recyclerView=(RecyclerView)rootView.findViewById(R.id.recyclerAircraftAdd);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
adapter = new AircraftAdapter(getActivity(),path);
recyclerView.setAdapter(adapter);
Button button = (Button)rootView.findViewById(R.id.salvaereo);
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
adapter = (AircraftAdapter)recyclerView.getAdapter();
ParseObject aircraft = new ParseObject("Aircrafts");
for(int i = 0;i<adapter.getItemCount(); i++)
{
if (i== 0) //first card
{
View view = recyclerView.getLayoutManager().findViewByPosition(i);
ImageView image = (ImageView)view.findViewById(R.id.aircfraftImg);
image.setDrawingCacheEnabled(true);
image.buildDrawingCache();
Bitmap bm = image.getDrawingCache();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bytes = stream.toByteArray();
ParseFile file = new ParseFile("Image.jpg",bytes);
aircraft.put("aircraft_image",file);
file.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
Log.d("sa","tutto ok");
}
});
}
else if (i ==1) //second card
{
View view = recyclerView.getLayoutManager().findViewByPosition(i);
EditText immatricolazione =(EditText)view.findViewById(R.id.immatricolazione);
EditText modello = (EditText)view.findViewById(R.id.modello);
EditText manifacturer = (EditText)view.findViewById(R.id.manifacturer);
EditText categoria = (EditText)view.findViewById(R.id.categoria);
EditText classe = (EditText)view.findViewById(R.id.classe);
EditText velocita = (EditText)view.findViewById(R.id.velocita);
EditText autonomia = (EditText)view.findViewById(R.id.autonomia);
EditText consumo = (EditText)view.findViewById(R.id.consumo);
EditText posti = (EditText)view.findViewById(R.id.postitotali);
EditText costo = (EditText)view.findViewById(R.id.costorario);
aircraft.put("re",immatricolazione.getEditableText().toString());
aircraft.put("ml",modello.getEditableText().toString());
aircraft.put("man",manifacturer.getEditableText().toString());
aircraft.put("Aircraft_Type",categoria.getEditableText().toString());
aircraft.put("ar",classe.getEditableText().toString());
aircraft.put("post",Integer.parseInt(posti.getEditableText().toString()));
aircraft.put("meter",Integer.parseInt(consumo.getEditableText().toString()));
aircraft.put("speed",Integer.parseInt(velocita.getEditableText().toString()));
aircraft.put("prezzi",Float.parseFloat(costo.getEditableText().toString()));
aircraft.put("fuel",Integer.parseInt(autonomia.getEditableText().toString()));
}
else if(i==2) //third card
{
View view = recyclerView.getLayoutManager().findViewByPosition(i);
EditText description = (EditText) view.findViewById(R.id.description);
aircraft.put("descrizione", description.getEditableText().toString());
aircraft.put("User", ParseUser.getCurrentUser());
dialog = ProgressDialog.show(getActivity(), "", "Caricamento aereo in corso...", true);
aircraft.saveInBackground(new SaveCallback() {
public void done(ParseException e) {
dialog.dismiss();
if (e == null) {
new AlertDialog.Builder(getActivity())
.setMessage("Caricamento aereo avvenuto con successo!")
.setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
}).create().show();
} else {
new AlertDialog.Builder(getActivity())
.setMessage("Non è stato possibile caricare l'aereo, riprova più tardi!")
.setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
}).create().show();
}
}
});
}
}
}
});
return rootView;
}
but there is this problem: if I charge a photo (first card) and press button, it uploads the photo, but if I write into EditText, it crashes and gives me this error:
Process: com.run.flyproject, PID: 10796
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
at com.run.flyproject.Fragments.AddAircraftFragment$1.onClick(AddAircraftFragment.java:78)
at android.view.View.performClick(View.java:4756)
at android.view.View$PerformClick.run(View.java:19749)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5253)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Not that this is an explicit answer (the explicit answer would be something like "Your adapter count doesn't coincide with the views available from your adapter"), but my comments were probably getting a bit confusing. You could do something like this...
public class YourAdapter extends RecyclerView.Adapter<YourViewHolder>{
private boolean mSaveImages = false;
private SparseArray<Boolean> mImageSavedFlags = new SparseArray<>();
public void toggleSaveStatus(){
mSaveImages = !mSaveImages;
}
// ... your code
#Override
public void onBindViewHolder(YourViewHolder holder, final int position) {
// Could also manage this in a loop or something
// in your constructor/when you set your adapter data
// but this will set our SparseArray
if(mImageSavedFlags.get(position) == null)
mImageSavedFlags.put(position, false);
// ... your code
if(mSaveImages && !mImageSavedFlags.get(position){
// ... save your image
mImageSavedFlags.put(position, true);
}
}
// ... your code
}
This way whenever you attempt to bind a view, you can check if you want to save the ImageViews source and if you haven't already saved it, if you haven't it will save the source and update the SparseArray.
To toggle your status just do something like this
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v){
adapter.toggleSaveStatus();
}
}
It is worth noting that this will only save images that you actually scroll to after you toggle the save setting on. I suppose you could force scrolling of you RecyclerView but that is getting into something else.
It is also important to realize that if you are doing something like loading images from a URL or from your drawables based on position or something, you don't actually need your ImageView to load the source before you can save it, there are plenty of ways (including libraries) to save images that haven't been explicitly loaded into your app yet, which would completely remove the need to include your adapter in the process.
I am sure this isn't the only way to do this, and I am sure this isn't the best answer, but again my comments were getting a bit confusing.
You can use use both
recyclerViewInstance.findViewHolderForAdapterPosition(adapterPosition) and
recyclerViewInstance.findViewHolderForLayoutPosition(layoutPosition).
Be sure that RecyclerView view uses two type of positions
Adapter position : Position of an item in the adapter. This is the position from the Adapter's perspective.
Layout position : Position of an item in the latest layout calculation. This is the position from the LayoutManager's perspective.
You should use getAdapterPosition() for findViewHolderForAdapterPosition(adpterPosition) and getLayoutPosition() for findViewHolderForLayoutPosition(layoutPosition).
Take a member variable to hold previously selected item position in recyclerview adapter and other member variable to check whether user is clicking for first time or not.
Sample code and screen shots are attached for more information at the bottom.
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerList = null;
private RecyclerAdapter adapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerList = (RecyclerView) findViewById(R.id.recyclerList);
}
#Override
protected void onStart() {
RecyclerView.LayoutManager layoutManager = null;
String[] daysArray = new String[15];
String[] datesArray = new String[15];
super.onStart();
for (int i = 0; i < daysArray.length; i++){
daysArray[i] = "Sunday";
datesArray[i] = "12 Feb 2017";
}
adapter = new RecyclerAdapter(mRecyclerList, daysArray, datesArray);
layoutManager = new LinearLayoutManager(MainActivity.this);
mRecyclerList.setAdapter(adapter);
mRecyclerList.setLayoutManager(layoutManager);
}
}
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyCardViewHolder>{
private final String TAG = "RecyclerAdapter";
private Context mContext = null;
private TextView mDaysTxt = null, mDateTxt = null;
private LinearLayout mDateContainerLayout = null;
private String[] daysArray = null, datesArray = null;
private RecyclerView mRecyclerList = null;
private int previousPosition = 0;
private boolean flagFirstItemSelected = false;
public RecyclerAdapter(RecyclerView mRecyclerList, String[] daysArray, String[] datesArray){
this.mRecyclerList = mRecyclerList;
this.daysArray = daysArray;
this.datesArray = datesArray;
}
#Override
public MyCardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = null;
View view = null;
MyCardViewHolder cardViewHolder = null;
mContext = parent.getContext();
layoutInflater = LayoutInflater.from(mContext);
view = layoutInflater.inflate(R.layout.date_card_row, parent, false);
cardViewHolder = new MyCardViewHolder(view);
return cardViewHolder;
}
#Override
public void onBindViewHolder(MyCardViewHolder holder, final int position) {
mDaysTxt = holder.mDaysTxt;
mDateTxt = holder.mDateTxt;
mDateContainerLayout = holder.mDateContainerLayout;
mDaysTxt.setText(daysArray[position]);
mDateTxt.setText(datesArray[position]);
if (!flagFirstItemSelected){
mDateContainerLayout.setBackgroundColor(Color.GREEN);
flagFirstItemSelected = true;
}else {
mDateContainerLayout.setBackground(null);
}
}
#Override
public int getItemCount() {
return daysArray.length;
}
class MyCardViewHolder extends RecyclerView.ViewHolder{
TextView mDaysTxt = null, mDateTxt = null;
LinearLayout mDateContainerLayout = null;
LinearLayout linearLayout = null;
View view = null;
MyCardViewHolder myCardViewHolder = null;
public MyCardViewHolder(View itemView) {
super(itemView);
mDaysTxt = (TextView) itemView.findViewById(R.id.daysTxt);
mDateTxt = (TextView) itemView.findViewById(R.id.dateTxt);
mDateContainerLayout = (LinearLayout) itemView.findViewById(R.id.dateContainerLayout);
mDateContainerLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LinearLayout linearLayout = null;
View view = null;
if (getAdapterPosition() == previousPosition){
view = mRecyclerList.findViewHolderForAdapterPosition(previousPosition).itemView;
linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);
linearLayout.setBackgroundColor(Color.GREEN);
previousPosition = getAdapterPosition();
}else {
view = mRecyclerList.findViewHolderForAdapterPosition(previousPosition).itemView;
linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);
linearLayout.setBackground(null);
view = mRecyclerList.findViewHolderForAdapterPosition(getAdapterPosition()).itemView;
linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);
linearLayout.setBackgroundColor(Color.GREEN);
previousPosition = getAdapterPosition();
}
}
});
}
}
}
1
source
you are getting NullPointerException as your recyclerView.getLayoutManager().find... returns null and your second question why you don't get view by position, check recyclerView.getLayoutManager().getChildCount() to verify that you have any child for that index
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.