Calling notifyDataSetChanged() outside of the Fragment it is in - android

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.

Related

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);

listview adapter not updating after removing an item

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;
}

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!

Refresh ListView (with BaseAdapter) after SQLiteDatabase data changed

Firstly, I want to apologize for asking this question, because I know that there are a lot similar ones here, but none of the answers solve my problem.
As the title of the question suggests I need to populate ListView with new items when data in SQLiteDatabase changes.
To be more specific...
I have an activity that shows contacts in a ListView. At the bottom of the screen I have a button that adds a contact (A Dialog pops up with fields for name, phone number etc...).
When an item in the list is clicked another Dialog is opened. In that dialog there are 3 buttons for SendSMS (to the selected contact), Edit and Delete contact.
When I fill in the form for adding new contact, or click the Delete button, I want the ListView to refresh.
It doesn't happen. In order to see the updated list I need to navigate back, and start the Contacts activity again.
Here is the code:
Activity:
public class ContactsActivity extends Activity {
private MyUtilities myUtilities;
private MyDatabaseHelper mdbh;
private AdapterContactListView contactsAdapter;
private ListView contactsListView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contacts);
mdbh = new MyDatabaseHelper(this);
myUtilities = new MyUtilities(this);
contactsAdapter = new AdapterContactListView(this,mdbh);
contactsListView = (ListView)findViewById(R.id.contactActivityLV);
contactsListView.setAdapter(contactsAdapter);
contactsAdapter.notifyDataSetChanged();
contactsListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// TODO Auto-generated method stub
TextView phoneNumberTV = (TextView)view.findViewById(R.id.contactElementNumberTV);
String phoneNumber = phoneNumberTV.getText().toString();
Contact contact = mdbh.getContactFromPhoneNumber(phoneNumber);
Dialog d = myUtilities.createSelectedContactOptionsDialog(contact);
d.show();
contactsAdapter.updateAdapter(mdbh.getAllContacts());
}
});
public void addContact(View view) {
Dialog d = myUtilities.createAddContactDialog();
d.show();
contactsAdapter.updateAdapter(mdbh.getAllContacts());
}
}
The Adater:
private List<Contact> allContacts;
private int numberOfContacts;
private MyDatabaseHelper mdbh;
private Context context;
public AdapterContactListView(Context c, MyDatabaseHelper m) {
super();
context = c;
mdbh = m;
allContacts = mdbh.getAllContacts();
numberOfContacts = allContacts.size();
}
public void updateAdapter(List<Contact> cs) {
allContacts = cs;
numberOfContacts = allContacts.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = convertView;
if (view == null) {
LayoutInflater li = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = li.inflate(R.layout.contact_element, null);
}
String fullName = allContacts.get(position).getFirstName();
fullName = fullName.concat(" ");
fullName = fullName.concat(allContacts.get(position).getLastName());
TextView contactName = (TextView)view.findViewById(R.id.contactElementNameTV);
TextView phoneNumber = (TextView)view.findViewById(R.id.contactElementNumberTV);
contactName.setText(fullName);
phoneNumber.setText(allContacts.get(position).getPhoneNumber());
return view;
}
The job of the dialogs is to do operations with the database (update, add, delete).
I tried placing the notifyDataSetChanged() right after updateAdapter() and in the updateAdapter() method itself, but none of that works.
One thing I think I might be missing:
The definition notifyDataSetChanged() says that it notifies attached observers. I have no attached observers, but in all the answers that I have read no one mentioned anything about attaching an observer. If you think this is the problem, please tell me how to do this.
Can someone, please, shed some light on this problem.
Thanks in advance.
To refresh your listview, either you can call a method from a list called notifydatasetchanged but that will only work when youll get the contacts in the contactsalllist. So what you need to do is that you should first get the new data in your arraylist and then call notifydataset changed on your listview.
Apart from that if you are using Contacts database I would recommend you using a simplecursoradapter instead of using the baseadapter but its completely upto you. Anyhow I have added the code for that as well. Let me know if it helps you.
/**
*
* #author Syed Ahmed Hussain
*/
public class TestListActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor>, MultiChoiceModeListener {
NotificationsAdapter mNotificationAdapter;
ListView mNotificationsListView;
TextView mTxtNotificationsInfo;
Button mBtnCreateNotification;
public static final String TAG = "NotificationsList";
// ---------------------------------------------------------------------------
#Override
protected void onCreate(Bundle pSavedInstanceState) {
super.onCreate(pSavedInstanceState);
setContentView(R.layout.fragment_notifications);
initializeUIElements();
// registerForContextMenu(mNotificationsListView);
getSupportLoaderManager().initLoader(0, null, this);
mNotificationsListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mNotificationsListView.setMultiChoiceModeListener(this);
}
// ---------------------------------------------------------------------------
/**
*
*/
private void initializeUIElements() {
mTxtNotificationsInfo = (TextView) findViewById(R.id.txtNotificationInfo);
mNotificationsListView = (ListView) findViewById(R.id.list_notifications);
mBtnCreateNotification = (Button) findViewById(R.id.btnAddNotification);
}
// ---------------------------------------------------------------------------
/**
*
*/
public void onCreateNewNotificationClick(View pV) {
Log.d(TAG, "onCreateNewNotificationClick");
Intent intent = new Intent(this, AddNewNotification.class);
startActivity(intent);
// setResult(0);
// finish();
}
// ---------------------------------------------------------------------------
#Override
public Loader<Cursor> onCreateLoader(int pId, Bundle pArgs) {
return new android.support.v4.content.CursorLoader(getApplicationContext(), NotificationsContentProvider.CONTENT_URI, null, null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> pLoader, Cursor pData) {
if (pData == null || pData.getCount() == 0) {
Log.d("pData", "is null");
showTextView();
return;
}
mNotificationAdapter = new NotificationsAdapter(this, R.layout.item_notification, pData, new String[] { NotificationDatabaseHelper.COL_TITLE }, new int[] {R.id.txtNotificationTitle}, 0);
mNotificationsListView.setAdapter(mNotificationAdapter);
}
#Override
public void onLoaderReset(Loader<Cursor> pLoader) {
}
// ---------------------------------------------------------------------------
/**
* Hides the list view. shows the textview
*/
private void showTextView() {
mNotificationsListView.setVisibility(View.GONE);
mTxtNotificationsInfo.setVisibility(View.VISIBLE);
}
// ---------------------------------------------------------------------
// Multi-choice list item
#Override
public boolean onCreateActionMode(ActionMode pMode, Menu pMenu) {
// Inflate the menu for the CAB
MenuInflater inflater = pMode.getMenuInflater();
inflater.inflate(R.menu.menu_list_item, pMenu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode pMode, Menu pMenu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode pMode, MenuItem pItem) {
switch (pItem.getItemId()) {
case 1:
Toast.makeText(getApplicationContext(), pItem.getTitle(), Toast.LENGTH_SHORT).show();
pMode.finish();
break;
case 2:
Toast.makeText(getApplicationContext(), pItem.getTitle(), Toast.LENGTH_SHORT).show();
pMode.finish();
break;
default:
break;
}
return true;
}
#Override
public void onDestroyActionMode(ActionMode pMode) {
}
#Override
public void onItemCheckedStateChanged(ActionMode pMode, int pPosition, long pId, boolean pChecked) {
}
// --------------------------------------------------------------------
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.actionbar_menu_items, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
}
**
Notification Adapter is a Simple Curser Adapter:
**
/**
*
* #author Syed Ahmed Hussain
*/
public class NotificationsAdapter extends SimpleCursorAdapter {
private LayoutInflater mLayoutInflater;
private Context mContext;
private int mLayout;
public NotificationsAdapter(Context pContext, int pLayout, Cursor pC, String[] pFrom, int[] pTo, int pFlags) {
super(pContext, pLayout, pC, pFrom, pTo, pFlags);
mLayout = pLayout;
mContext = pContext;
mLayoutInflater = LayoutInflater.from(mContext);
}
#Override
public View newView(Context pContext, Cursor pCursor, ViewGroup pParent) {
return mLayoutInflater.inflate(mLayout, null);
}
}
To get it updated whenever you have a change in records do notifydatasetchange or take a refresh cursor to get all the values. Recall the method which returns you the dataset/cursor.

listView isn't updating until I navigate up from the fragment and then go back?

I apologize for the awkward wording of my title, I'm not sure how to succinctly ask this question. I have a listView within a fragment called TaskListFragment. This fragment is started after a user selects a course from CourseListFragment, and it shows a list of tasks for that course. From here, the user can add a task. Upon saving that task, they are brought back to TaskListFragment, where the task does not appear. If you navigate up to get back to CourseListFragment and then select the course again, the task appears in the list. Likewise if I try to delete a task, it still shows in the list until I navigate up and go back again. Any idea why this might be happening?
Below is my TaskListFragment:
public class TaskListFragment extends ListFragment {
private ArrayList<Task> mTasks;
private static String courseName;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
courseName = getActivity().getIntent().getStringExtra("name");
getActivity().setTitle(courseName);
ArrayList<Task> alltasks = TaskLab.get(getActivity()).getTasks();
mTasks = filterTasks(alltasks);
TaskAdapter adapter = new TaskAdapter(mTasks);
setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
private ArrayList<Task> filterTasks(ArrayList<Task> tasks) {
ArrayList<Task> filteredTasks = new ArrayList<Task>();
for (Task t: tasks) {
if (t.getBelongsToCourse().equals(courseName)) {
filteredTasks.add(t);
}
}
return filteredTasks;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
//Get the Task from the adapter
Task t = ((TaskAdapter)getListAdapter()).getItem(position);
// Start TaskActivity for this task
Intent i = new Intent(getActivity(), TaskActivity.class);
i.putExtra(TaskFragment.EXTRA_TASK_ID, t.getId());
startActivity(i);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_task_list, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_new_task:
Task task = new Task();
task.setBelongsToCourse(courseName);
TaskLab.get(getActivity()).addTask(task);
Intent i = new Intent(getActivity(), TaskActivity.class);
i.putExtra(TaskFragment.EXTRA_TASK_ID, task.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.task_list_item_context, menu);
}
#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);
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.task_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_task:
TaskAdapter adapter = (TaskAdapter)getListAdapter();
TaskLab taskLab = TaskLab.get(getActivity());
for (int i = adapter.getCount() - 1; i >= 0; i--) {
if (getListView().isItemChecked(i)) {
taskLab.deleteTask(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;
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
int position = info.position;
TaskAdapter adapter = (TaskAdapter)getListAdapter();
Task task = adapter.getItem(position);
switch (item.getItemId()) {
case R.id.menu_item_delete_task:
TaskLab.get(getActivity()).deleteTask(task);
adapter.notifyDataSetChanged();
return true;
}
return super.onContextItemSelected(item);
}
#Override
public void onResume() {
super.onResume();
((TaskAdapter)getListAdapter()).notifyDataSetChanged();
}
private class TaskAdapter extends ArrayAdapter<Task> {
public TaskAdapter(ArrayList<Task> tasks) {
super(getActivity(), 0, tasks);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// If we weren't given a view, inflate one
if (convertView == null) {
convertView = getActivity().getLayoutInflater()
.inflate(R.layout.list_item_task, null);
}
// Configure the view for this Task
Task t = getItem(position);
TextView titleTextView =
(TextView)convertView.findViewById(R.id.task_list_item_titleTextView);
titleTextView.setText(t.getTitle());
TextView dateTextView =
(TextView)convertView.findViewById(R.id.task_list_item_dateTextView);
dateTextView.setText(t.getDate().toString());
CheckBox completedCheckBox =
(CheckBox)convertView.findViewById(R.id.task_list_item_completedCheckBox);
completedCheckBox.setChecked(t.isCompleted());
return convertView;
}
}
}
EDIT: Below is my TaskLab, which is used to add and delete tasks.
public class TaskLab {
private static final String TAG = "TaskLab";
private static final String FILENAME = "tasks.json";
private ArrayList<Task> mTasks;
private TaskJSONSerializer mSerializer;
private static TaskLab sTaskLab;
private Context mAppContext;
private TaskLab(Context appContext) {
mAppContext = appContext;
mSerializer = new TaskJSONSerializer(mAppContext, FILENAME);
try {
mTasks = mSerializer.loadTasks();
} catch (Exception e) {
mTasks = new ArrayList<Task>();
Log.e(TAG, "Error loading tasks: ", e);
}
}
public static TaskLab get(Context c) {
if (sTaskLab == null) {
sTaskLab = new TaskLab(c.getApplicationContext());
}
return sTaskLab;
}
public void addTask(Task t) {
mTasks.add(t);
}
public void deleteTask(Task t) {
mTasks.remove(t);
}
public boolean saveTasks() {
try {
mSerializer.saveTasks(mTasks);
Log.d(TAG, "Tasks saved to file");
return true;
} catch (Exception e) {
Log.e(TAG, "Error saving tasks: ", e);
return false;
}
}
public ArrayList<Task> getTasks() {
return mTasks;
}
public Task getTask(UUID id) {
for (Task t : mTasks) {
if (t.getId().equals(id)) {
return t;
}
} return null;
}
}

Categories

Resources