RecyclerAdapter IndexOutOfBoundError on using CustomViewHolder - java

What i'm trying to do is that, I have an adapter which I'm using for many different activities each having their own ViewHolder. So I'm firstly making an abstract recycler adapter named DimRecyclerAbstractAdapter without a ViewHolder. Then for each different activity I'm making a static inner class named DimCustomAdapter which extends DimRecyclerAbstractAdapter having it's own ViewHolder. But I'm getting this error.
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.get(ArrayList.java:411)
This is the abstract adapter class -
public abstract class DimRecyclerAbstractAdapter<VHA extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VHA> {
private List<tbl_dim_1> mtbldimList1;
public DimRecyclerAbstractAdapter(List<tbl_dim_1> tblDimList1) {
this.mtbldimList1 = tblDimList1;
}
#Override
public int getItemCount() {
return mtbldimList1.size();
}
public void addItems(List<tbl_dim_1> tblDimList1) {
this.mtbldimList1 = tblDimList1;
notifyDataSetChanged();
}
#Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
mtbldimList1 = null;
super.onDetachedFromRecyclerView(recyclerView);
}
}
This is the activity in which I've implemented custom ViewHolder -
public class DetailActivity1 extends LifecycleActivity{
DimListViewModel dmvmodel;
RecyclerView rcView;
DimCustomAdapter rcAdapter;
public static final String LOG_TAG = "In DetailActivity1 ";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_view);
Intent receivedIntent = getIntent();
int rid_int = receivedIntent.getIntExtra("mRId",0);
Log.v(LOG_TAG,"Rid value int == " + rid_int);
rcView = (RecyclerView) findViewById(R.id.recyclerView);
rcAdapter = new DimCustomAdapter(new ArrayList<tbl_dim_1>());
rcView.setLayoutManager(new LinearLayoutManager(DetailActivity1.this));
Log.v(LOG_TAG, "Layout manager set");
rcView.setAdapter(rcAdapter);
dmvmodel = ViewModelProviders.of(this).get(DimListViewModel.class);
Log.v(LOG_TAG, "View model returned");
dmvmodel.getDimList2con1(rid_int).observe(DetailActivity1.this, new Observer<List<tbl_dim_1>>() {
#Override
public void onChanged(#Nullable List<tbl_dim_1> changedItems) {
Log.v(LOG_TAG, "onChanged called, items will be added");
rcAdapter.addItems(changedItems);
}
});
}
#Override
protected void onDestroy() {
rcAdapter = null;
rcView.setAdapter(null);
rcView.setLayoutManager(null);
rcView = null;
dmvmodel = null;
super.onDestroy();
RefWatcher refWatcher = LeakCheckApplication.getRefWatcher(this);
refWatcher.watch(this);
}
public static class DimCustomAdapter extends DimRecyclerAbstractAdapter<DimCustomAdapter.RecyclerViewHolder> {
private static List<tbl_dim_1> mtbldimCustom;
DimCustomAdapter(List<tbl_dim_1> tblDimListPassed) {
super(mtbldimCustom);
mtbldimCustom = tblDimListPassed;
}
#Override
public DimCustomAdapter.RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View vw = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_item, parent, false);
// vw.setOnClickListener(vwOnClickListener);
return new DimCustomAdapter.RecyclerViewHolder(vw);
}
#Override
public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
// Log.v(LOG_TAG, "Inside onBindViewHolder - ");
if (holder.dataTextView.getText() != null) {
String LOG_TAG = "DimCustomAdapter:";
Log.d(LOG_TAG, "holder is not null, i was right");
holder.dataTextView.setText(null);
holder.dataTextView.setOnClickListener(null);
}
final tbl_dim_1 dimAtPosition = mtbldimCustom.get(position);
holder.dataTextView.setText(dimAtPosition.mCONTENT);
holder.dataTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg) {
Intent dw = new Intent(arg.getContext(), DetailActivity2.class);
dw.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
dw.putExtra("mRId", dimAtPosition.mR_ID);
arg.getContext().startActivity(dw);
}
});
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView dataTextView;
RecyclerViewHolder(View view) {
super(view);
dataTextView = (TextView) view.findViewById(R.id.data_text_view);
}
}
}
}
And this is how I'm calling this inner class from outer class within same activity -
DimCustomAdapter rcAdapter = new DimCustomAdapter(new ArrayList<tbl_dim_1>());

Its because of empty list that you are passing while creating the adapter.
DimCustomAdapter rcAdapter = new DimCustomAdapter(new ArrayList<tbl_dim_1>());
Just add a null or empty check in onBindViewHolder method before calling
final tbl_dim_1 dimAtPosition = mtbldimCustom.get(position);
Hope this will stop crashing your application.
You can try like below,
ArrayList<tbl_dim_1> list = new ArrayList<>()
rcAdapter = new DimCustomAdapter(list);
then in observe method,
dmvmodel.getDimList2con1(rid_int).observe(DetailActivity1.this, new Observer<List<tbl_dim_1>>() {
#Override
public void onChanged(#Nullable List<tbl_dim_1> changedItems) {
Log.v(LOG_TAG, "onChanged called, items will be added");
list.addAll(changedItems);
rcAdapter.notifyDataSetChanged()
}
});

This is the solution i worked out for my problem( In case anyone face the same problem ).
Modyfying Durga's answer -
Firstly i added the isEmpty() check that he mentioned in comment.
Then in the activity i changed the code to this -
a) Added this new method in DimCustomAdapter -
public void changeList(List<tbl_dim_1> addedList){
mtbldimCustom = addedList;
}
b) Called this method in observe method -
dmvmodel.getDimList2con1(rid_int).observe(DetailActivity1.this, new Observer<List<tbl_dim_1>>() {
#Override
public void onChanged(#Nullable List<tbl_dim_1> changedItems) {
Log.v(LOG_TAG, "onChanged called, items will be added");
rcAdapter.changeList(changedItems);
rcAdapter.addItems(changedItems);
}
});

