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
Related
I am giving product id with barcode scanner. I can add product to listView but when i try to increase or decrease amount of the product. It doesn't update UI. I used Toast message to see weather list is updated, it updates list but doesn't update UI
I have tried to use runOnUiThread() but i couldn't find any solution. How to update UI can you please help me
custom_lisView_row
BaseActivity which keeps MainFragment on it
public class BaseActivity extends AppCompatActivity {
public static final String MAIN_FRAGMENT = "mainFragment";
public static final String PRODUCTS = "products";
FragmentManager fragmentManager;
Dialog dialog ;
public static ArrayList<MyProduct> myProductList = new ArrayList<>();
public static MyTablet myTablet = new MyTablet();
Activity mActivity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
//Initialize fragment manager
fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.fl_BaseActivity, new MainFragment()).commit();
//Create database
mDatabase = FirebaseDatabase.getInstance().getReference();
dialog = new Dialog(this);
//Runs when i enter product id
initScanner();
}
public void updateMyProductList(MyProduct myProduct){
for(int i= 0 ; i< myProductList.size() ; i++ ){
MyProduct temp = myProductList.get(i);
if (temp.getId().equals(myProduct.getId())) {
temp.setAmount(temp.getAmount() + myProduct.getAmount());
myProductList.set(i, temp);
return;
}
}
myProductList.add(myProduct);
updateMainFragment();
}
private void initScanner() {
mDatabase.child(PRODUCTS).child(finalData).get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
MyProduct myProduct = task.getResult().getValue(MyProduct.class);
myProduct.setAmount(1);
dialog.setContentView(R.layout.custom_product_dialog);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.setCancelable(false);
TextView tv_addBasket_product_dialog = dialog.findViewById(R.id.tv_addBasket_product_dialog);
tv_addBasket_product_dialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
updateMyProductList(myProduct);
dialog.dismiss();
}
});
dialog.show();
}
};
}
public void updateMainFragment() {
if (isExist(MAIN_FRAGMENT)) {
Fragment fragment = findFragment(MAIN_FRAGMENT);
((MainFragment) fragment).updateMyList();
}
}
//Add fragments to BaseActivity
public void addFragments(Fragment fragment, String tag) {
fragmentManager.beginTransaction().add(R.id.fl_BaseActivity, fragment, tag).commit();
}
//Replace fragments to BaseActivity
public void replaceFragments(Fragment fragment, String tag) {
fragmentManager.beginTransaction().replace(R.id.fl_BaseActivity, fragment, tag).commit();
}
//Remove fragment from BaseActivity
public void removeFragment(String tag) {
Fragment fragmentB = fragmentManager.findFragmentByTag(tag);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragmentB != null) {
fragmentTransaction.remove(fragmentB);
fragmentTransaction.commit();
}
}
// finds fragment and returns it
// It may return null first check fragment is exist. use isExist() method
public Fragment findFragment(String tag) {
Fragment fragment = fragmentManager.findFragmentByTag(tag);
return fragment;
}
//Check fragment exist in BaseActivity
public boolean isExist(String tag) {
Fragment fragmentB = fragmentManager.findFragmentByTag(tag);
if (fragmentB != null) {
return true;
}
return false;
}
}
MainFragment
public class MainFragment extends Fragment {
ListView lv_MainFragment;
public MyProductListAdapter myListAdapter;
public static ArrayList<MyProduct> myProductList;
Activity mActivity;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mActivity = getActivity();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myProductList = BaseActivity.myProductList;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
lv_MainFragment = view.findViewById(R.id.lv_MainFragment);
myListAdapter = new MyProductListAdapter(mActivity.getApplicationContext(), R.layout.custom_product_list_row, myProductList);
lv_MainFragment.setAdapter(myListAdapter);
return view;
}
public void updateMyList() {
myProductList = BaseActivity.myProductList;
myListAdapter.notifyDataSetChanged();
}
}
MyProductListAdapter
public class MyProductListAdapter extends ArrayAdapter<MyProduct> {
private Context mContext;
private ArrayList<MyProduct> list;
AppCompatButton acb_DecreaseAmount_productListRow, acb_IncreaseAmount_productListRow;
public MyProductListAdapter(Context context, int resource, ArrayList<MyProduct> objects) {
super(context, resource, objects);
this.mContext = context;
this.list = objects;
}
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.custom_product_list_row, parent, false);
tv_ProductAmount_productListRow = view.findViewById(R.id.tv_ProductAmount_productListRow);
acb_DecreaseAmount_productListRow = view.findViewById(R.id.acb_DecreaseAmount_productListRow);
acb_IncreaseAmount_productListRow = view.findViewById(R.id.acb_IncreaseAmount_productListRow);
tv_ProductAmount_productListRow.setText(String.valueOf(list.get(position).getAmount()));
acb_IncreaseAmount_productListRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
double productPrice = list.get(position).getPrice();
int productAmount = list.get(position).getAmount();
productAmount++;
list.get(position).setAmount(productAmount);
Toast.makeText(mContext, String.valueOf(productAmount), Toast.LENGTH_SHORT).show();
tv_ProductAmount_productListRow.setText(String.valueOf(list.get(position).getAmount()));
}
});
acb_DecreaseAmount_productListRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int productAmount = list.get(position).getAmount();
if (productAmount > 1) {
double productPrice = list.get(position).getPrice();
productAmount--;
list.get(position).setAmount(productAmount);
Toast.makeText(mContext, String.valueOf(productAmount), Toast.LENGTH_SHORT).show();
tv_ProductAmount_productListRow.setText(String.valueOf(list.get(position).getAmount()));
}
}
});
}
return view;
}
}
Hej Metehan,
your use case sounds perfect for a RecyclerView with a ListAdapter. You just submit a new list of products to the adapter and it will handle the updating and notifying for you.
My fragment has a Recycler View. Therefore I have a RecyclerView Adapter too. From this Adapter, I am opening an AlertDialog. When I click OK, I need to pass the onclick event from my DialogFragment back to my RecyclerView Adapter.
Currently, I am doing it like here, but this passes the event back to the activity and not to the RecyclerView Adapter.
public class FreshwaterRecyclerViewAdapter extends RecyclerView.Adapter<FreshwaterRecyclerViewAdapter.ViewHolder> implements BiotopeDialogFragment.NoticeDialogListener {
private List<Biotope> data;
private LayoutInflater layoutInflater;
FreshwaterRecyclerViewAdapter(Context context, List<Biotope> data) {
this.layoutInflater = LayoutInflater.from(context);
this.data = data;
}
//The dialog fragment receives a reference to this Activity through the
//Fragment.onAttach() callback, which it uses to call the following methods
//defined by the NoticeDialogFragment.NoticeDialogListener interface
#Override
public void onDialogPositiveClick(DialogFragment dialog) {
notifyItemInserted(getItemCount()-1);
}
#Override
public void onDialogNegativeClick(DialogFragment dialog) {
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView;
if (viewType == R.layout.biotope_cardview){
itemView = layoutInflater.inflate(R.layout.biotope_cardview, parent, false);
} else {
itemView = layoutInflater.inflate(R.layout.biotope_add_button, parent, false);
}
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if (position == data.size()) {
holder.imageButtonAddBiotope.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fragmentManager = ((AppCompatActivity) layoutInflater.getContext()).getSupportFragmentManager();
DialogFragment dialog = new BiotopeDialogFragment();
dialog.show(fragmentManager, "NoticeDialogFragment");
}
});
} else {
holder.textViewBiotopeTitle.setText(getItem(position).name);
Picasso.get().load(Uri.parse(getItem(position).imageUri)).into(holder.imageViewBiotope);
LastValuesRecyclerViewAdapter recyclerAdapter = new LastValuesRecyclerViewAdapter(layoutInflater.getContext(), getData());
holder.recyclerViewLastValues.setLayoutManager(new LinearLayoutManager(layoutInflater.getContext(), LinearLayoutManager.HORIZONTAL, false));
holder.recyclerViewLastValues.setAdapter(recyclerAdapter);
}
}
//total number of rows
#Override
public int getItemCount() {
return data.size() + 1; //+1 for the add button
}
#Override
public int getItemViewType(int position) {
return (position == data.size()) ? R.layout.biotope_add_button : R.layout.biotope_cardview;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView textViewBiotopeTitle;
private ImageView imageViewBiotope;
private RecyclerView recyclerViewLastValues;
private ImageButton imageButtonAddBiotope;
public ViewHolder(View view) {
super(view);
textViewBiotopeTitle = (TextView) view.findViewById(R.id.textViewBiotopeTitle);
imageViewBiotope = (ImageView) view.findViewById(R.id.imageViewBiotopeCardview);
recyclerViewLastValues = (RecyclerView) view.findViewById(R.id.recyclerViewLastValues);
imageButtonAddBiotope = (ImageButton) view.findViewById(R.id.imageButtonAddBiotope);
}
}
Biotope getItem(int id) {
return data.get(id);
}
private List<String> getData() {
List<String> data = new ArrayList<>();
data.add("PO4");
data.add("NO3");
return data;
}
}
This is my dialog.
public class BiotopeDialogFragment extends DialogFragment {
private NoticeDialogListener listener;
public interface NoticeDialogListener {
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
}
//Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
//Verify that the host activity implements the callback interface
try {
//Instantiate the NoticeDialogListener so we can send events to the host
listener = (NoticeDialogListener) context;
} catch (ClassCastException e) {
//The activity doesn't implement the interface, throw exception
throw new ClassCastException("FreshwaterRecyclerViewAdapter must implement NoticeDialogListener | Context: " + context.toString());
}
}
public static final String TAG = "biotope_dialog_fragment";
private ActivityResultLauncher<Intent> activityResultLauncher;
private Uri imageUri = null;
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext());
LayoutInflater inflater = requireActivity().getLayoutInflater();
//Inflate and set the layout for the dialog
//Pass null as the parent view because its going in the dialog layout
View view = inflater.inflate(R.layout.fragment_dialog_biotope, null, false);
builder.setView(view);
View colorPickerPreviewView = view.findViewById(R.id.colorPickerPreviewView);
ColorPickerView colorPickerView = view.findViewById(R.id.colorPickerView);
ImageView imageViewBiotope = view.findViewById(R.id.imageViewBiotopePreview);
TextInputEditText textFieldBiotopeName = view.findViewById(R.id.textFieldBiotopeName);
builder.setTitle("New biotope")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
BiotopeDatabase database = BiotopeDatabase.getDbInstance(requireContext().getApplicationContext());
Biotope biotope = new Biotope();
if (textFieldBiotopeName.getText() != null) {
biotope.name = textFieldBiotopeName.getText().toString();
} else {
biotope.name = "";
}
if (imageUri != null) {
biotope.imageUri = imageUri.toString();
} else {
biotope.imageUri = "";
}
biotope.color = colorPickerView.getColor();
database.biotopeDao().insertAll(biotope);
//Send the positive button event back to the host activity
listener.onDialogPositiveClick(BiotopeDialogFragment.this);
}
})
.setNegativeButton("noke", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Send the negative button event back to the host activity
listener.onDialogNegativeClick(BiotopeDialogFragment.this);
Objects.requireNonNull(BiotopeDialogFragment.this.getDialog()).cancel();
}
});
return builder.create();
}
public static BiotopeDialogFragment display(FragmentManager fragmentManager) {
BiotopeDialogFragment fragment = new BiotopeDialogFragment();
fragment.show(fragmentManager, TAG);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
This is my fragment building the RecyclerView. Alternatively, I can pass the event back to the fragment if it is not possible to pass it to the adapter.
public class BiotopesFragment extends Fragment {
private FreshwaterRecyclerViewAdapter recyclerAdapter;
public static BiotopesFragment newInstance(String param1, String param2) {
BiotopesFragment fragment = new BiotopesFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_biotopes, container, false);
RecyclerView recyclerViewFreshwater = (RecyclerView) root.findViewById(R.id.recyclerViewFreshwater);
recyclerAdapter = new FreshwaterRecyclerViewAdapter(getContext(), getData());
recyclerViewFreshwater.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
recyclerViewFreshwater.setAdapter(recyclerAdapter);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
recyclerViewFreshwater.addItemDecoration(dividerItemDecoration);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.START | ItemTouchHelper.END, 0) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
Collections.swap(getData(), fromPosition, toPosition);
recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
});
itemTouchHelper.attachToRecyclerView(recyclerViewFreshwater);
return root;
}
private List<Biotope> getData() {
BiotopeDatabase database = BiotopeDatabase.getDbInstance(requireContext().getApplicationContext());
BiotopeDao biotopeDao = database.biotopeDao();
return biotopeDao.getAll();
}
}
Ideal Way to do this to create all UI component in Fragment not in the adapter . Create an interface to handle events in the fragment and provide callback to the fragment from adapter. now your Fragment should create all the UI component .
Now coming to the
How to provide callback from dialog fragment to Fragment.
You can use setTargetFragment but its deprecated . Now you can use setFragmentResultListener instead of setTargetFragment(), its the safest way i think. Once you get the result back in fragment you can call any method of your adapter.
I'm on a project that, i'm getting datas from Json output. And showing them in my app. Json output includes categories in categories. I'm showing categories with listView, therefore i'm using adapters. It's all ok with FirstPageAdapter but when I switch the other, I can't get datas from FirstPageAdapter with using intent. That question(How to call getIntent() in adapter class) didn't helped me well btw.
FirstPageAdapter.java:
public class FirstPageAdapter extends BaseAdapter {
List<ResponseDTO> responseDTOList;
Context context;
Activity activity;
public FirstPageAdapter(List<ResponseDTO> responseDTOList, Context context, Activity activity) {
this.responseDTOList = responseDTOList;
this.context = context;
this.activity = activity;
}
#Override
public int getCount() {
return responseDTOList.size();
}
#Override
public Object getItem(int i) {
return responseDTOList.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = LayoutInflater.from(context).inflate(R.layout.layout_main_act, viewGroup, false);
TextView id, idCategory, parent_id, categoryName, filters, brands;
Button categoriesButton, specsButton;
id = view.findViewById(R.id.id);
idCategory = view.findViewById(R.id.idCategory);
parent_id = view.findViewById(R.id.parent_id);
categoryName = view.findViewById(R.id.categoryName);
filters = view.findViewById(R.id.filters);
brands = view.findViewById(R.id.brands);
categoriesButton = view.findViewById(R.id.childCategories);
specsButton = view.findViewById(R.id.specs);
id.setText("ID : "+responseDTOList.get(i).getId());
idCategory.setText("Category ID: "+responseDTOList.get(i).getIdcategory());
parent_id.setText("Parent ID: "+responseDTOList.get(i).getParentId());
categoryName.setText("Category name : "+responseDTOList.get(i).getCategoryName());
filters.setText("Filters : "+responseDTOList.get(i).getFilters());
brands.setText("Brands : "+responseDTOList.get(i).getBrands());
final String post = "" + responseDTOList.get(i).getId();
final String id_category = "" + responseDTOList.get(i).getIdcategory();
categoriesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(activity, ChildCategoriesAdapter.class);
intent.putExtra("post_id",post);
intent.putExtra("id_category",id_category);
activity.startActivity(intent);
}
});
specsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(activity, ChildCategoriesAdapter.class);
intent.putExtra("post_id",post);
intent.putExtra("id_category",id_category);
activity.startActivity(intent);
}
});
return view;
}
}
ChildCategoriesAdapter.java:
public class ChildCategoriesAdapter extends BaseAdapter {
List<ResponseDTO> responseDTOList;
Context context;
Activity activity;
public ChildCategoriesAdapter(List<ResponseDTO> responseDTOList, Context context, Activity activity) {
this.responseDTOList = responseDTOList;
this.context = context;
this.activity = activity;
}
#Override
public int getCount() {
return responseDTOList.size();
}
#Override
public Object getItem(int i) {
return responseDTOList.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
defVars(view, viewGroup);
return null;
}
public void defVars(View view, ViewGroup viewGroup)
{
view = LayoutInflater.from(context).inflate(R.layout.layout_activity_child, viewGroup, false);
Button variationsButton;
TextView id, idCategory, parent_id, categoryName, filters, brands;
id = view.findViewById(R.id.id);
idCategory = view.findViewById(R.id.idCategory);
parent_id = view.findViewById(R.id.parent_id);
categoryName = view.findViewById(R.id.categoryName);
filters = view.findViewById(R.id.filters);
brands = view.findViewById(R.id.brands);
variationsButton = view.findViewById(R.id.variationsButton);
}
public void request()
{
responseDTOList = new ArrayList<>();
//Call<List<ResponseDTO>> call = ManagerAll
}
}
I have their Activities apart from these.
MainActivity.java(FirstPageAdapter):
public class MainActivity extends AppCompatActivity {
FirstPageAdapter adp;
List<ResponseDTO> list;
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
defVars();
request();
}
public void defVars()
{
listView = findViewById(R.id.listView);
}
public void request()
{
list = new ArrayList<>();
Call<List<ResponseDTO>> call = ManagerAll.getInstance().bringCall();
call.enqueue(new Callback<List<ResponseDTO>>() {
#Override
public void onResponse(Call<List<ResponseDTO>> call, Response<List<ResponseDTO>> response) {
if (response.isSuccessful())
{
list = response.body();
adp = new FirstPageAdapter(list, getApplicationContext(), MainActivity.this);
listView.setAdapter(adp);
}
}
#Override
public void onFailure(Call<List<ResponseDTO>> call, Throwable t) {
}
});
}
}
Nothing important in ChildCategories.java
I'm building a list using a RecyclerView. When the user clicks the '+' button in the toolbar an AlertDialog is launched that prompts the users to add an item in the list. I've built the AlertDialog in a separate class that extends DialogFragment. How can I make so that the item is added to the List<Task>?
What I've done so far in my adapter class is make List<Task> mTaskList a public static variable and I also created a static method that will return this list. I call this static method in the DialogFragment class so I can retrieve the list. But I don't think this is good practice. Is there a better way I can be adding an item to my list?
TaskListFragment.java
public class TaskListFragment extends Fragment {
private RecyclerView mRecyclerView;
private TaskAdapter mAdapter;
private List<Task> mTaskList;
private static final String ADD_DIALOG = "add_dialog";
public TaskListFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_task_list, container, false);
mRecyclerView = view.findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
//mTaskList = createTasks();
//mAdapter = new TaskAdapter(mTaskList);
mRecyclerView.setAdapter(updateUI());
return view;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_list_item, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.add_new_task:
FragmentManager manager = getFragmentManager();
AddTaskFragment dialog = new AddTaskFragment();
dialog.show(manager, ADD_DIALOG);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*
public List<Task> createTasks() {
List<Task> tasks = new ArrayList<>();
for(int i = 1; i <= 100; i++) {
Task task = new Task();
task.setTitle("Task #" + i);
task.setSolved(i % 2 == 0);
tasks.add(task);
}
return tasks;
}
*/
public TaskAdapter updateUI(){
if(mAdapter == null) {
mTaskList = new ArrayList<>();
mAdapter = new TaskAdapter(mTaskList);
}else {
mAdapter.notifyDataSetChanged();
}
return mAdapter;
}
}
TaskAdapter.java
public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.ViewHolder> {
public static List<Task> mTaskList;
public TaskAdapter(List<Task> taskList) {
mTaskList = taskList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Task currentTask = mTaskList.get(position);
holder.bindData(currentTask);
}
#Override
public int getItemCount() {
return mTaskList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView mTitle;
private CheckBox mSolved;
private ViewHolder(View itemView) {
super(itemView);
mTitle = itemView.findViewById(R.id.task_title);
mSolved = itemView.findViewById(R.id.task_solved);
}
private void bindData(Task task) {
mTitle.setText(task.getTitle());
mSolved.setChecked(task.isSolved());
}
}
public static List<Task> getTaskList(){
return mTaskList;
}
}
AddTaskFragment.java
public class AddTaskFragment extends DialogFragment {
private EditText mTaskTitle;
private List<Task> mTaskList;
private void addTask() {
if(!mTaskTitle.getText().toString().equals("")) {
Task task = new Task();
task.setTitle(mTaskTitle.getText().toString());
mTaskList = TaskAdapter.getTaskList();
mTaskList.add(task);
}
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//return super.onCreateDialog(savedInstanceState);
View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_task_dialog,null);
mTaskTitle = view.findViewById(R.id.task_title);
return new AlertDialog.Builder(getContext())
.setView(view)
.setTitle("Add Task")
.setPositiveButton("Add", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
addTask();
}
})
.create();
}
}
You could call startActivityForResult when starting addTask(), which would put the Task to add inside an Intent which you would receive in your activity's onActivityResult(int requestCode, int resultCode, Intent data).
You can look into using the ViewModel pattern that Google introduced last IO.
The section talking about sharing would be especially beneficial in your situation.
I have one ViewPager(mainViewPager) inside my MainActivity which renders from a fragment that contains another ViewPager(imageViewPager) and a TextView. Now The imageViewPager renders from another fragment that contains ImageView and a button. I've set onClick listener on this ImageView that turns in fullscreen view of the image with a button beneath.Now onClick of this buttton I want to return to my MainActivity with the condition to be on the same page from which I entered and with the same image which I viewed last in fullscreen.I am able to get the same page but the image always starts from 0.
Basically my hierarchy is like:
MainActivity
--mainViewPager-->TaskFragment
--imageViewPager-->ImageFragment(contains only ImageView
--TextView(set text returned from MainActivity)
My Code:
MainActivity.java
public class MainActivity extends FragmentActivity {
private ViewPager mViewPager;
private CustomPagerAdapter mPagerAdapter;
private int changedPosition;
private String[] vehicles = new String[]{"Audi Q7", "Honda Accord", "Hyundai i20", "Maruti Suzuki Swift", "Mahindra XUV 500",
"Swift Dzire", "Honda City", "Honda Civic", "Mercedez Benz", "Rolls Royce", "Ferrari"};
private String[][] vehicle_info = new String[][]{
{"http://www.hdwallpapers.in/walls/2010_abt_audi_q7_3_tdi_3-wide.jpg",
"http://www.hdwallpapers.in/walls/2010_mtm_audi_s5_cabrio_michelle_edition-wide.jpg",
"http://www.hdwallpapers.in/walls/2009_audi_tts_coupe_car-wide.jpg"},
{"http://automobiles.honda.com/images/2015/accord-sedan/exterior-gallery/2015-honda-accord-sedan-sport-exterior-side1.jpg",
"http://www.carprousa.com/wp-content/uploads/2015/01/HondaInterior-e1421978263126.jpg",
"http://www.carprousa.com/wp-content/uploads/2015/01/HondaInterior2-e1421978365916.jpg"},
...........
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager)findViewById(R.id.mainViewPager);
mPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager(), vehicles, vehicle_info);
mViewPager.setAdapter(mPagerAdapter);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0) {
changedPosition = data.getIntExtra("CHANGED_POSITION", 0);
Log.i("POSITION 3:"," "+changedPosition);
TaskFragment fragment = new TaskFragment();
Bundle bundle = new Bundle();
bundle.putInt("IMAGE_POSITION", changedPosition);
fragment.setArguments(bundle);
}
}
}
activity_main.xml
<android.support.v4.view.ViewPager
android:id="#+id/mainViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
CustomPagerAdapter.java
public class CustomPagerAdapter extends FragmentStatePagerAdapter{
private String[] vehicles,selected_vehicle_info;
private String[][] vehicle_info;
public CustomPagerAdapter(FragmentManager fragmentManager,String[] vehicles,String[][] vehicle_info){
super(fragmentManager);
this.vehicles = vehicles;
this.vehicle_info = vehicle_info;
}
#Override
public Fragment getItem(int position) {
selected_vehicle_info = vehicle_info[position];
TaskFragment taskFragment = new TaskFragment();
Bundle bundle = new Bundle();
bundle.putString("ITEM",vehicles[position]);
bundle.putStringArray("ITEM_INFO",selected_vehicle_info);
taskFragment.setArguments(bundle);
return taskFragment;
}
#Override
public int getCount() {
return vehicles.length;
}
}
TaskFragment.java
public class TaskFragment extends Fragment {
private String vehicle;
private String[] vehicle_info;
private ViewPager imageViewPager;
private ImagePagerAdapter imagePagerAdapter;
private int changedImagePosition;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
vehicle = getArguments().getString("ITEM");
vehicle_info = getArguments().getStringArray("ITEM_INFO");
View view = inflater.inflate(R.layout.activity_task_fragment,container,false);
TextView messageTextView = (TextView) view.findViewById(R.id.textView);
messageTextView.setText(vehicle);
imageViewPager = (ViewPager)view.findViewById(R.id.imageViewPager);
imagePagerAdapter = new ImagePagerAdapter(getActivity(), vehicle_info);
imagePagerAdapter.notifyDataSetChanged();
imageViewPager.setAdapter(imagePagerAdapter);
imageViewPager.setCurrentItem(changedImagePosition);
return view;
}
private class ImagePagerAdapter extends PagerAdapter {
private Activity activity;
private String[] vehicle_info;
public ImagePagerAdapter(Activity activity,String[] vehicle_info){
this.activity = activity;
this.vehicle_info = vehicle_info;
}
#Override
public Object instantiateItem(ViewGroup container, final int position) {
LayoutInflater inflater = LayoutInflater.from(activity);
View view = inflater.inflate(R.layout.activity_image_fragment,container,false);
ImageView imageView = (ImageView) view.findViewById(R.id.imageView);
Picasso.with(getContext()).load(vehicle_info[position]).into(imageView);
if(imageView.getParent()!=null)
((ViewGroup)imageView.getParent()).removeView(imageView);
((ViewPager) container).addView(imageView, 0);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(activity, ImageInFullScreen.class);
intent.putExtra("IMAGES_URL", vehicle_info);
intent.putExtra("IMAGE_POSITION", position);
activity.startActivityForResult(intent, 0);
}
});
return imageView;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public int getCount() {
return vehicle_info.length;
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view) {
collection.removeView((View) view);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
}
ImageInFullScreen.java
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent();
intent.putExtra("CHANGED_POSITION",changedImgPosition);
setResult(0,intent);}});
//and the same adapter n all.
where ever you want to refresh the view put the following code
this.page_position = 0;
imagePagerAdapter.notifyDataSetChanged();
and in your ImagePagerAdapter override the following function -
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
POSITION_NONE means whenever notifyDataSetChanged is called, adapter will create fresh views rather than using the same views.
This should work in our case.
I have found an answer to my question, the problem was that somehow my setCurrentItem() wasn't working inside TaskFragment's onCreateView(), so I've moved it to the Run method of Runnable interface's postAtTime()nd then it worked perfectly.
Here's my edited code.
MainActivity.java`
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0) {
claim_id = vehicleDetailsArrayList.get(changedPage).getClaimId();
//Retrieve value of position of last viewed image, before clicking the button
changedPosition = data.getIntExtra("CHANGED_POSITION", 0);
Log.i("POSITION 3:"," "+changedPosition);
if(changedPage > -1 && changedPage < vehicleDetailsArrayList.size()) {
addUpdateImagePositionInList(claim_id, changedPosition);
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (mViewPager.getAdapter() != null) {
mViewPager.getAdapter().notifyDataSetChanged();
}
}
}, 0);
}
}
public void addUpdateImagePositionInList(int claimId, int position){
for (int imageLength = 0; imageLength < imagePositionArrayList.size(); imageLength++)
{
if (claimId == (imagePositionArrayList.get(imageLength).getClaim_id()))
{
imagePositionArrayList.get(imageLength).setImagePosition(position);
return;
}
}
imagePositionArrayList.add(new ImagePosition(claimId, position));
}
public int getChangedImagePosition(int claimId){
for (int imageLength = 0; imageLength < imagePositionArrayList.size(); imageLength++)
{
if (claimId == (imagePositionArrayList.get(imageLength).getClaim_id()))
{
Log.i("POSITION123 "," ::"+ imagePositionArrayList.get(imageLength).getImagePosition() );
return imagePositionArrayList.get(imageLength).getImagePosition();
}
}
return 0;
}
`
TaskFragment.java`
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
id = getArguments().getInt("ID");
vehicle = getArguments().getString("ITEM");
vehicle_info = getArguments().getStringArray("ITEM_INFO");
changedImagePosition = ((MainActivity)getActivity()).getChangedImagePosition(id);
View view = inflater.inflate(R.layout.task_fragment,container,false);
TextView messageTextView = (TextView) view.findViewById(R.id.textView);
messageTextView.setText(vehicle);
imageViewPager = (ViewPager)view.findViewById(R.id.imageViewPager);
imagePagerAdapter = new ImagePagerAdapter(getActivity(), vehicle_info);
imageViewPager.setAdapter(imagePagerAdapter);
/*The below code doesn't work
if (imageViewPager.getCurrentItem() != changedImagePosition) {
Log.i("POSITION current", ":" + imageViewPager.getCurrentItem());
Log.i("POSITION changed", " :"+ changedImagePosition);
setCurrentItem = true;
imageViewPager.setCurrentItem(changedImagePosition, false);
Log.i("POSITION getCurrent", " :" + imageViewPager.getCurrentItem());
}
*/
new Handler().postAtTime(new Runnable() {
#Override
public void run() {
if (imageViewPager.getAdapter() != null) {
imageViewPager.getAdapter().notifyDataSetChanged();
imageViewPager.setCurrentItem(changedImagePosition);
}
}
},0);
return view;
}
`