listview adapter not updating after removing an item - android

Hello am trying to delete an item from my listview am able to delete item from my db but my adapter is not getting updated I have attached the code below`
public class SavedPolygonFragment extends android.support.v4.app.Fragment implements RefreshListener {
private static String LOG_TAG = SavedPolygonFragment.class.getName();
private String message = "No message";
private ListView shapeList;
private TextView textView;
private Button startMainBtn;
private SavedShapeAdapter savedShapeAdapter;
private long shapeId;
private float scaleFactor;
private List<Shape> savedShapes = new ArrayList<>();
private StartDrawingListener startListener;
private DeleteShapesDialog deleteDialog;
public SavedPolygonFragment() {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
startListener = (StartDrawingListener) activity;
}
#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_one, container, false);
savedShapes = getArguments().getParcelableArrayList("shapes");
AssetLog.verbose(LOG_TAG, "savedshapes.size " + savedShapes.size());
shapeList = (ListView) view.findViewById(R.id.shapeList);
textView = (TextView) view.findViewById(R.id.polygonTitle);
startMainBtn = (Button) view.findViewById(R.id.gotoMain);
startMainBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startListener.startMainReceived();
}
});
if (!savedShapes.isEmpty() && !savedShapes.equals(null) && savedShapes.size() != 0) {
textView.setText("Polygons");
shapeList.setVisibility(View.VISIBLE);
startMainBtn.setVisibility(View.GONE);
if (savedShapeAdapter != null) {
savedShapeAdapter.notifyDataSetChanged();
} else {
savedShapeAdapter = new SavedShapeAdapter(savedShapes, getActivity());
shapeList.setAdapter(savedShapeAdapter);
shapeList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
MainActivity_.intent(getActivity())
.savedProjectId(ProjectShapesActivity.projId)
.scaleFactor(ProjectShapesActivity.scaleFactor)
.shapeId(((Shape) view.getTag()).getShapeId())
.lineId(-1)
.pointId(-1)
.start();
}
});
}
}
else{
shapeList.setVisibility(View.GONE);
startMainBtn.setVisibility(View.VISIBLE);
textView.setText("Sorry no shapes are saved");
}
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
registerForContextMenu(shapeList);
}
#Override
public void onRefreshPressed() {
}
#Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
shapeId = info.id;
menu.add(Menu.NONE, R.id.deleteShapes, Menu.NONE, "Delete");
menu.add(Menu.NONE, R.id.editShapes, Menu.NONE, "Edit");
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.refresh:
return false;
case R.id.deleteShapes:
if(deleteDialog == null){
Bundle bundle = new Bundle();
bundle.putString("SHAPE", "SHAPE");
bundle.putLong("shapeId", shapeId);
deleteDialog = new DeleteShapesDialog();
deleteDialog.setArguments(bundle);
deleteDialog.show(getActivity().getFragmentManager().beginTransaction(), "showDeleteDialog");
}
return true;
case R.id.editShapes:
return true;
}
return super.onContextItemSelected(item);
}
public void onDataChanged(long shapeid) {
Shape shape;
for (int i = 0; i <savedShapes.size() ; i++) {
shape = savedShapes.get(i);
if(shape.getShapeId() == shapeid){
savedShapes.remove(i);
shapeList.removeViewAt(i);
shapeList.invalidate();
savedShapeAdapter.notifyDataSetChanged();
break;
}
}
}
}
`
Now when user selects yes from deleteDialog i wrote a callback to my activity and in the corresponding methods this is what I do
SavedPolygonFragment polygonFragment = new SavedPolygonFragment();
polygonFragment.onDataChanged(shapeId);
Can somebody show me whats wrong
/////EDIT 1
public void onDataChanged(long shapeid) {
savedShapeAdapter.removeItemById(shapeid);
}
and my adapter
public void removeItemById(long itemId){
for(int i =0; i< shapeList.size() ; i++){
if(shapeList.get(i).getShapeId() == itemId){
shapeList.remove(i);
}
}
notifyDataSetChanged();
}