Related

How to flow Data from One RecyclerView to Another RecyclerView when an item in first RecyclerView is clicked?

Hi, I faced an issue here.. I was creating a chatbot in which user can type a text to send it and also can select a text out of the recommended texts
so I created two RecycleViews
My goal is - when the user selects one of the recommended text, then that text should appear in the Chatting RecycleView
here is my main Activity Class
public class Charts extends AppCompatActivity {
private static final String USER_KEY = "user";
private static final String BOT_KEY = "bot";
RecyclerView chart_recycle,auto_texts;
EditText message_text;
ImageView send_btn,mic_button;
ImageView setting_button;
ChartsAdapter chartsAdapter;
RecyclerView.LayoutManager linearLayout;
ArrayList<ChartModeClass> modeClassesArrayList = new ArrayList<>();
AutoAdapter autoAdapter;
RecyclerView.LayoutManager horizontal;
List<Texts> list = new ArrayList();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chatting_hole);
message_text = findViewById(R.id.message_text);
send_btn = findViewById(R.id.send_btn);
mic_button = findViewById(R.id.mic_btn);
setting_button = findViewById(R.id.setting_button);
chart_recycle = findViewById(R.id.chart_recycle);
chart_recycle.setHasFixedSize(true);
auto_texts = findViewById(R.id.auto_texts);
auto_texts.setHasFixedSize(true);
linearLayout = new LinearLayoutManager(getApplicationContext(), RecyclerView.VERTICAL, false);
chart_recycle.setLayoutManager(linearLayout);
//Auto text
horizontal = new LinearLayoutManager(getApplicationContext(),RecyclerView.HORIZONTAL, false);
auto_texts.setLayoutManager(horizontal);
chartsAdapter = new ChartsAdapter(modeClassesArrayList, Charts.this);
chart_recycle.setAdapter(chartsAdapter);
//Auto texts
autoAdapter = new AutoAdapter(getApplicationContext(),list);
auto_texts.setAdapter(autoAdapter);
addInputs();
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(Charts.this);
mic_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bottomSheetDialog.setContentView(R.layout.record);
bottomSheetDialog.show();
}
});
message_text.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().trim().length()==0){
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}else {
send_btn.setVisibility(View.VISIBLE);
mic_button.setVisibility(View.GONE);
}
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().trim().isEmpty()){
// Toast.makeText(getApplicationContext(),"Enter text",Toast.LENGTH_LONG).show();
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}else {
send_btn.setVisibility(View.VISIBLE);
mic_button.setVisibility(View.GONE);
}
}
#Override
public void afterTextChanged(Editable editable) {
if (editable.toString().length()==0){
mic_button.setVisibility(View.VISIBLE);
send_btn.setVisibility(View.GONE);
}
}
});
send_btn.setOnClickListener(view -> {
if (message_text.getText().toString().isEmpty()) {
Toast.makeText(Charts.this, "Please enter text..", Toast.LENGTH_SHORT).show();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
returnResponse(message_text.getText().toString());
}
message_text.setText("");
});
}
#SuppressLint("NotifyDataSetChanged")
private void returnResponse(String message) {
modeClassesArrayList.add(new ChartModeClass(message, USER_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size()-1);
String url = "http://xxxxxxxxxxxxxxxx"+message;
String BASE_URL = "https://xxxxxxxxx";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitApi retrofitApi = retrofit.create(RetrofitApi.class);
Call<MessageModeClass> call = retrofitApi.getMessage(url);
call.enqueue(new Callback<MessageModeClass>() {
#Override
public void onResponse(#NonNull Call<MessageModeClass> call, #NonNull Response<MessageModeClass> response) {
if (response.isSuccessful()) {
MessageModeClass messageModeClass = response.body();
if (messageModeClass != null) {
modeClassesArrayList.add(new ChartModeClass(messageModeClass.getCnt(), BOT_KEY));
}
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
} else {
Toast.makeText(Charts.this, "response is null", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(#NonNull Call<MessageModeClass> call, #NonNull Throwable t) {
modeClassesArrayList.add(new ChartModeClass("No response check your network connection!", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}
});
}
#SuppressLint("NotifyDataSetChanged")
#Override
protected void onStart() {
super.onStart();
String lang = getIntent().getExtras().getString("lang");
if (lang.equals("english")){
modeClassesArrayList.add(new ChartModeClass("Hey welcome back am fema bot", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}else if (lang.equals("swahili")){
modeClassesArrayList.add(new ChartModeClass("Habari karibu miminni bot niliyetengenezw", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}else {
modeClassesArrayList.add(new ChartModeClass("Hey welcome back am fema bot", BOT_KEY));
chartsAdapter.notifyDataSetChanged();
chart_recycle.scrollToPosition(modeClassesArrayList.size() - 1);
}
}
private void addInputs() {
Texts text1 = new Texts("gender?");
Texts text2 = new Texts("gender equality");
Texts text3 = new Texts("what is good about females");
Texts text4 = new Texts("un goals");
Texts text5 = new Texts("about men");
list.addAll(Arrays.asList(new Texts[]{text1,text2,text3,text4,text5}));
}
}
here is my Adapter class class codes
public class AutoAdapter extends RecyclerView.Adapter<AutoAdapter.ViewHolderClass> {
Context context;
List<Texts> list;
public AutoAdapter(Context context, List<Texts> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public ViewHolderClass onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_list,parent,false);
ViewHolderClass viewHolderClass = new ViewHolderClass(view);
return viewHolderClass;
}
#Override
public void onBindViewHolder(#NonNull ViewHolderClass holder, #SuppressLint("RecyclerView") int position) {
holder.input_text.setText(list.get(position).getText());
holder.input_text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// my stack
}
});
}
#Override
public int getItemCount() {
return list.size();
}
public class ViewHolderClass extends RecyclerView.ViewHolder {
TextView input_text;
public ViewHolderClass(#NonNull View itemView) {
super(itemView);
input_text = itemView.findViewById(R.id.input_text);
}
}
}
You can add a list of your recommendations in another RecyclerView
Then in the ViewHolder of each item of the RecyclerView add Callback to listen on click events when a user clicks one of the item like the following
public class ViewHolderClass extends RecyclerView.ViewHolder {
private TextView input_text;
private final Callback callback; // custom callback
public ViewHolderClass(#NonNull View itemView, Callback callback) {
super(itemView);
this.callback = callback;
input_text = itemView.findViewById(R.id.input_text);
// now add onClickListener of the itemView to fire custom callback
itemView.setOnClickListener(view -> {
this.callback.onItemClick(getAdapterPosition());
});
}
// this is my custom callback for return click event
public interface Callback {
void onItemClick(int position);
}
}
Now inside your adapter add the callback from viewholder
public class AutoAdapter extends RecyclerView.Adapter<AutoAdapter.ViewHolderClass> {
private Context context;
private List<Texts> list;
private AutoAdapterCallback callback;
public AutoAdapter(Context context, List<Texts> list) {
this.context = context;
this.list = list;
}
public setCallback(AutoAdapterCallback callback) {
this.callback = callback;
}
#NonNull
#Override
public ViewHolderClass onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_list,parent,false);
ViewHolderClass viewHolderClass = new ViewHolderClass(view, new ViewHolderClass.Callback() {
#Override
public void onItemClick(int position) {
// forward callback to adapter callback
if (callback != null) {
// get actual item from its position
final Texts texts = getItemByPosition(position);
// send to adapter callback
callback.onItemClick(texts);
}
});
return viewHolderClass;
}
#Override
public void onBindViewHolder(#NonNull ViewHolderClass holder, #SuppressLint("RecyclerView") int position) {
holder.input_text.setText(list.get(position).getText());
// I haven't used this inteady I added callback on viewholder side
// holder.input_text.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View view) {
// // my stack
// }
// });
}
#Override
public int getItemCount() {
return list.size();
}
// return Texts object by given position
public Texts getItemByPosition(int position) {
return this.list.get(position);
}
// add adapter callback to be called by viewholder
public interface AdapterCallback {
void onItemClick(Texts texts);
}
}
After that, now on your Activity you can easily listen on any item when a user clicks and get its corresponding Texts object from list as following:
//code ...
// here
//Auto texts
autoAdapter = new AutoAdapter(getApplicationContext(),list);
//set callback to listen for click events
autoAdapter.setCallback(new AutoAdapter.AutoAdapterCallback() {
#Override
public void onItemClick(Texts texts) {
// you can get your clicked item here
// now you can put texts object to another RecyclerView :)
}
});
auto_texts.setAdapter(autoAdapter);
//code ...

How can I get a variable from RecyclerView Adapter passed to MainActivity?

I was just playing around with some code, learning new things, when I ran into this problem... I'm trying to pass a variable from my RecylcerViewAdapter to a method in MainActivity, but I just can't seem to accomplish it.
I tried a lot of different thing with interfaces and casting, but nothing did the trick. Since I'm fairly new to all of this, maybe I'm making a trivial mistake somewhere?
My Interface:
public interface AdapterCallback {
void onMethodCallback(int id);
}
This is my adapter class:
public class PostAdapter extends RecyclerView.Adapter<PostAdapter.ViewHolder> {
private List<Post> postList;
private Context context;
private AdapterCallback listener;
public PostAdapter() {
}
public PostAdapter(List<Post> postList, Context context) {
this.postList = postList;
this.context = context;
}
public void setListener(AdapterCallback listener) {
this.listener = listener;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_layout, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder viewHolder, final int position) {
viewHolder.tvTitle.setText(postList.get(position).getTitle());
viewHolder.tvBody.setText(new StringBuilder(postList.get(position).getBody().substring(0, 20)).append("..."));
viewHolder.tvId.setText(String.valueOf(postList.get(position).getUserId()));
viewHolder.parentLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int id = postList.get(position).getId();
if (listener != null) {
listener.onMethodCallback(id);
}
}
});
}
#Override
public int getItemCount() {
return postList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
TextView tvBody;
TextView tvId;
LinearLayout parentLayout;
public ViewHolder(View itemView) {
super(itemView);
tvTitle = itemView.findViewById(R.id.tvTitle);
tvBody = itemView.findViewById(R.id.tvBody);
tvId = itemView.findViewById(R.id.tvId);
parentLayout = itemView.findViewById(R.id.parentLayout);
}
}
}
And my MainActivity:
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainActivityLog";
private CompositeDisposable disposable = new CompositeDisposable();
#BindView(R.id.rvPosts)
RecyclerView rvPosts;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
rvPosts.setHasFixedSize(true);
rvPosts.setLayoutManager(new LinearLayoutManager(this));
populateList();
logItems();
}
private void populateList() {
MainViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(MainViewModel.class);
viewModel.makeQuery().observe(MainActivity.this, new Observer<List<Post>>() {
#Override
public void onChanged(#Nullable List<Post> posts) {
PostAdapter adapter = new PostAdapter(posts, getApplicationContext());
rvPosts.setAdapter(adapter);
}
});
}
public void logItems() {
PostAdapter adapter = new PostAdapter();
adapter.setListener(new AdapterCallback() {
#Override
public void onMethodCallback(int id) {
MainViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(MainViewModel.class);
viewModel.makeSingleQuery(id).observe(MainActivity.this, new Observer<Post>() {
#Override
public void onChanged(#Nullable final Post post) {
Log.d(TAG, "onChanged: data response");
Log.d(TAG, "onChanged: " + post);
}
});
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
disposable.clear();
}
}
The populateList() method works just fine, but the logItems() method is the problem.
So when i click on a view in RecyclerView I expect the log to output the title, description and ID of the post that was clicked. nut nothing happens...
So, any help would be appreciated.
Make adapter global variable i.e. a field. Use the same object to set every properties.
private PostAdapter adapter;
Replace your logItems method with this:
public void logItems() {
adapter.setListener(new AdapterCallback() {
#Override
public void onMethodCallback(int id) {
MainViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(MainViewModel.class);
viewModel.makeSingleQuery(id).observe(MainActivity.this, new Observer<Post>() {
#Override
public void onChanged(#Nullable final Post post) {
Log.d(TAG, "onChanged: data response");
Log.d(TAG, "onChanged: " + post);
}
});
}
});
}
And populateList with this:
private void populateList() {
MainViewModel viewModel = ViewModelProviders.of(MainActivity.this).get(MainViewModel.class);
viewModel.makeQuery().observe(MainActivity.this, new Observer<List<Post>>() {
#Override
public void onChanged(#Nullable List<Post> posts) {
adapter = new PostAdapter(posts, getApplicationContext());
rvPosts.setAdapter(adapter);
logItems();
}
});
}
And don't call logItems() from onCreate
This is how I implement with my ListAdapters:
public class FeedbackListAdapter extends RecyclerView.Adapter<FeedbackListAdapter.ViewHolder> {
private final ArrayList<Feedback> feedbacks;
private View.OnClickListener onItemClickListener;
private View.OnLongClickListener onItemLongClickListener;
private final Context context;
public FeedbackListAdapter(ArrayList<Feedback> feedbacks, Context context) {
this.feedbacks = feedbacks;
this.context = context;
}
public void setItemClickListener(View.OnClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public void setOnItemLongClickListener(View.OnLongClickListener onItemLongClickListener){
this.onItemLongClickListener = onItemLongClickListener;
}
public class ViewHolder extends RecyclerView.ViewHolder{
final TextView feedback, created, updated;
final LinearLayout mainLayout;
ViewHolder(View iv) {
super(iv);
/*
* Associate layout elements to Java declarations
* */
mainLayout = iv.findViewById(R.id.main_layout);
feedback = iv.findViewById(R.id.feedback);
created = iv.findViewById(R.id.created_string);
updated = iv.findViewById(R.id.updated_string);
}
}
#Override
public int getItemCount() {
return feedbacks.size();
}
#Override
#NonNull
public FeedbackListAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_feedback_table_row, parent, false);
return new FeedbackListAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(final #NonNull FeedbackListAdapter.ViewHolder holder, final int position) {
/*
* Bind data to layout
* */
try{
Feedback feedback = feedbacks.get(position);
holder.feedback.setText(feedback.getContent());
holder.created.setText(feedback.getCreated());
holder.updated.setText(feedback.getUpdated());
holder.mainLayout.setOnClickListener(this.onItemClickListener);
holder.mainLayout.setOnLongClickListener(this.onItemLongClickListener);
holder.mainLayout.setTag(feedback.getDbID());
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
holder.mainLayout.setBackgroundResource(outValue.resourceId);
}catch(IndexOutOfBoundsException e){
e.printStackTrace();
}
}
}
In onPopulateList you create an adaptor:
PostAdapter adapter = new PostAdapter(posts, getApplicationContext());
rvPosts.setAdapter(adapter);
However in public void logItems() { you used a different adapter
PostAdapter adapter = new PostAdapter();
adapter.setListener(new AdapterCallback() {
#Override
public void onMethodCallback(int id) {
...
}
});
Therefore the list is being populated with 1 adapter, but you are setting the listener on an unused second adapter.
The fix is to use the same adapter for both. If you make the adapater a field, and don't create a new one inside of logItems, but just set your listener it should work.
i.e.
// as a field in your class
private PostAdapter adapter;
then
// in `populateList()`
adapter = new PostAdapter(posts, getApplicationContext());
rvPosts.setAdapter(adapter);
and
// in `logItems()`
adapter.setListener(new AdapterCallback() {
#Override
public void onMethodCallback(int id) {
...
}
});
In Adapter
public class CustomerListAdapter extends RecyclerView.Adapter<CustomerListAdapter.OrderItemViewHolder> {
private Context mCtx;
ProgressDialog progressDialog;
//we are storing all the products in a list
private List<CustomerModel> customeritemList;
public CustomerListAdapter(Context mCtx, List<CustomerModel> orderitemList) {
this.mCtx = mCtx;
this.customeritemList = orderitemList;
progressDialog = new ProgressDialog(mCtx);
}
#NonNull
#Override
public OrderItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.activity_customer_list, null);
return new OrderItemViewHolder(view, mCtx, customeritemList);
}
#Override
public void onBindViewHolder(#NonNull OrderItemViewHolder holder, int position) {
CustomerModel customer = customeritemList.get(position);
try {
//holder.textViewPINo.setText("PINo \n"+Integer.toString( order.getPINo()));
holder.c_name.setText(customer.getCustomerName());
holder.c_address.setText(customer.getAddress());
holder.c_contact.setText(customer.getMobile());
holder.i_name.setText(customer.getInteriorName());
holder.i_contact.setText(customer.getInteriorMobile());
holder.i_address.setText(customer.getAddress());
} catch (Exception E) {
E.printStackTrace();
}
}
#Override
public int getItemCount() {
return customeritemList.size();
}
class OrderItemViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener {
AlertDialog.Builder alert;
private Context mCtx;
TextView c_name, c_contact, c_address, i_name, i_contact, i_address;
TextView OrderItemID, MaterialType, Price2, Qty, AQty;
//we are storing all the products in a list
private List<CustomerModel> orderitemList;
public OrderItemViewHolder(View itemView, Context mCtx, List<CustomerModel> orderitemList) {
super(itemView);
this.mCtx = mCtx;
this.orderitemList = orderitemList;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
// CatelogOrderDetailModel catelogOrderDetailModel = new CatelogOrderDetailModel();
c_name = itemView.findViewById(R.id.customerName);
c_contact = itemView.findViewById(R.id.contact);
c_address = itemView.findViewById(R.id.address);
i_name = itemView.findViewById(R.id.interiorName);
i_address = itemView.findViewById(R.id.interiorAddress);
i_contact = itemView.findViewById(R.id.interiorContact);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
CustomerModel orderitem = this.orderitemList.get(position);
}
#Override
public boolean onLongClick(View v) {
int position = getAdapterPosition();
CustomerModel orderitem = this.orderitemList.get(position);
if (v.getId() == itemView.getId()) {
// showUpdateDeleteDialog(order);
try {
} catch (Exception E) {
E.printStackTrace();
}
Toast.makeText(mCtx, "lc: ", Toast.LENGTH_SHORT).show();
}
return true;
}
}
}

Show wrong data when filtered RecyclerView item is clicked

I have a RecyclerView with edittext for search in my android app. When I search in it and click on an item, it shows wrong data.
I know why it happens but I don't know how to fix it. I have tried many things but still I have the problem. i am new in programming, please help :).
Here is the code of my Adapter.
public class ProjectAdapter extends RecyclerView.Adapter<ProjectAdapter.ProjectViewHolder> {
private Context mCtx;
private List<Project> projectList;
private OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public ProjectAdapter(Context mCtx, List<Project> projectList) {
this.mCtx = mCtx;
this.projectList = projectList;
}
#Override
public ProjectViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mCtx);
View view = inflater.inflate(R.layout.project_list, null);
return new ProjectAdapter.ProjectViewHolder(view);
}
#Override
public void onBindViewHolder(ProjectViewHolder holder, int position) {
Project project = projectList.get(position);
holder.textViewProject.setText(project.getProject());
}
#Override
public int getItemCount() {
return projectList.size();
}
class ProjectViewHolder extends RecyclerView.ViewHolder {
TextView textViewProject;
public ProjectViewHolder(View itemView) {
super(itemView);
textViewProject = itemView.findViewById(R.id.textViewProject);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mListener != null){
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
mListener.onItemClick(position);
}
}
}
});
}
}
}
and this is my ListprojectActivity.java
public class ListprojectActivity extends AppCompatActivity implements ProjectAdapter.OnItemClickListener {
public static final String project_select = "project";
private static final String URL_PRODUCTS = "http://192.168.43.245/android_register_login/Api_1.php";
EditText editTextProject;
//a list to store all the products
List<Project> projectList;
//the recyclerview
RecyclerView recyclerView;
ProjectAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listproject);
//getting the recyclerview from xml
recyclerView = findViewById(R.id.recylcerViewProject);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
editTextProject = findViewById(R.id.EditTextProject);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
DividerItemDecoration itemDecoration = new DividerItemDecoration(this, layoutManager.getOrientation());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(itemDecoration);
//initializing the productlist
projectList = new ArrayList<>();
editTextProject.addTextChangedListener (new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
final String query = s.toString().toLowerCase().trim();
final ArrayList<Project> filteredList = new ArrayList<>();
for (int i = 0; i < projectList.size(); i++) {
final String text = projectList.get(i).getProject().toLowerCase();
if (text.contains(query)) {
filteredList.add(projectList.get(i));
}
}
recyclerView.setLayoutManager(new LinearLayoutManager(ListprojectActivity.this));
adapter = new ProjectAdapter(ListprojectActivity.this, filteredList);
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(ListprojectActivity.this);
adapter.notifyDataSetChanged();
}
#Override
public void afterTextChanged(Editable s) {
}
});
//this method will fetch and parse json
//to display it in recyclerview
loadProjects();
}
private void loadProjects() {
/*
* Creating a String Request
* The request type is GET defined by first parameter
* The URL is defined in the second parameter
* Then we have a Response Listener and a Error Listener
* In response listener we will get the JSON response as a String
* */
StringRequest stringRequest = new StringRequest(Request.Method.GET, URL_PRODUCTS,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
//converting the string to json array object
JSONArray array = new JSONArray(response);
//traversing through all the object
for (int i = 0; i < array.length(); i++) {
//getting product object from json array
JSONObject project = array.getJSONObject(i);
//adding the product to product list
projectList.add(new Project(
project.getInt("id_project"),
project.getString("project")
));
}
//creating adapter object and setting it to recyclerview
ProjectAdapter adapter = new ProjectAdapter(ListprojectActivity.this, projectList);
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(ListprojectActivity.this);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
//adding our stringrequest to queue
Volley.newRequestQueue(this).add(stringRequest);
}
#Override
public void onItemClick(int position) {
Intent detailMasalah = new Intent(this, ListproblemActivity.class);
Project projectclick = projectList.get(position);
detailMasalah.putExtra(project_select, projectclick.getProject());
startActivity(detailMasalah);
}
}
and project.java
public class Project {
private int id_project;
private String project;
public Project (int id_project, String project) {
this.id_project = id_project;
this.project = project;
}
public int getId() {
return id_project;
}
public String getProject() {
return project;
}
}
Try this
#Override
public void onBindViewHolder(ProjectViewHolder holder, int position) {
Project project = projectList.get(position);
holder.textViewProject.setText(project.getProject());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mListener != null){
int position = holder.getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
mListener.onItemClick(position);
}
}
}
});
}
It happened because you are setting the listener in your ViewHolder class instead of your onBindViewHolder. As the viewholder is recycled, no new objects are created after some scrolling. The created object's click listener is bound to the item that first created it.
As Vishrut mentioned, you should move the listener to onBindViewHolder.

