I have a fragment (Inventory Fragment) that displays some CardView objects in a RecyclerView. These objects get their data from an Adapter after the data has been received from the ViewModel. Inside the adapter, there are certain functions that can change the Livedata. All of these functions first open another Fragment (Food Editor), and this where the new data is set to the ViewModel.
My problem is that even after this, the RecyclerView does not get the new object. I used notifyDataSetChanged(). What am I doing wrong? Is there an easier way to achieve what I am trying to do (Add, Delete, Modify and such)?
Inventory Fragment:
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.List;
public class InventoryFragment extends Fragment {
//GLOBAL VARIABLES
RecyclerView recyclerView;
FoodAdapter foodAdapter;
FloatingActionButton add_button;
FrameLayout frameLayout;
FoodViewModel foodViewModel;
//FOOD LIST
private List<Food> foodList;
public InventoryFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_inventory, container, false);
//GETTING THE FOOD VIEW MODEL
foodViewModel = new ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication())).get(FoodViewModel.class); //TODO:HERE
foodList = foodViewModel.getFoods().getValue();
foodAdapter = new FoodAdapter(foodList);
recyclerView=v.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(foodAdapter);
//SETTING THE FOOD VIEW MODEL
foodViewModel.getFoods().observe(getActivity(), new Observer<List<Food>>() {
#Override
public void onChanged(List<Food> foods) {
foodAdapter.setFoods(foods);
foodList=foods;
foodAdapter.notifyDataSetChanged(); //TODO: MAKE THIS BETTER
}
});
//setting up the frameLayout
frameLayout = v.findViewById(R.id.food_editor_frame);
//setting up the Add button
add_button=v.findViewById(R.id.add_button);
add_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //for new food addition to list
openFoodEditorFragment(-1);
}
});
foodAdapter.setOnFoodcardClickListener(new FoodAdapter.OnFoodcardClickListener() {
#Override
public void deleteFood(int position) { //code that deletes current food
foodViewModel.delete(foodList.get(position));
foodAdapter.notifyItemRemoved(position);
}
#Override
public void onEdit(int position) { //code that runs the edit of each food
openFoodEditorFragment(position);
foodAdapter.notifyItemChanged(position);
}
#Override
public void decrease(int position) {
foodList.get(position).decrease();
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
#Override
public void increase(int position) {
foodList.get(position).increase();
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
#Override
public void setSeekBar(int position,int progress) {
foodList.get(position).setQuantity(progress);
foodViewModel.update(foodList.get(position));
foodAdapter.notifyItemChanged(position);
}
});
return v;
}
public void openFoodEditorFragment(int position){ //position = -1 for new, and an integer (position) for edit
FoodEditorFragment foodEditorFragment;
switch(position){
case -1:
foodEditorFragment = new FoodEditorFragment(foodViewModel);
break;
default:
foodEditorFragment = new FoodEditorFragment(foodList.get(position),foodViewModel);
break;
}
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
transaction.commit();
}
}
RecyclerView's adapter:
package com.coffeetech.kittycatch;
import android.app.Application;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.FoodViewHolder> {
//VARIABLE THAT CONTAINS THE FOOD LIST (array list)
public List<Food> foods;
int size;
private OnFoodcardClickListener onFoodcardClickListener;
//listener interface
public interface OnFoodcardClickListener{
void deleteFood(int position);
void onEdit(int position);
void decrease(int position);
void increase(int position);
void setSeekBar(int position, int progress);
}
public void setOnFoodcardClickListener(OnFoodcardClickListener activity){ //this is called in MainActivity
onFoodcardClickListener=activity;
}
public FoodAdapter(List<Food>foods){
this.foods=foods;
}
public static class FoodViewHolder extends RecyclerView.ViewHolder{
//VARIABLES FOR EACH WIDGET IN FOODCARD
TextView name,quantity; //to modify according to current food
ImageButton decreaseButton,increaseButton; //to hide or show
SeekBar seekbar; //according to current type
ImageButton deleteButton,editButton;
public FoodViewHolder(#NonNull View itemView, final OnFoodcardClickListener listener) {//'itemView' is the card
super(itemView);
name=itemView.findViewById(R.id.name);
quantity=itemView.findViewById(R.id.quantity);
decreaseButton=itemView.findViewById(R.id.decrease_button);
increaseButton=itemView.findViewById(R.id.increase_button);
seekbar=itemView.findViewById(R.id.seekbar);
deleteButton=itemView.findViewById(R.id.delete_button);
editButton=itemView.findViewById(R.id.edit_button);
editButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.onEdit(position);
}
}
}
});
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.deleteFood(position);
}
}
}
});
decreaseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.decrease(position);
}
}
}
});
increaseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.increase(position);
}
}
}
});
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
if(listener!=null){
int position=getAdapterPosition();
if (position!= RecyclerView.NO_POSITION){
listener.setSeekBar(position,seekBar.getProgress());
}
}
}
});
}
}
#NonNull
#Override
public FoodViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.foodcard, parent, false); //inflating Foodcard
FoodViewHolder vw = new FoodViewHolder(v,onFoodcardClickListener);
return vw;
}
#Override
public void onBindViewHolder(#NonNull FoodViewHolder holder, int position) { //'holder' is the foodcard here
Food currentFood=foods.get(position);
holder.name.setText(currentFood.getName());
holder.quantity.setText(String.valueOf(currentFood.getQuantity()));
holder.seekbar.setProgress(currentFood.getQuantity());
//code to hide or show certain widgets based on food type
if(currentFood.getType()==0){ //for discrete food
holder.increaseButton.setVisibility(View.VISIBLE);
holder.decreaseButton.setVisibility(View.VISIBLE);
holder.quantity.setVisibility(View.VISIBLE);
holder.seekbar.setVisibility(View.GONE);
}else{// for continuous food
holder.increaseButton.setVisibility(View.GONE);
holder.decreaseButton.setVisibility(View.GONE);
holder.quantity.setVisibility(View.GONE);
holder.seekbar.setVisibility(View.VISIBLE);
}
}
#Override
public int getItemCount() {
return size;
}
//FUCNTION TO GET LIVE DATA HERE
public void setFoods (List<Food> foods){
this.foods=foods;
notifyDataSetChanged();
}
}
Food Editor Fragment:
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class FoodEditorFragment extends Fragment {
private TextView name,quantity,min_quantity;
private ImageButton save,cancel;
private RadioGroup radioGroup;
protected int t,mode;
protected Food food;
FoodViewModel foodViewModel;
public FoodEditorFragment() {
// Required empty public constructor
}
public FoodEditorFragment (Food food, FoodViewModel foodViewModel){
this.food=food;
this.foodViewModel=foodViewModel;
mode=1;
}
public FoodEditorFragment (FoodViewModel foodViewModel){
this.foodViewModel=foodViewModel;
this.food = new Food();
mode=0;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_food_editor, container, false);
name=view.findViewById(R.id.name_editor);
quantity=view.findViewById(R.id.quantity_editor);
min_quantity=view.findViewById(R.id.min_quantity_editor);
save=view.findViewById(R.id.save_button_editor);
cancel=view.findViewById(R.id.cancel_button_editor);
radioGroup=view.findViewById(R.id.radioGroup_editor);
if (mode==1){ //for editing Food
//CODE TO SETUP EDITOR ACCORDING TO INITIAL DETAILS
name.setText(food.getName());
quantity.setText(String.valueOf(food.getQuantity()));
min_quantity.setText(String.valueOf(food.getMin_quantity()));
t=food.getType();
if(t==0){//for discrete food
radioGroup.check(R.id.discrete_radioButton);
}else{//for cont food
radioGroup.check(R.id.cont_radioButton);
}
}
setButtons();
return view;
}
public void setButtons(){
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //USE BELOW 'food' TO PASS NEW DATA TO ACTIVITY
try {
if ((!name.getText().toString().isEmpty()) && ((radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) || (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton))) {
food.setName(name.getText().toString());
food.setQuantity(Integer.parseInt(quantity.getText().toString()));
food.setMin_quantity(Integer.parseInt(min_quantity.getText().toString()));
if (radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) {
food.setType(0);
} else if (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton) {
food.setType(1);
}
switch (mode){
case 0:
foodViewModel.insert(food);
break;
case 1:
foodViewModel.update(food);
break;
}
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
} else {
throw new Exception();
}
}catch (Exception e){
Toast.makeText(getContext(),"Please set all details",Toast.LENGTH_SHORT).show();
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //CODE IF USER PRESSES ON CANCEL
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
}
});
}
}
ViewModel I am using:
package com.coffeetech.kittycatch;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import java.util.ArrayList;
import java.util.List;
public class FoodViewModel extends AndroidViewModel {
private FoodRepository repository;
private LiveData<List<Food>> foods;
public FoodViewModel(#NonNull Application application) {
super(application);
repository = new FoodRepository(application);
foods=repository.getAll();
}
public void insert(Food food){
repository.insert(food);
}
public void update(Food food){
repository.update(food);
}
public void delete(Food food){
repository.delete(food);
}
public void deleteAll(){
repository.deleteAll();
}
public LiveData<List<Food>> getFoods(){
return foods;
}
public LiveData<List<Food>> getBuying () {return repository.getBuying();}
}
In FoodAdapter's getItemCount() method, You set itemcount static. You have to change it to foods.size()
Related
I have an app, where I have one Activity (main), and there in the layout, I have a ViewPager2. That ViewPager2's adapter is set with 2 fragments. Let's call one of these as Fragment A.
When Fragment A opens up, users have the option to open another fragment, Fragment B from within itself. (by transaction; I have an empty FrameLayout inside Fragment A). Fragment B provides a dialog box to edit the data shown with a RecyclerView in Fragment A. Fragment A itself also has a few options to change the data in its RecyclerView.
This data is populated from Shared preferences. Now, here's the problem - since the Fragments can be made to communicate only with the Activity with Interfaces, I can save the data in the Activity, but then I have no other option but to reload the entire RecyclerView in Fragment A since Fragment A doesn't know at which position it got the new data.
Please advice. Below are the Fragments and the Activity that I mentioned.
MainActivity.java:
package com.coffeetech.kittycatch;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity implements FoodEditorFragment.SendFoodFromEditor{
ViewPager2 viewPager;
TabLayout tab_menu;
SwipeAdapter adapter;
ArrayList<Food> foods;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager=findViewById(R.id.viewpager);
adapter=new SwipeAdapter(this);
viewPager.setAdapter(adapter);
//SETTING TABS
tab_menu = findViewById(R.id.tab_menu);
new TabLayoutMediator(tab_menu, viewPager, true, new TabLayoutMediator.TabConfigurationStrategy() {
#Override
public void onConfigureTab(#NonNull TabLayout.Tab tab, int position) {
switch(position){
case 0:
tab.setText("INVENTORY");
break;
case 1:
tab.setText("SHOPPING LIST");
}
}
}).attach();
}
#Override
public void onBackPressed() {
super.onBackPressed(); //TODO: CONFIGURE THIS
}
#Override
public void sendFood(Food food, int position) { //TODO: CODE TO REPLACE DATA TO SPECIFIC POSITION
loadData();
saveData();
}
#Override
public void sendFood(Food food) { //TODO: CODE TO ADD DATA TO POSITION 0
loadData();
saveData();
}
public void loadData(){
//TODO: LOAD THE LIST HERE
}
public void saveData(){
//TODO: SAVE THE DATA HERE
}
}
The FragmentStateAdapter for the ViewPager2:
package com.coffeetech.kittycatch;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
public class SwipeAdapter extends FragmentStateAdapter {
Fragment fragment;
public SwipeAdapter(FragmentActivity fa){
super(fa);
}
#NonNull
#Override
public Fragment createFragment(int position) {
switch (position){
case 0: //START INVENTORY FRAGMENT
fragment = new InventoryFragment();
break;
case 1: //START SHOPPING LIST FRAGMENT
fragment = new ShoppingListFragment();
break;
}
return fragment;
}
#Override
public int getItemCount() {
return 2;
}
}
Fragment 'A':
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
public class InventoryFragment extends Fragment {
//GLOBAL VARIABLES
RecyclerView recyclerView;
FoodAdapter foodAdapter;
ArrayList<Food> foods = new ArrayList<Food>();
FloatingActionButton add_button;
FrameLayout frameLayout;
Food food;
int q; //for use in decrease and functions
public InventoryFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onPause() { //TODO:CODE TO SAVE DATA
saveData();
super.onPause();
}
#Override
public void onResume() { //TODO:CODE TO LOAD DATA
loadData();
super.onResume();
//food constructor takes arguments -> (String name, int type, int quantity, int min_quantity)
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_inventory, container, false);
foodAdapter = new FoodAdapter(foods);
recyclerView=v.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(foodAdapter);
//setting up the frameLayout
frameLayout = v.findViewById(R.id.food_editor_frame);
//setting up the Add button
add_button=v.findViewById(R.id.add_button);
add_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //for new food addition to list
openFoodEditorFragment();
}
});
foodAdapter.setOnFoodcardClickListener(new FoodAdapter.OnFoodcardClickListener() {
#Override
public void deleteFood(int position) { //code that deletes current food
foods.remove(position);
foodAdapter.notifyItemRemoved(position);
}
#Override
public void onEdit(int position, int mode) { //code that runs the edit of each food, mode=1 for edit
openFoodEditorFragment(position,foods.get(position)); //TODO: SEE IF YOU NEED 'mode' AT ALL
}
#Override
public void decrease(int position) {
food = foods.get(position);
q=food.getQuantity();
food.setQuantity(q-1);
foodAdapter.notifyItemChanged(position);
}
#Override
public void increase(int position) {
food = foods.get(position);
q=food.getQuantity();
food.setQuantity(q+1);
foodAdapter.notifyItemChanged(position);
}
#Override
public void setSeekBar(int position,int progress) {
food = foods.get(position);
food.setQuantity(progress);
Toast.makeText(getContext(),"Quantity set to "+progress+"%",Toast.LENGTH_SHORT).show();
foodAdapter.notifyItemChanged(position);
}
});
return v;
}
public void openFoodEditorFragment(int position,Food food){ //code for Editor in Edit Old mode
//creating new Bundle and passing each member data of 'food'
Bundle bundle = new Bundle();
bundle.putString("name",food.getName());
bundle.putInt("type",food.getType());
bundle.putInt("quantity",food.getQuantity());
bundle.putInt("min_quantity",food.getMin_quantity());
bundle.putInt("mode",1);
bundle.putInt("position",position);
//setting up arguments for Fragment
FoodEditorFragment foodEditorFragment = new FoodEditorFragment();
foodEditorFragment.setArguments(bundle);
//creating the Fragment
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
transaction.commit();
}
public void openFoodEditorFragment(){ //code for Editor in Add New mode
//creating new Bundle and passing each member data of 'food'
Bundle bundle = new Bundle();
bundle.putInt("position",0);
bundle.putInt("mode",0);
//setting up arguments for Fragment
FoodEditorFragment foodEditorFragment = new FoodEditorFragment();
foodEditorFragment.setArguments(bundle);
//creating the Fragment
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
transaction.commit();
}
protected void setData(int position, Food food){
foods.remove(position);
foods.add(position,food);
foodAdapter.notifyItemChanged(position);
}
protected void setData(Food food){
foods.add(0,food);
foodAdapter.notifyItemInserted(0);
Toast.makeText(getContext(),"Added to the top",Toast.LENGTH_SHORT).show();
}
void loadData(){
//TODO: CODE TO LOAD DATA
}
void saveData(){
//TODO: CODE TO SAVE DATA
}
}
Fragment 'B':
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class FoodEditorFragment extends Fragment {
private TextView name,quantity,min_quantity;
private ImageButton save,cancel;
private RadioGroup radioGroup;
protected int mode,t,position;
protected Food food = new Food();
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
sffe = (SendFoodFromEditor)context;
}
public FoodEditorFragment() {
// Required empty public constructor
}
public interface SendFoodFromEditor{
void sendFood(Food food,int position); //FOR EDITING FOOD
void sendFood(Food food); //FOR NEW FOOD
}
SendFoodFromEditor sffe;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_food_editor, container, false);
name=view.findViewById(R.id.name_editor);
quantity=view.findViewById(R.id.quantity_editor);
min_quantity=view.findViewById(R.id.min_quantity_editor);
save=view.findViewById(R.id.save_button_editor);
cancel=view.findViewById(R.id.cancel_button_editor);
radioGroup=view.findViewById(R.id.radioGroup_editor);
mode=getArguments().getInt("mode");
position=getArguments().getInt("position");
if (mode==1){ //for editing Food
//CODE TO SETUP EDITOR ACCORDING TO INITIAL DETAILS
name.setText(getArguments().getString("name"));
quantity.setText(String.valueOf(getArguments().getInt("quantity")));
min_quantity.setText(String.valueOf(getArguments().getInt("min_quantity")));
t=getArguments().getInt("type");
if(t==0){//for discrete food
radioGroup.check(R.id.discrete_radioButton);
}else{//for cont food
radioGroup.check(R.id.cont_radioButton);
}
}
setButtons();
return view;
}
public void setButtons(){
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //USE BELOW 'food' TO PASS NEW DATA TO ACTIVITY
try {
if ((!name.getText().toString().isEmpty()) && ((radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) || (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton))) {
food.setName(name.getText().toString());
food.setQuantity(Integer.parseInt(quantity.getText().toString()));
food.setMin_quantity(Integer.parseInt(min_quantity.getText().toString()));
if (radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) {
food.setType(0);
} else if (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton) {
food.setType(1);
}
//CODE TO SEND THE FOOD TO ACTIVITY
if (mode == 1) {
sffe.sendFood(food, position);
} else {
sffe.sendFood(food);
}
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
} else {
throw new Exception();
}
}catch (Exception e){
Toast.makeText(getContext(),"Please set all details",Toast.LENGTH_SHORT).show();
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //CODE IF USER PRESSES ON CANCEL
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
}
});
}
}
You need to make following changes.
In Fragment A,
Replace
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
With
transaction.add(R.id.food_editor_frame,foodEditorFragment);
Reason: using replace will remove the fragmentA and FragmentA will always be recreated.
In MainActivity
#Override
public void sendFood(Food food, int position){
//find fragment by Id
Fragment fragmentA = (Fragment)
getSupportFragmentManager().findFragmentById(R.id.fragmetnA);
fragment.setData(position,food)
//code for save data here
}
#Override
public void sendFood(Food food) {
Fragment fragmentA = (Fragment)
getSupportFragmentManager().findFragmentById(R.id.fragmetnA);
fragment.setData(food)
//code for save data here
}
I've been working on a messaging app and within the group and private chat, the first message duplicates and then when another message is sent, it's hidden behind the duplicated text until another one is sent and then so on. Can anybody help me with this problem? I'm using Quickblox as a database
ChatMessage Class
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.v7.app.AlertDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.Toast;
import com.liftersheaven.messaging.Adapter.ChatMessageAdapter;
import com.liftersheaven.messaging.Common.Common;
import com.liftersheaven.messaging.Holder.QBChatMessagesHolder;
import com.quickblox.chat.QBChatService;
import com.quickblox.chat.QBIncomingMessagesManager;
import com.quickblox.chat.QBRestChatService;
import com.quickblox.chat.exception.QBChatException;
import com.quickblox.chat.listeners.QBChatDialogMessageListener;
import com.quickblox.chat.model.QBChatDialog;
import com.quickblox.chat.model.QBChatMessage;
import com.quickblox.chat.model.QBDialogType;
import com.quickblox.chat.request.QBDialogRequestBuilder;
import com.quickblox.chat.request.QBMessageGetBuilder;
import com.quickblox.chat.request.QBMessageUpdateBuilder;
import com.quickblox.core.QBEntityCallback;
import com.quickblox.core.exception.QBResponseException;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smackx.muc.DiscussionHistory;
import java.util.ArrayList;
public class ChatMessage extends AppCompatActivity implements
QBChatDialogMessageListener{
QBChatDialog qbChatDialog;
ListView lstChatMessages;
ImageButton submitButton;
EditText edtContent;
ChatMessageAdapter adapter;
int contextMenuIndexClicked = -1;
boolean isEditMode = false;
QBChatMessage editMessage;
Toolbar toolbar;
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId()){
case R.id.chat_group_edit_name:
editNameGroup();
break;
case R.id.chat_group_add_user:
addUser();
break;
case R.id.chat_group_remove_user:
removeUser();
break;
}
return true;
}
private void removeUser() {
Intent intent = new Intent(this,ListUsers.class);
intent.putExtra(Common.UPDATE_DIALOG_EXTRA, qbChatDialog);
intent.putExtra(Common.UPDATE_MODE, Common.UPDATE_REMOVE_MODE);
startActivity(intent);
}
private void addUser() {
Intent intent = new Intent(this,ListUsers.class);
intent.putExtra(Common.UPDATE_DIALOG_EXTRA, qbChatDialog);
intent.putExtra(Common.UPDATE_MODE,Common.UPDATE_ADD_MODE);
startActivity(intent);
}
private void editNameGroup() {
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.dialog_edit_group_layout, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setView(view);
final EditText newName = (EditText) view.findViewById(R.id.edt_group_name);
alertDialogBuilder.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
qbChatDialog.setName(newName.getText().toString());
QBDialogRequestBuilder requestBuilder = new QBDialogRequestBuilder();
QBRestChatService.updateGroupChatDialog(qbChatDialog, requestBuilder)
.performAsync(new QBEntityCallback<QBChatDialog>() {
#Override
public void onSuccess(QBChatDialog qbChatDialog, Bundle bundle) {
Toast.makeText(ChatMessage.this, "Group name edited", Toast.LENGTH_SHORT);
toolbar.setTitle(qbChatDialog.getName());
}
#Override
public void onError(QBResponseException e) {
Toast.makeText(getBaseContext(), ""+e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (qbChatDialog.getType() == QBDialogType.GROUP || qbChatDialog.getType() == QBDialogType.PUBLIC_GROUP)
getMenuInflater().inflate(R.menu.chat_message_group_menu, menu);
return true;
}
#Override
public boolean onContextItemSelected(MenuItem item){
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
contextMenuIndexClicked = info.position;
switch (item.getItemId()){
case R.id.chat_message_update:
updateMessage();
break;
case R.id.chat_message_delete:
deleteMessage();
break;
}
return true;
}
private void deleteMessage() {
final ProgressDialog deleteDialog = new ProgressDialog(ChatMessage.this);
deleteDialog.setMessage("Please wait...");
deleteDialog.show();
editMessage = QBChatMessagesHolder.getInstance().getChatMessagesByDialogId(qbChatDialog.getDialogId())
.get(contextMenuIndexClicked);
QBRestChatService.deleteMessage(editMessage.getId(),false).performAsync(new QBEntityCallback<Void>() {
#Override
public void onSuccess(Void aVoid, Bundle bundle) {
retrieveAllMessage();
deleteDialog.dismiss();
}
#Override
public void onError(QBResponseException e) {
}
});
}
private void updateMessage() {
editMessage = QBChatMessagesHolder.getInstance().getChatMessagesByDialogId(qbChatDialog.getDialogId())
.get(contextMenuIndexClicked);
edtContent.setText(editMessage.getBody());
isEditMode = true;
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo){
getMenuInflater().inflate(R.menu.chat_message_content_menu, menu);
}
#Override
protected void onDestroy(){
super.onDestroy();
qbChatDialog.removeMessageListrener(this);
}
#Override
protected void onStop(){
super.onStop();
qbChatDialog.removeMessageListrener(this);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_message);
initViews();
initChatDialogs();
retrieveAllMessage();
submitButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!edtContent.getText().toString().isEmpty()){
if (!isEditMode) {
QBChatMessage chatMessage = new QBChatMessage();
chatMessage.setBody(edtContent.getText().toString());
chatMessage.setSenderId(QBChatService.getInstance().getUser().getId());
chatMessage.setSaveToHistory(true);
try {
qbChatDialog.sendMessage(chatMessage);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
if (qbChatDialog.getType() == QBDialogType.PRIVATE){
QBChatMessagesHolder.getInstance().putMessage(qbChatDialog.getDialogId(),chatMessage);
ArrayList<QBChatMessage> messages = QBChatMessagesHolder.getInstance().getChatMessagesByDialogId(chatMessage.getDialogId());
adapter = new ChatMessageAdapter(getBaseContext(),messages);
lstChatMessages.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
edtContent.setText("");
edtContent.setFocusable(true);
}else
{
final ProgressDialog updateDialog = new ProgressDialog(ChatMessage.this);
updateDialog.setMessage("Please wait...");
updateDialog.show();
QBMessageUpdateBuilder messageUpdateBuilder = new QBMessageUpdateBuilder();
messageUpdateBuilder.updateText(edtContent.getText().toString()).markDelivered().markRead();
QBRestChatService.updateMessage(editMessage.getId(),qbChatDialog.getDialogId(),messageUpdateBuilder)
.performAsync(new QBEntityCallback<Void>() {
#Override
public void onSuccess(Void aVoid, Bundle bundle) {
retrieveAllMessage();
isEditMode = false;
updateDialog.dismiss();
edtContent.setText("");
edtContent.setFocusable(true);
}
#Override
public void onError(QBResponseException e) {
Toast.makeText(getBaseContext(),""+e.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
}
}
});
}
private void retrieveAllMessage() {
QBMessageGetBuilder messageGetBuilder = new QBMessageGetBuilder();
messageGetBuilder.setLimit(500);
if(qbChatDialog != null){
QBRestChatService.getDialogMessages(qbChatDialog,messageGetBuilder).performAsync(new QBEntityCallback<ArrayList<QBChatMessage>>() {
#Override
public void onSuccess(ArrayList<QBChatMessage> qbChatMessages, Bundle bundle) {
QBChatMessagesHolder.getInstance().putMessages(qbChatDialog.getDialogId(),qbChatMessages);
adapter = new ChatMessageAdapter(getBaseContext(),qbChatMessages);
lstChatMessages.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onError(QBResponseException e) {
}
});
}
}
private void initChatDialogs() {
qbChatDialog = (QBChatDialog)getIntent().getSerializableExtra(Common.DIALOG_EXTRA);
qbChatDialog.initForChat(QBChatService.getInstance());
QBIncomingMessagesManager incomingMessage = QBChatService.getInstance().getIncomingMessagesManager();
incomingMessage.addDialogMessageListener(new QBChatDialogMessageListener() {
#Override
public void processMessage(String s, QBChatMessage qbChatMessage, Integer integer) {
}
#Override
public void processError(String s, QBChatException e, QBChatMessage qbChatMessage, Integer integer) {
}
});
if (qbChatDialog.getType() == QBDialogType.PUBLIC_GROUP || qbChatDialog.getType() == QBDialogType.GROUP){
DiscussionHistory discussionHistory = new DiscussionHistory();
discussionHistory.setMaxStanzas(0);
qbChatDialog.join(discussionHistory, new QBEntityCallback() {
#Override
public void onSuccess(Object o, Bundle bundle) {
}
#Override
public void onError(QBResponseException e) {
Log.d("ERROR", ""+e.getMessage());
}
});
}
qbChatDialog.addMessageListener(this);
toolbar.setTitle(qbChatDialog.getName());
setSupportActionBar(toolbar);
}
private void initViews() {
lstChatMessages = (ListView)findViewById(R.id.messages_list);
submitButton = (ImageButton)findViewById(R.id.send);
edtContent = (EditText)findViewById(R.id.edt_content);
registerForContextMenu(lstChatMessages);
toolbar = (Toolbar)findViewById(R.id.chatmessage_toolbar);
}
#Override
public void processMessage(String s, QBChatMessage qbChatMessage, Integer integer) {
QBChatMessagesHolder.getInstance().putMessage(qbChatMessage.getDialogId(),qbChatMessage);
ArrayList<QBChatMessage> messages = QBChatMessagesHolder.getInstance().getChatMessagesByDialogId(qbChatMessage.getDialogId());
adapter = new ChatMessageAdapter(getBaseContext(),messages);
lstChatMessages.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void processError(String s, QBChatException e, QBChatMessage qbChatMessage, Integer integer) {
Log.e("ERROR",""+e.getMessage());
}
}
ChatMessageAdapter Class
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.github.library.bubbleview.BubbleTextView;
import com.liftersheaven.messaging.Holder.QBUsersHolder;
import com.liftersheaven.messaging.R;
import com.quickblox.chat.QBChatService;
import com.quickblox.chat.model.QBChatMessage;
import java.util.ArrayList;
public class ChatMessageAdapter extends BaseAdapter {
private Context context;
private ArrayList<QBChatMessage> qbChatMessages;
public ChatMessageAdapter(Context context, ArrayList<QBChatMessage> qbChatMessages){
this.context = context;
this.qbChatMessages = qbChatMessages;
}
#Override
public int getCount() {
return qbChatMessages.size();
}
#Override
public Object getItem(int position) {
return qbChatMessages.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null){
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (qbChatMessages.get(position).getSenderId().equals(QBChatService.getInstance().getUser().getId())){
view = inflater.inflate(R.layout.list_message_send, null);
BubbleTextView bubbleTextView = (BubbleTextView)view.findViewById(R.id.message_content);
bubbleTextView.setText(qbChatMessages.get(position).getBody());
}
else{
view = inflater.inflate(R.layout.list_recieve_message, null);
BubbleTextView bubbleTextView = (BubbleTextView)view.findViewById(R.id.message_recieve);
bubbleTextView.setText(qbChatMessages.get(position).getBody());
TextView txtName = (TextView)view.findViewById(R.id.message_user);
txtName.setText(QBUsersHolder.getInstance().getUserById(qbChatMessages.get(position).getSenderId()).getFullName());
}
}
return view;
}
}
QBChatMessagesHolder Class
import com.quickblox.chat.model.QBChatMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class QBChatMessagesHolder {
private static QBChatMessagesHolder instance;
private HashMap<String,ArrayList<QBChatMessage>> qbChatMessageArray;
public static synchronized QBChatMessagesHolder getInstance(){
QBChatMessagesHolder qbChatMessagesHolder;
synchronized (QBChatMessagesHolder.class){
if (instance == null)
instance = new QBChatMessagesHolder();
qbChatMessagesHolder = instance;
}
return qbChatMessagesHolder;
}
private QBChatMessagesHolder(){
this.qbChatMessageArray = new HashMap<>();
}
public void putMessages(String dialogId,ArrayList<QBChatMessage> qbChatMessages){
this.qbChatMessageArray.put(dialogId,qbChatMessages);
}
public void putMessage(String dialogId,QBChatMessage qbChatMessage){
List<QBChatMessage> lstResult = (List)this.qbChatMessageArray.get(dialogId);
lstResult.add(qbChatMessage);
ArrayList<QBChatMessage> lstAdded = new ArrayList(lstResult.size());
lstAdded.addAll(lstResult);
putMessages(dialogId, lstAdded);
}
public ArrayList<QBChatMessage> getChatMessagesByDialogId(String dialogId){
return (ArrayList<QBChatMessage>)this.qbChatMessageArray.get(dialogId);
}
}
I have a RecyclerView and each item is a button. Each button will call the same activity by passing a different parameter to this activity.
I tried many solutions found on the web but none of them had worked for me.
Here is my adapter :
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import java.util.List;
public class FormAdapter extends RecyclerView.Adapter<FormAdapter.FormViewHolder> {
private List<Form> forms;
private int rowLayout;
private Context context;
public class FormViewHolder extends RecyclerView.ViewHolder {
LinearLayout formsLayout;
Button form;
public FormViewHolder(View v) {
super(v);
formsLayout = (LinearLayout) v.findViewById(R.id.forms_layout);
form = (Button) v.findViewById(R.id.formButton);
}
}
public FormAdapter(List<Form> forms, int rowLayout, Context context) {
this.forms = forms;
this.rowLayout = rowLayout;
this.context = context;
}
#Override
public FormAdapter.FormViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
return new FormViewHolder(view);
}
#Override
public void onBindViewHolder(FormViewHolder holder, final int position) {
holder.form.setText(forms.get(position).getSubject());
}
#Override
public int getItemCount() {
return forms.size();
}
}
A form is represented by the following class :
public class Form {
private final String subject;
private final int idForm;
public Form(String subject,int idForm)
{
this.idForm=idForm;
this.subject=subject;
}
public String getSubject()
{
return subject;
}
public int getIdForm()
{
return idForm;
}
}
And here is my MainActivity :
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private final static int idCreator = 1;
private FormAdapter formAdapter;
private List<Form> forms;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Main activity");
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerViewForm);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
Formable formService =
ApiClient.getClient().create(Formable.class);
Call<List<Form>> call = formService.getForms(idCreator);
call.enqueue(new Callback<List<Form>>() {
#Override
public void onResponse(Call<List<Form>> call, Response<List<Form>> response) {
forms = response.body();
formAdapter=new FormAdapter(forms, R.layout.one_form, getApplicationContext());
recyclerView.setAdapter(formAdapter);
}
#Override
public void onFailure(Call<List<Form>> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
}
I have my buttons on screen but I don't understand how to make them call the activity "QuestionsActivity" with a parameter "idForm" that I know.
Here is the MainActivity when I run the app
Thanks in advance for your help
You can get item data by following way when you click on recyclerview item:
Create Interface in your adapter and use it in your activity:
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
Now Your code look like below:
FormAdapter.java
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import java.util.List;
public class FormAdapter extends RecyclerView.Adapter<FormAdapter.FormViewHolder> {
private List<Form> forms;
private int rowLayout;
private Context context;
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
public class FormViewHolder extends RecyclerView.ViewHolder {
LinearLayout formsLayout;
Button form;
public FormViewHolder(View v) {
super(v);
formsLayout = (LinearLayout) v.findViewById(R.id.forms_layout);
form = (Button) v.findViewById(R.id.formButton);
}
}
public FormAdapter(List<Form> forms, int rowLayout, Context context) {
this.forms = forms;
this.rowLayout = rowLayout;
this.context = context;
}
#Override
public FormAdapter.FormViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
return new FormViewHolder(view);
}
#Override
public void onBindViewHolder(FormViewHolder holder, final int position) {
holder.form.setText(forms.get(position).getSubject());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(mListener!=null)
{
mListener.onItemClick(view,position);
}
}
});
}
#Override
public int getItemCount() {
return forms.size();
}
public void setOnItemClick(OnItemClickListener listener)
{
this.mListener=listener;
}
}
MainActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import com.newstory.android.R;
import com.newstory.android.activity.FormAdapter;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private final static int idCreator = 1;
private FormAdapter formAdapter;
private List<Form> forms;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Main activity");
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerViewForm);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
Formable formService =
ApiClient.getClient().create(Formable.class);
Call<List<Form>> call = formService.getForms(idCreator);
call.enqueue(new Callback<List<Form>>() {
#Override
public void onResponse(Call<List<Form>> call, Response<List<Form>> response) {
forms = response.body();
formAdapter=new FormAdapter(forms, R.layout.one_form, getApplicationContext());
recyclerView.setAdapter(formAdapter);
setOnItemListener();
}
#Override
public void onFailure(Call<List<Form>> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
public void setOnItemListener(){
if(formAdapter!=null)
{
formAdapter.setOnItemClick(new FormAdapter.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Form clickedForm=forms.get(position);
// You can call QuestionsActivity here
//Now you can access [Form] data
Log.d("getIdForm->",String.valueOf(clickedForm.getIdForm()))
}
});
}
}
}
I hope it's helps you.
Do this way :
form.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// do something when the form is clicked
context.startActivity(new Intent(context, YourActivity.class)
.putExtra("idForm", someValue));
}
});
In your adapter's onBindViewHolder method, assign a click listener to the button view element, so it would look something like this:
#Override
public void onBindViewHolder(FormViewHolder holder, final int position {
holder.form.setText(forms.get(position).getSubject());
holder.form.setOnClickListener(v -> {
startQuestionsWithId(forms.get(position).getIdForm);
});
}
And then, your startQuestionsWithIdmethod would typically be like:
private void startQuestionsWithId(int idForm) {
Intent intent = new Intent(context, QuestionsActivity.class);
intent.putExtra("id_form", idForm);
context.startActivity(intent);
}
I am using recycler view for products. I want to display product description on recycler item click.
I also put a button and checkbox(favorite) on recyclerview row.
Now i required to get click event of all, means i want recyclerview item click and child control click.
My layout is look like this :
RecyclerView Touch event
productRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
final int action = e.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
if (actionMasked == MotionEvent.ACTION_DOWN) {
return false;
} else if (actionMasked == MotionEvent.ACTION_UP) {
HomeActivity.productclicked = (productDatas.get
(2));
HomeActivity.loadView(new SingleProductFragment(), "SingleProduct");
return false; //intercepted by the viewgroup and passed down to child
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
In Adapter Add to Cart Button click
viewHolder.cart_action.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
UserCart.addProductToCart(Integer.parseInt(view.getTag().toString()));
HomeActivity.increaseCartCount();
}
});
If i didn't implement touchlistener on recyclerview then every button will work else it didn't work.
Basically i want to know how to implement click on recyclerview item and its child
For information i also using Scroll Listener over RecyclerView. But i thought it didn't affect to click events
My Adapter Class
package net.techdesire.swarnasikha.adapter_package;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.facebook.common.soloader.SoLoaderShim;
import com.facebook.common.util.UriUtil;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import net.techdesire.swarnasikha.R;
import net.techdesire.swarnasikha.activity_package.HomeActivity;
import net.techdesire.swarnasikha.data_package.ProductData;
import net.techdesire.swarnasikha.data_package.UserCart;
import net.techdesire.swarnasikha.fragments_package.SingleProductFragment;
import java.util.ArrayList;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Created by Naitik Kundalia on 2/28/2017.
*/
public class ProductDataAdapter extends RecyclerView.Adapter<ProductDataAdapter
.ProductViewHolder> {
private ArrayList<ProductData> productDataArrayList;
private Context context;
public ProductDataAdapter(Context context, ArrayList<ProductData> countries) {
this.context=context;
this.productDataArrayList = countries;
}
#Override
public ProductDataAdapter.ProductViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_product, viewGroup,
false);
return new ProductViewHolder(view);
}
#Override
public void onBindViewHolder(ProductViewHolder viewHolder,final int position) {
try {
ProductData currentProduct = productDataArrayList.get(position);
viewHolder.product_name.setText(currentProduct.getName());
viewHolder.product_image.setImageURI(currentProduct.getImages().get(0).getSrc());
viewHolder.cart_action.setTag(currentProduct.getId());
viewHolder.cart_action.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
UserCart.addProductToCart(Integer.parseInt(view.getTag().toString()));
HomeActivity.increaseCartCount();
}
});
viewHolder.container.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "Clicked", Toast.LENGTH_SHORT).show();
HomeActivity.productclicked=productDataArrayList.get(position);
HomeActivity.loadView(new SingleProductFragment(),"SingleProduct");
}
});
}
catch(Exception ex)
{
Toast.makeText(context, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
}
#Override
public int getItemCount() {
return productDataArrayList.size();
}
public class ProductViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public View container;
public TextView addedtocart;
public TextView product_name;
SimpleDraweeView product_image;
Button cart_action;
public ProductViewHolder(View view) {
super(view);
container=view;
product_name = (TextView)view.findViewById(R.id.row_product_name_textview);
addedtocart = (TextView)view.findViewById(R.id.row_added_to_cart_textview);
product_image=(SimpleDraweeView) view.findViewById(R.id.row_product_imageview);
cart_action=(Button)view.findViewById(R.id.row_cart_action_button);
//view.setOnClickListener(this);
}
public void onClick(View v)
{
Toast.makeText(context, "View Clicked", Toast.LENGTH_SHORT).show();
}
}
}
I have been reading the different answers here on stackoverflow and on this blog post and tried to implement their solutions but I am still getting the error: No adapter attached; skipping layout.
RecyclerAdapter:
package vn.jupviec.frontend.android.monitor.app.ui.candidate;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.w3c.dom.Text;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import butterknife.BindView;
import vn.jupviec.frontend.android.monitor.app.R;
import vn.jupviec.frontend.android.monitor.app.domain.candidate.TrainingDTO;
import vn.jupviec.frontend.android.monitor.app.util.Utils;
/**
* Created by Windows 10 Gamer on 16/12/2016.
*/
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.RecyclerViewHolder> {
private static final String TAG = "RecyclerView";
private List<TrainingDTO> mTrainingDTOs;
private Context mContext;
private LayoutInflater mLayoutInflater;
private String today;
private static final DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
AdapterInterface buttonListener;
public RecyclerAdapter(Context context, List<TrainingDTO> datas, AdapterInterface buttonListener) {
mContext = context;
mTrainingDTOs = datas;
this.mLayoutInflater = LayoutInflater.from(mContext);
this.buttonListener = buttonListener;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.candidate_item, parent, false);
// View itemView = mLayoutInflater.inflate(R.layout.candidate_item, parent, false);
return new RecyclerViewHolder(itemView);
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
final ObjectMapper mapper = new ObjectMapper();
final TrainingDTO trainingDTO = mapper.convertValue(mTrainingDTOs.get(position), TrainingDTO.class);
holder.tvName.setText(trainingDTO.getMaidName());
holder.status.setVisibility(View.GONE);
Date date = new Date();
String currentDate = sdf.format(date);
for (TrainingDTO.TrainingDetailDto td : trainingDTO.getListTrain()) {
today = Utils.formatDate((long) td.getTrainingDate(),"dd/MM/yyyy");
break;
}
if(currentDate.equals(today)) {
holder.status.setVisibility(View.VISIBLE);
holder.status.setText("(Mới)");
}
holder.btnHistory.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext,R.string.msg_no_candidate_history,Toast.LENGTH_SHORT).show();
}
});
holder.btnTest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
buttonListener.showComment(trainingDTO);
}
});
}
#Override
public int getItemCount() {
int size ;
if(mTrainingDTOs != null && !mTrainingDTOs.isEmpty()) {
size = mTrainingDTOs.size();
}
else {
size = 0;
}
return size;
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView tvName;
private Button btnTest;
private Button btnHistory;
private TextView status;
public RecyclerViewHolder(View itemView) {
super(itemView);
tvName = (TextView) itemView.findViewById(R.id.txtName);
btnTest = (Button) itemView.findViewById(R.id.btnTest);
btnHistory = (Button) itemView.findViewById(R.id.btnHistory);
status = (TextView)itemView.findViewById(R.id.status);
}
}
public boolean removeItem(int position) {
if (mTrainingDTOs.size() >= position + 1) {
mTrainingDTOs.remove(position);
return true;
}
return false;
}
public interface AdapterInterface {
void showComment(TrainingDTO trainingDTO);
void showHistory(TrainingDTO trainingDTO);
}
}
FragmentTapNew:
package vn.jupviec.frontend.android.monitor.app.ui.candidate;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;
import vn.jupviec.frontend.android.monitor.app.R;
import vn.jupviec.frontend.android.monitor.app.domain.ResultDTO;
import vn.jupviec.frontend.android.monitor.app.domain.candidate.TrainingDTO;
import vn.jupviec.frontend.android.monitor.app.domain.training.CandidateService;
import vn.jupviec.frontend.android.monitor.app.util.Constants;
import vn.jupviec.frontend.android.monitor.app.util.Utils;
/**
* Created by Windows 10 Gamer on 09/12/2016.
*/
public class FragmentTapNew extends Fragment implements RecyclerAdapter.AdapterInterface {
private static final String TAG = FragmentTapNew.class.getSimpleName();
Activity myContext = null;
private OnItemSelectedListener listener;
ShapeDrawable shapeDrawable;
#BindView(R.id.lvToday)
RecyclerView lvToday;
#BindView(R.id.textView)
TextView textView;
#BindView(R.id.pb_loading)
ProgressBar pbLoading;
private Unbinder unbinder;
private boolean loading = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;
ArrayList<TrainingDTO> mTrainingDTO ;
RecyclerAdapter mTrainingDTOAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_candidate_training, container, false);
unbinder = ButterKnife.bind(this, v);
initViews();
return v;
}
private void initViews() {
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
lvToday.setHasFixedSize(true);
lvToday.setNestedScrollingEnabled(false);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
today();
}
});
t.start();
}
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null) {
Toast.makeText(getActivity(), R.string.err_cannot_establish_connection, Toast.LENGTH_SHORT).show();
return false;
} else
return true;
}
private void today() {
if(isNetworkConnected()){
String token = "a";
Integer date = 0;
setLoadingVisible(true);
CandidateService.getApiDummyClient(getContext()).getCandidate(
token,
date,
Constants.TRAINING,
Arrays.asList(Constants.TRAINING_DAY_NEW),
new Callback<ResultDTO>() {
#Override
public void success(ResultDTO resultDTO, Response response) {
setLoadingVisible(false);
mTrainingDTO = (ArrayList<TrainingDTO>) resultDTO.getData();
if (mTrainingDTO.size() == 0) {
if(textView!=null) {
textView.setVisibility(View.VISIBLE);
textView.setTextColor(Color.RED);
textView.setGravity(Gravity.CENTER | Gravity.BOTTOM);
}
} else {
if(textView!=null) {
textView.setVisibility(View.GONE);
}
if(null==mTrainingDTOAdapter) {
mTrainingDTOAdapter = new RecyclerAdapter(getActivity(), mTrainingDTO, FragmentTapNew.this);
lvToday.setAdapter(mTrainingDTOAdapter);
} else {
lvToday.setAdapter(mTrainingDTOAdapter);
mTrainingDTOAdapter.notifyDataSetChanged();
}
lvToday.invalidate();
}
}
#Override
public void failure(RetrofitError error) {
Log.e(TAG, "JV-ERROR: " + error.getMessage());
Log.e(TAG, "JV-ERROR: " + error.getSuccessType());
}
});
}
}
#Override
public void onResume() {
setLoadingVisible(false);
initViews();
lvToday.setAdapter(mTrainingDTOAdapter);
super.onResume();
}
#Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
private void setLoadingVisible(boolean visible) {
// pbLoading.getIndeterminateDrawable().setColorFilter(0xFFFF0000, android.graphics.PorterDuff.Mode.MULTIPLY);
if(pbLoading!=null) {
pbLoading.setVisibility(visible ? View.VISIBLE : View.GONE);
lvToday.setVisibility(visible ? View.GONE : View.VISIBLE);
}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof OnItemSelectedListener) {
listener = (OnItemSelectedListener) activity;
} else {
throw new ClassCastException(activity.toString()
+ " phải implemenet MyListFragment.OnItemSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
#Override
public void showComment(TrainingDTO trainingDTO) {
Intent intent = new Intent(getContext(), CommentActivity.class);
intent.putExtra(Constants.ARG_NAME_DETAIL, trainingDTO);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
}
#Override
public void showHistory(TrainingDTO trainingDTO) {
Intent intent = new Intent(getContext(), HistoryActivity.class);
intent.putExtra(Constants.ARG_CANDIDATE_HISTORY_DETAIL, trainingDTO);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
}
public interface OnItemSelectedListener {
void showComment(TrainingDTO trainingDTO);
void showHistory(TrainingDTO trainingDTO);
}
}
The first, you don't need to set adapter multiple time, only set adapter at the first time in your method initView().
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
lvToday.setHasFixedSize(true);
lvToday.setNestedScrollingEnabled(false);
if(mTrainingDTO == null) {
mTrainingDTO = new ArrayList<>();
}
if(null == mTrainingDTOAdapter ) {
mTrainingDTOAdapter = new RecyclerAdapter(getActivity(), mTrainingDTO, FragmentTapNew.this);
}
lvToday.setAdapter(mTrainingDTOAdapter);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
today();
}
});
t.start();
After that, you don't need to call lvToday.setAdapter(mTrainingDTOAdapter);
many times. Just call mTrainingDTOAdapter.notifyDataSetChanged(); if having any changes in your data mTrainingDTO.
The errorlog - error:No adapter attached; skipping layout indicates that you've attached LayoutManager but you haven't attached an adapter yet, so recyclerview will skip layout. I'm not sure but, in other words recyclerView will skip layout measuring at the moment.
to prevent this errorLog Try to set an adapter with an empty dataSet i.e. ArrayList or
Attach LayoutManager just before you are setting your adapter.
Try this,
private void initViews() {
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(getActivity());
lvToday.setLayoutManager(mLinearLayoutManager);
lvToday.setHasFixedSize(true);
lvToday.setNestedScrollingEnabled(false);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
today();
}
});
t.start();
}