am able to delete item from my db but my adapter is not getting
updated
Problem is caused by :
savedShapes.remove(i);
line.
Currently removing item from ArrayList which is in SavedPolygonFragment class, not from ArrayList which is used by Adapter to fill ListView.
Using current approach try this way will work by setting new Adapter every time:
if(shape.getShapeId() == shapeid){
savedShapes.remove(i);
savedShapeAdapter = new SavedShapeAdapter(savedShapes, getActivity());
shapeList.setAdapter(savedShapeAdapter);
savedShapeAdapter.notifyDataSetChanged();
break;
}
But this is not optimize solution to create and set new object of Adapter every-time when want to update ListView.
Right approach is create a method in SavedShapeAdapter class for removing item for ArrayList which is used by Adapter and then call it inside onDataChanged method:
public void deleteRowItem(int index){
this.savedShapes.remove(index);
this..notifyDataSetChanged();
}
Now call deleteRowItem when want to delete row item from ListView :
if(shape.getShapeId() == shapeid){
savedShapeAdapter.deleteRowItem(i);
break;
}

Related

Updating Elements of Listview in a Fragment from a Catalog within another Fragment

The title might be a little confusing so I hope that I can express my problem correctly. So I'm working on a simple workout log app. I have fragment ActiveWorkout as in Image 1. When I press the pink add button I am directed to another fragment, which contains different exercises as a List, which is shown in Image 2. Then I am to select an exercise(with the onItemClickListener) and the title of that exercise should be sent back to the ActiveWorkoutFragment and added to the Active Workout, so it should be like Image 3. So the problem here is, I don't exactly know how to keep my Active Workout 'alive', it should be updated if I want to add another exercise and not be blank when I press the pink add button again, so in the end it should be something like in Image 4. I was thinking about sending data with a Bundle, which I also tried in the code but the more difficult part is updating the Workout list without deleting the previous added exercises. Btw the reason I am trying to do something like this is because the data is actually in Firebase Database, so in a sense I'm trying to retrieve data from the Workout database.
Images:
Image 1 Image 2 Image 3 Image 4
This is the Exercise List or the Catalog:
public class ExercisesFragment extends Fragment {
private ListView lv;
private FirebaseListAdapter adapter;
private ArrayList<Exercise> exerciseList;
private ArrayList<String> nameList;
//private Adapter adapter;
public ExercisesFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_exercises, container, false);
lv = v.findViewById(R.id.lv);
Query query = FirebaseDatabase.getInstance().getReference().child("exerciseList");
FirebaseListOptions<ExerciseElement> options = new FirebaseListOptions.Builder<ExerciseElement>()
.setLayout(R.layout.exercise)
.setQuery(query, ExerciseElement.class)
.build();
adapter = new FirebaseListAdapter(options) {
#Override
protected void populateView(#NonNull View v, #NonNull Object model, int position) {
TextView bodypart = v.findViewById(R.id.bodypart);
TextView title = v.findViewById(R.id.title);
ExerciseElement el = (ExerciseElement) model;
bodypart.setText(el.getBodypart().toString());
title.setText(el.getTitle().toString());
}
};
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ExerciseElement el = (ExerciseElement) lv.getItemAtPosition(position);
String item = el.getTitle();
ActiveWorkoutFragment awf = new ActiveWorkoutFragment();
Bundle args = new Bundle();
args.putString("ExerciseTitle", item);
awf.setArguments(args);
getFragmentManager().beginTransaction().replace(R.id.nav_host_fragment, awf).commit();
//Navigation.findNavController(v).navigate(R.id.activeWorkoutFragment);
}
});
return v;
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
}
Then there is the ActiveWorkoutFragment, which is a little longer but the upper part is not the concern. The addNewExercise() method is being called when I click on the pink add button, so I was trying to retrieve the data somehow there.
public class ActiveWorkoutFragment extends Fragment {
private Workout workout;
private TextView emptyRecyclerView;
private RecyclerView exerciseRecyclerView;
private ExerciseRecyclerViewAdapter adapter;
private WorkoutHistory workoutHistory;
private FloatingActionButton fab;
private FirebaseAuth mAuth;
private DatabaseReference databaseWorkouts;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_active_workout, container, false);
fab = v.findViewById(R.id.fab);
fab.setOnClickListener(this::addNewExercise);
setHasOptionsMenu(true);
workout = new Workout("WORKOUT");
if(savedInstanceState != null) {
workout = savedInstanceState.getParcelable("key");
}
emptyRecyclerView = v.findViewById(R.id.empty_recycler_view);
//buildRecyclerView(workout);
exerciseRecyclerView = v.findViewById(R.id.recycler_view_exercise);
// improves performance if size of RecyclerView content is fixed
// taken from developer.android.com
exerciseRecyclerView.setHasFixedSize(true);
// use a linear layout manager for RecyclerView
LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext());
exerciseRecyclerView.setLayoutManager(layoutManager);
// add divider
RecyclerView.ItemDecoration itemDecoration = new
DividerItemDecoration(this.getContext(), DividerItemDecoration.VERTICAL);
exerciseRecyclerView.addItemDecoration(itemDecoration);
// Create adapter and set its data set to workout
adapter = new ExerciseRecyclerViewAdapter(workout, this);
// Set up swipe to dismiss and ability to move RecyclerView items around
// Create callback object for ItemTouchHelper
ItemTouchHelper.Callback callback = new CustomItemTouchHelperCallback(adapter);
// Implement object created above
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(exerciseRecyclerView);
if (adapter.getItemCount() == 0)
{
showEmptyRecyclerViewText();
}
else
{
exerciseRecyclerView.setAdapter(adapter);
}
return v;
}
// Adds save button (check mark) to action bar
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.active_workout_action_bar, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_save: {
List<Exercise> exercises = workout.getExercises();
mAuth = FirebaseAuth.getInstance();
String user_id = mAuth.getCurrentUser().getUid();
databaseWorkouts = FirebaseDatabase.getInstance().getReference("Workouts").child(user_id);
String id = databaseWorkouts.push().getKey();
workout = new Workout("abc", user_id, exercises);
databaseWorkouts.child(id).setValue(workout);
Toast.makeText(getContext(), "Workout saved", Toast.LENGTH_SHORT).show();
return true;
}
case R.id.action_delete: {
exerciseRecyclerView.requestFocus();
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Confirm deletion").setMessage("Are you sure you want to delete" +
" this workout?");
builder.setPositiveButton(android.R.string.yes, (dialog, which) -> {
try {
workoutHistory.removeWorkout(workout);
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getContext(), "Workout deleted", Toast.LENGTH_SHORT).show();
});
builder.setNegativeButton(android.R.string.no, (dialog, which) -> {
dialog.dismiss();
});
builder.show();
return true;
}
default:
// unrecognized button pressed
return super.onOptionsItemSelected(item);
}
}
public void showEmptyRecyclerViewText()
{
emptyRecyclerView.setVisibility(View.VISIBLE);
}
public void addNewExercise(View view) {
Bundle bundle = getArguments();
String value = "";
if(bundle != null) {
value = bundle.getString("ExerciseTitle");
}
System.out.println("lala");
System.out.println(value);
Exercise newExercise = new Exercise(value, -1, -1);
if (exerciseRecyclerView.getAdapter() == null) {
exerciseRecyclerView.setAdapter(adapter);
}
emptyRecyclerView.setVisibility(View.INVISIBLE);
workout.addExercise(newExercise);
adapter.notifyItemInserted(workout.getExercises().size() - 1);
}
private void hideKeyboard(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService
(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("key", workout);
}
}
Try this as a base for your project. add views to it and other necessary methods however it will provide you with the flow of module
//contract to update Framgents
public interface FragUpdater {
public void updateExerciseFrag(Exercise exercise);
}
public class ExerciseActiity extends AppCompatActivity implements FragUpdater {
FragmentManager fm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise_actiity);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gotoActiveWorkoutFragment();
}
});
fm = getSupportFragmentManager();
gotoExercisesFragment();
}
private void gotoActiveWorkoutFragment() {
ActiveWorkoutFragment activeWorkoutFragment = new ActiveWorkoutFragment();
Bundle bundle = new Bundle();
activeWorkoutFragment.setArguments(bundle);
fm.beginTransaction().add(R.id.content_frame, activeWorkoutFragment, "ExerciseSelectionFrag").addToBackStack(null).commit();
}
private void gotoExercisesFragment() {
ExercisesFragment exercisesFragment = new ExercisesFragment();
Bundle bundle = new Bundle();
exercisesFragment.setArguments(bundle);
fm.beginTransaction().replace(R.id.content_frame, exercisesFragment, "ExerciseDisplayFrag").commit();
}
#Override
public void updateExerciseFrag(Exercise exercise) {
// Get Fragment ExercisesFragment
ExercisesFragment frag = (ExercisesFragment)
fm.findFragmentByTag("ExerciseDisplayFrag");
if (frag == null) {
return;
}
frag.updateList(exercise);
}
}
public class ExercisesFragment extends Fragment {
//here update your list in ExerciseFragment
public void updateList(Exercise exercise) {}
}
public class ActiveWorkoutFragment extends Fragment {
FragUpdater fragUpdater;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragUpdater = (ExerciseActiity) getActivity();
}
private void selectListItem(Exercise exercise) {
fragUpdater.updateExerciseFrag(exercise);
getActivity().getSupportFragmentManager().popBackStack();
}
}