cannot refresh the recyclveiw from inside fragment?

I display data inside the fragment at first I used some functions within the function on Create View and everything became perfect and succeeded in fetching and displaying data, but when I call the adpter from within another function to try to do a re-display and update data happens errors,
specifically, a problem occurs when I press the button inside the dialog,
please help
//CustomerAdapter class
public class CustomerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public final int TYPE_MOVIE = 0;
public final int TYPE_LOAD = 1;
static Context context;
List<Customer>customers;
OnLoadMoreListener loadMoreListener;
boolean isLoading = false, isMoreDataAvailable = true;
public CustomerAdapter(Context context, List<Customer> customers) {
this.context = context;
this.customers = customers;
}
public void refreshEvents(List<Customer> data) {
clear();
addAll(data);
notifyDataSetChanged();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType==TYPE_MOVIE){
return new CustomerHolder(inflater.inflate(R.layout.row_movie,parent,false));
}else{
return new LoadHolder(inflater.inflate(R.layout.row_load,parent,false));
}
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
if(position>=getItemCount()-1 && isMoreDataAvailable && !isLoading && loadMoreListener!=null){
isLoading = true;
loadMoreListener.onLoadMore();
}
if(getItemViewType(position)==TYPE_MOVIE){
((CustomerHolder)holder).bindData(customers.get(position));
if(((CustomerHolder)holder).buttonViewOption != null)((CustomerHolder)holder).buttonViewOption.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// function call a volly function .. //..
// if(customers.get(position).user_id==2)((CustomerHolder)holder).imgLock.setVisibility(View.VISIBLE);
((CustomerHolder)holder).buttonViewOption.getRootView().toString();
// Toast.makeText(context,"Index Is "+customers.get(position).status+"usr_id"+customers.get(position).user_id, Toast.LENGTH_SHORT).show();
//Page_6Fragment.newInstance().sendNotfic(context ,customers.get(position).user_id);
// Call a fucntion to
Page_6Fragment.newInstance().showDialog(context,customers.get(position).user_id , Integer.parseInt(customers.get(position).id));
}
});
}
}
#Override
public int getItemViewType(int position) {
if(customers.get(position).type.equals("movie")){
return TYPE_MOVIE;
}else{
return TYPE_LOAD;
}
}
#Override
public int getItemCount(){
return customers.size();
}
/* VIEW HOLDERS */
static class CustomerHolder extends RecyclerView.ViewHolder{
TextView tvTitle;
TextView tvRating;
ImageView imgLock;
// int usrid;
Button buttonViewOption;
public CustomerHolder(View itemView){
super(itemView);
tvTitle=(TextView)itemView.findViewById(R.id.title);
tvRating=(TextView)itemView.findViewById(R.id.rating);
imgLock=(ImageView)itemView.findViewById(R.id.img_lock);
buttonViewOption = (Button) itemView.findViewById(R.id.textViewOptions);
}
void bindData(Customer cust){
tvTitle.setText(cust.name);
tvRating.setText(cust.title);
// if(cust.user_id==2)imgLock.setVisibility(View.GONE);
if(cust.status!=0)buttonViewOption.setBackground(context.getResources().getDrawable(R.drawable.lock));
// imgLock.setVisibility(View.VISIBLE);
}
}
static class LoadHolder extends RecyclerView.ViewHolder{
public LoadHolder(View itemView){
super(itemView);
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
/* notifyDataSetChanged is final method so we can't override it
call adapter.notifyDataChanged(); after update the list
*/
public void notifyDataChanged(){
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener{
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
}
// Fragment class :
public class Page_6Fragment extends android.support.v4.app.Fragment implements AdapterView.OnItemSelectedListener {
TextView t1,t2,t3,t4;
Spinner spin,spin2,spin3,spin4;
Dialog dialog;
RecyclerView recyclerView;
List<Customer>customers;
CustomerAdapter adapter;
View rootView;
String TAG = "MainActivity - ";
Context context;
API api;
Activity a;
Boolean acceptOrNo = true;
Context c =null;
public static Page_6Fragment newInstance(){
Page_6Fragment fragment = new Page_6Fragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.activity_customer, container, false);
//View rootView = inflater.inflate(R.xml.pref, container, false);
//Intent intent = new Intent(PreferenceDemoActivity.this,PrefsActivity.class);
// startActivity(intent);
this.context = getActivity();
recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
customers = new ArrayList<>();
adapter = new CustomerAdapter(context,customers);
adapter.setLoadMoreListener(new CustomerAdapter.OnLoadMoreListener(){
#Override
public void onLoadMore() {
recyclerView.post(new Runnable() {
#Override
public void run() {
int index = customers.size();
loadMore(index);
}
});
//Calling loadMore function in Runnable to fix the
// java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling error
}
});
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(adapter);
api = ServiceGenerator.createService(API.class);
load(0);
return rootView;
}
// recyclerView.addItemDecoration(new VerticalLineDecorator(2));
private void load(int index){
Call<List<Customer>> call = api.getCustomer(index);
call.enqueue(new Callback<List<Customer>>(){
#Override
public void onResponse(Call<List<Customer>> call, final Response<List<Customer>> response){
// Toast.makeText(MainActivity.this, "tost "+response.body().get(0).post_writer, Toast.LENGTH_LONG).show();
//Log.i("TRUE_TRUE_","Yes "+response.body().get(2).name);
if(response.isSuccessful()){
//Log.i("TRUE_TRUE3","Yes"+response.body().toString());
//movies.addAll(response.body());
//adapter.notifyDataChanged();
getActivity().runOnUiThread(new Runnable(){
public void run(){
// No.1 ..............
// ShowDataScreen();
// Toast.makeText( MainActivity.this, "ShowDataScreen",Toast.LENGTH_SHORT).show();
customers.addAll(response.body());
adapter.notifyDataChanged();
}});// end of No.1 UI new thread
getActivity().runOnUiThread(new Runnable(){
public void run() {//No.2
// Toast.makeText( MainActivity.this, "This is correct way",Toast.LENGTH_SHORT).show();
}});// end of No.2 UI new thread
// Toast.makeText(MainActivity.this, "tost "+response.body().get(0).post_writer, Toast.LENGTH_LONG).show();
}else{
Log.e(TAG," Response Error "+String.valueOf(response.code()));
}
}
#Override
public void onFailure(Call<List<Customer>> call, Throwable t) {
Log.e(TAG," Response Error "+t.getMessage());
}
});
}
public void showDialog(final Context context , final int getToken , final int id){
dialog = new Dialog(context);
dialog.setCancelable(true);
// dialog.setTitle("استقبال الطلب");
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.layout);
dialog.show();
String[] bankNames = {
"O","B","H","N","j"
};
t1= (TextView)dialog.findViewById(R.id.tv_h);
t2= (TextView)dialog.findViewById(R.id.tv_m);
t3= (TextView)dialog.findViewById(R.id.tv_title);
t4= (TextView)dialog.findViewById(R.id.tv_pam);
spin =(Spinner)dialog.findViewById(R.id.spinner_minutes);
spin2 =(Spinner)dialog.findViewById(R.id.spinner_minutes2);
spin3 =(Spinner)dialog.findViewById(R.id.spinner_minutes3);
spin4 =(Spinner)dialog.findViewById(R.id.tex);
spin.setOnItemSelectedListener(this);
spin2.setOnItemSelectedListener(this);
spin3.setOnItemSelectedListener(this);
spin4.setOnItemSelectedListener(this);
RadioButton radioButton2 = (RadioButton)dialog.findViewById(R.id.second2);
RadioButton radioButton = (RadioButton)dialog.findViewById(R.id.second);
RadioGroup radioGroup = (RadioGroup)dialog.findViewById(R.id.radioSex);
ArrayAdapter<String> a = new ArrayAdapter<String>(context,R.layout.spinner_item,bankNames);
//ArrayAdapter b = new ArrayAdapter(this,android.R.layout.simple_spinner_item,bankNames2);
//a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//spin.setAdapter(a);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton radioButton = (RadioButton)dialog.findViewById(checkedId);
if (checkedId == R.id.second2) {
RadioYes();
acceptOrNo = false;
} else if (checkedId == R.id.second) {
acceptOrNo = true;
RadioNo();
}
}
});
Button btnOk = (Button)dialog.findViewById(R.id.button_cancel);
btnOk.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
//TODO Auto-generated method stub
// Log.i("trace_u",""+acceptOrNo);
if(acceptOrNo)sendNotfic(context , id , getToken ,"1" , spin4.getSelectedItem().toString() , "الساعه"+spin.getSelectedItem().toString()+":"+spin2.getSelectedItem().toString()+" "+spin3.getSelectedItem().toString());
else
sendNotfic(context , id , getToken ,"2","--" ,"--");
dialog.dismiss();
/// Update Rview
// if(adapter != null) {
adapter.refreshEvents(customers);
//}
}
});
Button btnNo = (Button)dialog.findViewById(R.id.button_set);
btnNo.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
// TODO Auto-generated method stub
dialog.dismiss();
/*
adapter = new CustomerAdapter(context , customers);
Log.i("adapter_",""+adapter);
if(adapter != null) {
Log.i("adpter_33","yesysy");
adapter.refreshEvents();
}
*/
}
});
}
// Loge cat :
Process: com.example.android.wacher, PID: 2519
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.android.wacher.adapters.CustomerAdapter.refreshEvents(java.util.List)' on a null object reference
at com.example.android.wacher.fragments.Page_6Fragment$8.onClick(Page_6Fragment.java:312)
at android.view.View.performClick(View.java:5609)
at android.view.View$PerformClick.run(View.java:22259)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
In your onBindViewHolder you have this line
Page_6Fragment.newInstance().showDialog(context,customers.get(position).user_id , Integer.parseInt(customers.get(position).id));
In this line you create new instance of Page_6Fragment where you didn't initialize the adapter yet, You try to show dialog and in the button listener you refresh a null adapter
Solution 1:
Pass a callback function to the adapter, which is implemented in the fragment
Solution 2:
You can pass the fragment as a parameter to the adapter and call the method directly instead of creating new instance of the fragment
Change the constructor to
public CustomerAdapter(Page_6Fragment page_6Fragment, List<Customer> customers) {
// You can get context from page_6Fragment.getContext()
// And No need to make the context or the fragment static
}
And in onBindViewHolder
Call the method this way
page_6Fragment.showDialog(context,customers.get(position).user_id , Integer.parseInt(customers.get(position).id));
And in the fragment when you initialize the adapter
adapter = new CustomerAdapter(Page_6Fragment.this,customers);