Android ListView Back Button

I've made a listview and when i click an item, it filters and it shows items that filtered by what i clicked. We can think it is like a treeview.
My question is when i come last item "how can i go back one step in this listview ?". When i click device's back button it returns main activity but i want only returning back in this listview.
OsbItemsListActivity.java
public class OsbItemsListActivity extends AppCompatActivity {
private ListView sobItemsListView;
private Activity mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_osb_items_list);
mContext = this;
Intent intent = getIntent();
if(null != intent){
sobItemsListView = (ListView)findViewById(R.id.activity_osb_items_list_view);
SobItemsAdapter sobItemsAdapter = new SobItemsAdapter(mContext);
sobItemsListView.setAdapter(sobItemsAdapter);
sobItemsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String clickedItem = (String) parent.getAdapter().getItem(position);
Toast.makeText(mContext, "SOB : " + clickedItem, Toast.LENGTH_SHORT).show();
((SobItemsAdapter)parent.getAdapter()).setNextFilter(clickedItem);
((SobItemsAdapter) parent.getAdapter()).notifyDataSetChanged();
}
});
}
else {
Toast.makeText(mContext, "Listelenecek Veri Yok", Toast.LENGTH_SHORT).show();
}
}
}
And my SobItemsAdapter.java
public class SobItemsAdapter extends BaseAdapter {
public enum STEPS{ SOB, STREET, CONNECTIONARTICLE, INSTALLATION }
Activity mActivity;
List<OsbDownloadItem> osbDownloadItemList;
List<String> visualRows = new ArrayList<String>();
HashMap<String, List<OsbDownloadItem>> map;
STEPS filterStep;
public SobItemsAdapter(Activity activity){
mActivity = activity;
filterStep = STEPS.SOB;
osbDownloadItemList = SharedData.osbDownloadItemList;
setNextFilter("");
}
private void modifyVisualRows(HashMap<String, List<OsbDownloadItem>> _map){
visualRows.clear();
for(String item : _map.keySet()){
visualRows.add(item);
}
}
#Override
public int getCount() {
return visualRows.size();
}
#Override
public String getItem(int position) {
return visualRows.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = mActivity.getLayoutInflater();
View view = inflater.inflate(R.layout.activity_osb_items_row, parent, false);
if(null != view){
((TextView)view.findViewById(R.id.osb_items_sob)).setText(visualRows.get(position));
}
return view;
}
public void setNextFilter(String value){
switch (filterStep){
case SOB:
map = DataFilter.getSobs(osbDownloadItemList);
filterStep = STEPS.STREET;
break;
case STREET:
map = DataFilter.getStreetsBySob(map.get(value));
filterStep = STEPS.CONNECTIONARTICLE;
break;
case CONNECTIONARTICLE:
map = DataFilter.getConnectionArticlesByStreet(map.get(value));
filterStep = STEPS.INSTALLATION;
break;
case INSTALLATION:
map = DataFilter.getInstalliationsByConnectionArticle(map.get(value));
break;
}
modifyVisualRows(map);
}
}
Put this below code in your activity
#Override
public void onBackPressed()
{
if(checkBackPress)
{
checkBackPress =false;
sobItemsAdapter.setNextFilter(STEPS.SOB);
sobItemsAdapter.notifyDataSetChanged();
}
super.onBackPressed();
}
Create one boolean field public boolean checkBackPress=false; in your activity. Set this checkBackPress as true once item clicked on your item click event(checkBackPress=true) and set checkBackPress as false in backpressed