Updating Item in RecyclerView

I'm making a to do list app using a RecyclerView. When a task is clicked a dialog will appear and the user will be able to edit the name of the task. Once the user exists the dialog I want to reflect the changes of the task in the RecyclerView.
I have an activity called ListActivity that hosts a fragment which contains the RecyclerView. Likewise, I create my AlertDialog in a class called EditTaskFragment. Lastly, I store all the task objects in an arraylist in a Singleton class called TaskLab.
To retrieve the String after the user changes the name of a task item in the RecyclerView I am calling onActivityResult() in the ListFragment class. But I'm not sure how to update the task object that is stored in my Singleton and then how to get the ViewHolder to changes the Title field of a task item.
My ListFragment class
public class ListFragment extends Fragment {
private static final int REQUEST_TITLE = 0;
private RecyclerView mRecyclerView;
private TaskAdapter mAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_list, container, false);
mRecyclerView = view.findViewById(R.id.the_task_list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
updateUI();
return view;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == Activity.RESULT_OK && requestCode == ListFragment.REQUEST_TITLE) {
// Do something.
}
}
#Override
public void onResume() {
super.onResume();
updateUI();
}
public void updateUI() {
List<Task> taskList = TaskLab.get(getActivity()).getTaskList();
if(mAdapter == null) {
mAdapter = new TaskAdapter(taskList);
mRecyclerView.setAdapter(mAdapter);
}else {
mAdapter.notifyDataSetChanged();
}
}
private class TaskAdapter extends RecyclerView.Adapter<TaskHolder>{
private List<Task> mTaskList;
public TaskAdapter(List<Task> taskList) {
mTaskList = taskList;
}
#Override
public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.task_list_layout, parent, false);
return new TaskHolder(view);
}
#Override
public void onBindViewHolder(TaskHolder holder, int position) {
Task currentTask = mTaskList.get(position);
holder.bindData(currentTask);
}
#Override
public int getItemCount() {
return mTaskList.size();
}
}
private class TaskHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private Task mTask;
private TextView mTaskTitle;
private CheckBox mSolved;
private static final String DIALOG = "edit_dialog";
public TaskHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mTaskTitle = itemView.findViewById(R.id.task_title);
mSolved = itemView.findViewById(R.id.task_solved);
}
public void bindData(Task task) {
mTask = task;
mTaskTitle.setText(mTask.getTitle());
mSolved.setChecked(mTask.isSolved());
}
#Override
public void onClick(View view) {
FragmentManager manager = getFragmentManager();
EditTaskFragment dialog = EditTaskFragment.newInstance(mTask.getTitle());
dialog.setTargetFragment(ListFragment.this, REQUEST_TITLE);
dialog.show(manager, DIALOG);
}
}
}
My EditTaskFragment class
public class EditTaskFragment extends DialogFragment {
private EditText mTaskTitle;
private String mTaskName;
private static final String ARG_TASK_TITLE = "task_title";
public static final String EXTRA_TASK_TITLE = "list_app_task_title";
private void sendResult(int resultCode, String taskName) {
if(getTargetFragment() == null) {
return;
}
Intent intent = new Intent();
intent.putExtra(EXTRA_TASK_TITLE,taskName);
getTargetFragment().onActivityResult(getTargetRequestCode(),resultCode, intent);
}
public static EditTaskFragment newInstance(String taskName) {
Bundle args = new Bundle();
args.putString(ARG_TASK_TITLE, taskName);
EditTaskFragment fragment = new EditTaskFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTaskName = getArguments().getString(ARG_TASK_TITLE);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_edit_task_dialog, null);
mTaskTitle = view.findViewById(R.id.edit_task_title);
mTaskTitle.setText(mTaskName);
return new AlertDialog.Builder(getActivity())
.setView(view)
.setTitle(R.string.edit_task_dialog_title)
.setPositiveButton(R.string.edit_task_dialog_positive, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
sendResult(Activity.RESULT_OK, mTaskTitle.getText().toString());
}
})
.setNegativeButton(R.string.edit_task_dialog_negative, null)
.create();
}
}
My Singleton class - TaskLab
public class TaskLab {
private static TaskLab sTaskLab;
private List<Task> mTaskList;
private TaskLab(Context context){
mTaskList = new ArrayList<>();
for(int i = 0; i < 10; i++) {
Task task = new Task();
task.setTitle("Task #" + i);
task.setSolved(i%2 == 0);
mTaskList.add(task);
}
}
public static TaskLab get(Context context) {
if(sTaskLab == null) {
sTaskLab = new TaskLab(context);
}
return sTaskLab;
}
public List<Task> getTaskList(){
return mTaskList;
}
public Task getTask(int id){
for(Task task : mTaskList) {
if(task.getId().equals(id)){
return task;
}
}
return null;
}
}
In EditTaskFragment.sendResult() you are calling onActivityResult() of the target fragment. This is wrong. onActivityResult() is meant to be called by the framework, not the programmer.
What you have to do is use the enclosing activity of the fragments in order to pass data between the fragments.
Define an interface TaskChangedListener
Make your activity implement it, as well as ListFragment
In EditTaskFragment.sendResult(), use ((TaskChangedListener) getActivity()).onTaskChanged(taskName)
In onTaskChanged() of the activity, you will need to find the ListFragment (you can find it by tag from the fragment manager) and then call its onTaskChanged() from there.
In onTaskChanged() of ListFragment do:
List taskList = TaskLab.get(getActivity()).getTaskList();
mAdapter.clear();
mAdapter.addAll(taskList);
mAdapter.notifyDataSetChanged();
You will need to add the clear() and addAll() methods to your TaskAdapter class:
void clear() {
mTaskList.clear();
}
void addAll(List<Task> taskList) {
mTaskList.addAll(taskList);
}
As a next step

Categories

Resources