Selecting an item on an AppCompatActivity's ListView

I have an AppCompatActivity. In there I have a list view. I want to make it so when an item is selected something happens (another activity will fire off, but for now I just want to get into the method where I can call that intent).
Im not sure how to do this. I saw I can hae my AppCompatActivity implement AbsListView.OnItemClickListener and it gives me a method
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
But then when I run my code and I select an item it doesnt go into that method.
So can someone tell me how I do this?
Below is my entire code for the activity.
public class RouteList extends AppCompatActivity implements AbsListView.MultiChoiceModeListener, AbsListView.OnItemClickListener {
ArrayList<RouteItem> itemsList;
ArrayList<String> routeFiles;
ArrayList<RouteItem> selected;
RouteListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_route_list);
itemsList = new ArrayList<RouteItem>();
selected = new ArrayList<RouteItem>();
adapter = new RouteListAdapter(this, R.layout.route_list_item);
ListView listView = (ListView) findViewById(R.id.routeList);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(this);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("Routes");
toolbar.setTitleTextColor(Color.WHITE);
setSupportActionBar(toolbar);
getRouteFiles();
RouteLocationsTask task = new RouteLocationsTask(adapter, routeFiles, getApplicationContext());
task.execute();
}
public void getRouteFiles()
{
String path = Environment.getExternalStorageDirectory()+"/LocationTracker/Routes/";
// Read all files sorted into the values-array
routeFiles = new ArrayList();
File dir = new File(path);
String[] list = dir.list();
if (list != null) {
for (String file : list) {
if (!file.startsWith(".")) {
routeFiles.add(file);
}
}
}
Collections.sort(routeFiles);
}
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
int x = adapter.getCount();
RouteItem routeItem = adapter.getItem(position);
if(checked)
selected.add(adapter.getItem(position));
else
selected.remove(adapter.getItem(position));
mode.setTitle(String.valueOf(selected.size()));
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
getMenuInflater().inflate(R.menu.listview_cab_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch(item.getItemId()){
case R.id.delete:
itemsList = adapter.getItemList();
itemsList.removeAll(selected);
adapter.notifyDataSetChanged();
deleteSelectedFiles();
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
selected.clear();
}
public void deleteSelectedFiles()
{
for(RouteItem routeItem : selected)
{
File file = new File(routeItem.getFileName());
file.delete();
}
}
//#Override
public void onClick(View v) {
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int y = 0;
}
}
You need to call setOnItemClickListener method on ListView in order to receive callback in onItemClick. Just put this line in your Activity's onCreate method.
listView.setOnItemClickListener(this);

Change ActionBar items depending on how many selected

How can I change what the ActionBar menu contains depending on how many items in a RecyclerView are selected? For instance, when one card is selected in 'selection mode,' I want an Edit icon (pencil) visible. As soon as more than one item is selected, I want the Edit icon to disappear from the options.
The code below: I tried to create a condition in which mDeletionMode creates a menu with an Edit icon present if the number of selected items was <= 1 , and create a menu without the pencil if the number was more than one. My approach was foolish, as I realize that the menu is only created after an item experiences a longClick, and of course only one item would have been selected at that point. I left the dumb-dumb code I used to try this just to show my approach, while what I am actually looking for is the following:
public class SubjectManagerFragment extends BaseFragment implements ActionMode.Callback {
public static ArrayList<SubjectInfo> subjectList = new ArrayList<SubjectInfo>();
public static FloatingActionButton fabCreateSubject;
private AlertDialog.Builder build;
private MultiSelector mMultiSelector = new MultiSelector();
public ActionMode actionMode;
public RecyclerView recList;
public CardView cardView;
public ItemClickSupport itemClick;
// currently an adaptation from:
// https://github.com/bignerdranch/recyclerview-multiselect#modal-multiselection-with-long-click
public ActionMode.Callback mDeleteMode = new ModalMultiSelectorCallback(mMultiSelector) {
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
super.onCreateActionMode(actionMode, menu);
if (mMultiSelector.getSelectedPositions().size() <= 1) {
getActivity().getMenuInflater().inflate(R.menu.menu_subject_manager, menu);
} else {
getActivity().getMenuInflater().inflate(R.menu.menu_subject_manager_multiple, menu);
}
return true;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_select_all:
// Delete crimes from model
//actually do nothing.
mMultiSelector.clearSelections();
return true;
default:
break;
}
return false;
}
};
public static final String ARG_PARAM1 = "param1";
public static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
public static SubjectManagerFragment newInstance(String param1, String param2) {
SubjectManagerFragment fragment = new SubjectManagerFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
public SubjectManagerFragment() {
// Required empty public constructor
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
//non graphical initialization
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(false);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View smFragmentView = inflater.inflate(R.layout.fragment_subject_manager, container, false);
recList = (RecyclerView) smFragmentView.findViewById(R.id.subject_card_list);
cardView = (CardView) smFragmentView.findViewById(R.id.subject_card);
recList.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
llm.setOrientation(LinearLayoutManager.VERTICAL);
subjectList = getSubjectInfoArrayList();
recList.setLayoutManager(llm);
recList.setAdapter(new CrimeAdapter());
fabCreateSubject = (FloatingActionButton) smFragmentView.findViewById(R.id.fab_create_subject);
fabCreateSubject.setOnClickListener (new View.OnClickListener() {
#Override
public void onClick(View v) {
build = new AlertDialog.Builder(getActivity());
LayoutInflater inflater1 = getActivity().getLayoutInflater();
View alertview = inflater1.inflate(R.layout.create_subject_dialog, null);
// Pass null as the parent view because its going in the dialog layout
build.setView(alertview);
final EditText inputSubjectName = (EditText) alertview.findViewById(R.id.dialog_edit_subject_card_name);
final EditText inputSubjectGrade = (EditText) alertview.findViewById(R.id.dialog_edit_subject_card_grade);
build.setTitle("Add Subject");
build.setPositiveButton("Save", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
String enteredSubjectName = inputSubjectName.getText().toString();
int enteredSubjectGrade = Integer.parseInt("0" + inputSubjectGrade.getText().toString()); //was getting stupid error from null value going to int?
boolean enteredSubjectIsArchived = false;
if (subjectCanBeEntered(inputSubjectName, inputSubjectGrade, subjectList)) {
SubjectInfo si = new SubjectInfo(enteredSubjectName, "Assignments", enteredSubjectGrade, enteredSubjectIsArchived, true);
si.save();
subjectList.add(si);
getActivity().recreate();
sa.notifyDataSetChanged();
recList.smoothScrollToPosition(subjectList.size()-1);
} //will need to check if subject already exists, but YOLO for now.
dialog.cancel();
}
});
build.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = build.create();
alert.show();
}
});
// Inflate the layout for this fragment
return smFragmentView;
}
public ArrayList<SubjectInfo> getSubjectInfoArrayList(){
ArrayList<SubjectInfo> sial= new ArrayList<SubjectInfo>();
List<SubjectInfo> sil = SubjectInfo.listAll(SubjectInfo.class);
sial.addAll(sil);
for (int go = 0; go <sial.size(); go++) {
if (sial.get(go).itemHeaderTitle.equals("Archived")) {
sial.remove(go);
}
}
return sial;
}
public boolean subjectCanBeEntered (EditText inputName, EditText inputGrade, ArrayList<SubjectInfo> aList) {
boolean enterable = true;
if ((inputName.getText().toString().equals(""))) {
enterable = false;
Toast.makeText(
getActivity().getApplicationContext(), "Enter a class name.", Toast.LENGTH_SHORT).show();
}
if ((inputGrade.getText().toString().equals(""))) { // I don't think hint is picked up
enterable = false;
Toast.makeText(
getActivity().getApplicationContext(), "Enter a grade.", Toast.LENGTH_SHORT).show();
}
for (int go = 0; go < aList.size(); go++) {
if (inputName.getText().toString().equals(aList.get(go).subjectName)) {
enterable = false;
Toast.makeText(
getActivity().getApplicationContext(), "You've already saved a class with that name.", Toast.LENGTH_LONG).show();
}
}
return enterable;
}
private class CrimeHolder extends SwappingHolder
implements View.OnClickListener, View.OnLongClickListener {
protected TextView vSubjectName;
protected EditText vSubjectGrade;
protected RelativeLayout vSubjectLayout;
private SubjectInfo sInfo;
public CrimeHolder(View itemView) {
super(itemView, mMultiSelector);
vSubjectName = (TextView) itemView.findViewById(R.id.subject_card_name_textView);
vSubjectGrade = (EditText) itemView.findViewById(R.id.subject_card_grade_editText);
vSubjectLayout = (RelativeLayout) itemView.findViewById(R.id.subject_card_relative_layout);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
itemView.setLongClickable(true);
}
public void bindCrime(SubjectInfo si) {
sInfo = si;
vSubjectName.setText(sInfo.subjectName);
vSubjectGrade.setText(Integer.toString(si.subjectGrade));
vSubjectLayout.setBackgroundColor(Color.parseColor(SubjectAdapter.giveSubjectHexValue((double) si.subjectGrade)));
}
#Override
public void onClick(View v) {
if (sInfo == null) {
return;
}
if (!mMultiSelector.tapSelection(this)) {
// This condition is the same as, if not in ActionMode, handle the click normally:
//getActionBar().startActionMode(mDeleteMode);
}
}
#Override
public boolean onLongClick(View v) {
//ActionBarActivity activity = (ActionBarActivity)getActivity();
getActionBar().startActionMode(mDeleteMode);
mMultiSelector.setSelected(this, true);
return true;
}
}
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
#Override
public CrimeHolder onCreateViewHolder(ViewGroup parent, int pos) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.subject_card_layout, parent, false);
return new CrimeHolder(view);
}
#Override
public void onBindViewHolder(CrimeHolder holder, int pos) {
SubjectInfo sInfo = subjectList.get(pos);
holder.bindCrime(sInfo);
}
#Override
public int getItemCount() {
return subjectList.size();
}
}
}
SO my question is: how to programmatically either remove/add the Edit icon OR switch to the other menu (with one fewer option) depending on how may items are selected.
Use an ActionMode instance to manipulate the ActionBar menu.
#Override
public boolean onLongClick(View v) {
this.actionMode = getActionBar().startActionMode(mDeleteMode);
mMultiSelector.setSelected(this, true);
return true;
}
Below is where your menuItem gets initialized. Keep in mind that onCreateActionMode resides in the creation of the new ModalMultiSelectorCallback.
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
super.onCreateActionMode(actionMode, menu);getActivity().getMenuInflater().inflate(R.menu.menu_subject_manager, menu);
mEditItem = actionMode.getMenu().findItem(R.id.action_edit);
mActionMenu = actionMode.getMenu();
return true;
}
Now, mEditItem can be removed or replaced with ease, as mEditItem is an instance variable. I'll provide my implementation in my onClick()
#Override
public void onClick(View v) {
if (sInfo == null) {
return;
}
if (!mMultiSelector.tapSelection(this)) {
// if not in selection mode, this is handled
}
if (mMultiSelector.tapSelection(this)) {
mMultiSelector.tapSelection(this);
switch (mMultiSelector.getSelectedPositions().size()) {
case 0:
actionMode.finish();
break;
case 1:
mEditItem.setVisible(true);
break;
case 2:
mEditItem.setVisible(false);
break;
default:
break;
}
}
}
And there I have it. For me, I just needed an item to disappear/reappear according to how many items were selected at any given moment. The .setVisible() method took care of this for me. I hope this helps someone with a similar issue!

Calling notifyDataSetChanged() outside of the Fragment it is in

I'm writing an application that allows for the sharing of recipes. When one receives a recipe, they can save it to their phone and it will appear as a fragment of a list.
Problem is, when I save it, I get an IllegalStateException for not calling NotifyDataSetChanged(), which I can't find a way to do in the Activity that I am in. If anyone knows how I can find a way to get access to the adapter that calls this, that would be greatly appreciated. Making it static didn't seem to be an option.
public class SmsViewActivity extends Activity {
private static final String TAG = "SmsViewActivity";
private static final String SMS_FOOD = "food_recieved";
private FoodJSONSerializer mSerializer;
public Button mSaveButton, mDismissButton;
public int mNotificationId;
public String message;
private EditText mTitleField;
private EditText mServingsField;
private EditText mDirectionsField;
Food mFood;
private String msg;
private Activity mActivity;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Log.i(TAG, "OnCreate");
mActivity = this;
setContentView(R.layout.sms_view);
mSaveButton = (Button) findViewById(R.id.save_button_sms);
mDismissButton = (Button) findViewById(R.id.dismiss_button_sms);
// ------------------------------------------------------------
// Get extras and display information in view
//String sender = getIntent().getStringExtra("sender");
this.msg = getIntent().getStringExtra("message");
try {
JSONObject jsonRecipe = new JSONObject(this.msg);
this.mFood = new Food(jsonRecipe);
Log.i(TAG, "Food = " + mFood);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// -----------------------------------------------------------------------
mNotificationId = getIntent().getIntExtra("notificationid", 0);
if (mNotificationId == 0) {
Log.e(TAG, "Could not retrieve notification ID.");
Toast.makeText(this, "A fatal error has occurred in SMS viewer.",
Toast.LENGTH_LONG).show();
finish();
}
// Cancel the notification
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager notificationMgr = (NotificationManager) getSystemService(ns);
notificationMgr.cancel(mNotificationId);
// --------------------------------------------------
this.mTitleField = (EditText) findViewById(R.id.food_title_sms);
this.mTitleField.setText(mFood.getTitle());
this.mServingsField = (EditText) findViewById(R.id.food_servings_sms);
this.mServingsField.setText(Integer.toString(mFood.getServings()));
this.mDirectionsField = (EditText) findViewById(R.id.directions_text_sms);
this.mDirectionsField.setText(mFood.getDirections());
// --------------------------------------------------
// Listener for Save button click
this.mSaveButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
FoodStorage.get(mActivity).addFood(mFood);
//NEED TO CALL notifyDataSetChanged(); HERE
finish();
}
});
// Listener for Dismiss button click
this.mDismissButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
backToList();
finish();
}
});
}
public void backToList() {
Intent i = new Intent(this, FoodListActivity.class);
startActivity(i);
}
}
Here is the Fragment where the adapter lives and where every other instance of adding or deleting occurs.
public class FoodListFragment extends ListFragment{
private ArrayList<Food> mFood;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
getActivity().setTitle(R.string.food_title);
mFood = FoodStorage.get(getActivity()).getFood();
FoodAdapter adapter = new FoodAdapter(mFood);
setListAdapter(adapter);
}
#TargetApi(11)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v = super.onCreateView(inflater, parent, savedInstanceState);
ListView listView = (ListView)v.findViewById(android.R.id.list);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Use floating context menus on Froyo and Gingerbread
registerForContextMenu(listView);
} else {
// Use contextual action bar on Honeycomb and higher
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
// Required, but not used in this implementation
}
// ActionMode.Callback methods
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.food_list_item_context, menu);
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
// Required, but not used in this implementation
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_delete_food:
FoodAdapter adapter = (FoodAdapter)getListAdapter();
FoodStorage foodStorage = FoodStorage.get(getActivity());
for (int i = adapter.getCount() - 1; i >= 0; i--) {
if (getListView().isItemChecked(i)) {
foodStorage.deleteFood(adapter.getItem(i));
}
}
mode.finish();
adapter.notifyDataSetChanged();
return true;
default:
return false;
}
}
public void onDestroyActionMode(ActionMode mode) {
// Required, but not used in this implementation
}
});
}
return v;
}
public void onListItemClick(ListView l, View v, int position, long id) {
// get the Food from the adapter
Food c = ((FoodAdapter)getListAdapter()).getItem(position);
// start an instance of CrimePagerActivity
Intent i = new Intent(getActivity(), FoodPagerActivity.class);
i.putExtra(FoodFragment.EXTRA_FOOD_ID, c.getId());
startActivityForResult(i, 0);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
((FoodAdapter)getListAdapter()).notifyDataSetChanged();
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_food_list, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new_food:
Food food = new Food();
FoodStorage.get(getActivity()).addFood(food);
Intent i = new Intent(getActivity(), FoodPagerActivity.class);
i.putExtra(FoodFragment.EXTRA_FOOD_ID, food.getId());
startActivityForResult(i, 0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
getActivity().getMenuInflater().inflate(R.menu.food_list_item_context, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
int position = info.position;
FoodAdapter adapter = (FoodAdapter)getListAdapter();
Food food = adapter.getItem(position);
switch (item.getItemId()) {
case R.id.menu_item_delete_food:
FoodStorage.get(getActivity()).deleteFood(food);
adapter.notifyDataSetChanged();
return true;
}
return super.onContextItemSelected(item);
}
private class FoodAdapter extends ArrayAdapter<Food> {
public FoodAdapter(ArrayList<Food> food) {
super(getActivity(), android.R.layout.simple_list_item_1, food);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// if we weren't given a view, inflate one
if (null == convertView) {
convertView = getActivity().getLayoutInflater()
.inflate(R.layout.list_item_food, null);
}
// configure the view for this recipe
Food c = getItem(position);
TextView titleTextView =
(TextView)convertView.findViewById(R.id.food_list_item_titleTextView);
titleTextView.setText(c.getTitle());
TextView servingsTextView =
(TextView)convertView.findViewById(R.id.food_list_item_servingsTextView);
servingsTextView.setText("Makes " + c.getServings() + " servings");
TextView ingredientsTextView = (TextView) convertView
.findViewById(R.id.food_list_item_ingredientsTextView);
JSONArray j = c.jIngredients;
String display = "";
for (int i = 0; i < j.length(); i++) {
try {
display = display + j.get(i) + "\n";
} catch (JSONException e) {
// Do nothing.
e.printStackTrace();
}
}
ingredientsTextView.setText("Ingredients:\n" + display);
TextView directionsTextView =
(TextView)convertView.findViewById(R.id.food_list_item_directionsTextView);
directionsTextView.setText("Directions:\n " + c.getDirections());
return convertView;
}
}
}
You may use Eventbus from greenrobot. It provides you with a way to post events anywhere to any subscriber who can receive the event and call any method.
In the onCreate method of your fragment, call this EventBus.getDefault().register(this); to register your fragment as a subscriber.
Create a new method in your fragment: public void onEvent(AnyEventType event) {}. When an event is posted on the event bus, this method will be called. you may call adapter.notifyDatasetChanged() in the onEvent method. AnyEventType can be just any class (can be a POJO). You may use this class to pass any info to your fragment.
In your activity, you can call EventBus.getDefault().post(event); to notify your fragment. The onEvent method in your fragment will be executed when the event is posted.
Refer to the EventBus readme for more info.

Categories

Resources