Ok, I do realize there are allot of posts related to context menus and listViews. I have looked at over 20 pages and none have been able to fix my issue. I am able to remove an item from the listView but my application skips over the notifyDataSetChanged. The arrayList for the listView and listView itself are only static because I add to it from a separate activity. Here is my code...
/**
* Activity to complete trash audits.
* @author John D. Miller
* @version 1.0.1
* @since 12/06/2015
*/
package com.example.chefj.hometrashaudit;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.ContextMenu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Scanner;
public class HomeTrashAuditActivity extends AppCompatActivity {
static ListView listView;
static EditText dateText;
static ArrayList<Waste> items = new ArrayList<>();
ArrayAdapter<Waste> listAdapter;
ArrayList<Waste> wasteList = new ArrayList<>();
DateFormat df = DateFormat.getDateInstance(DateFormat.DEFAULT);
File journalFile = new File("Journal.txt");
File settingsFile = new File("Settings.txt");
// Context Menu
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.listview_context_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item)
{
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch(item.getItemId())
{
case R.id.edit:
// TODO launch activity to edit item...
return true;
case R.id.remove:
// Remove the item
items.remove(info.position);
Here is the line of code not being executed...
listAdapter.notifyDataSetChanged();
return true;
default:
return super.onContextItemSelected(item);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_trash_audit);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Context Configuration
listView = (ListView)findViewById(R.id.listView);
registerForContextMenu(listView);
// Adapter Configuration
listAdapter = new ArrayAdapter<Waste>(this, android.R.layout.simple_list_item_1, items);
listView.setAdapter(listAdapter);
// Setting current date
Date date = new Date();
String dat = df.format(date);
dateText = (EditText) findViewById(R.id.dateText);
dateText.setKeyListener(null);
dateText.setText(dat);
// Pick waste button listener
listView = (ListView) findViewById(R.id.listView);
Button pickWasteButton = (Button) findViewById(R.id.pickWasteButton);
pickWasteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), WasteSelectionActivity.class);
startActivity(i);
}
});
// Date button listener
Button dateButton = (Button) findViewById(R.id.dateButton);
dateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), DateActivity.class);
startActivity(i);
}
});
// Add to journal button listener
Button addToJournalButton = (Button) findViewById(R.id.addToJournalButton);
addToJournalButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
// Empty Journal
if (listView.getAdapter() == null) {
Toast.makeText(HomeTrashAuditActivity.this, "You must first complete an audit before adding to Journal!!!", Toast.LENGTH_SHORT).show();
}
// Checking if audit exists for selected date
else if (dateExists())
{
Toast.makeText(HomeTrashAuditActivity.this, "An audit for this date has already been completed!!!", Toast.LENGTH_SHORT).show();
}
// Appending Journal
else
{
try
{
FileOutputStream os = openFileOutput("Journal.txt", Context.MODE_APPEND);
PrintWriter output = new PrintWriter(os);
String format = "%s\t\t%-14s\t%-6s\t %-6s";
// Header
output.println(dateText.getText().toString() + "\n");
output.printf(format, "Material", "Category", "Amount", "Total");
output.println("-----------------------------------------------------------------");
// Body
for (Waste w : items)
{
output.printf(format, w.getWasteMaterial(), w.getWasteCategory(), w.getAmount(), w.getPercentage());
output.println();
}
output.println("-----------------------------------------------------------------");
output.println();
// Closing PrintWriter
output.flush();
output.close();
// Confirmation
Toast.makeText(HomeTrashAuditActivity.this, "The journal was successfully updated!", Toast.LENGTH_SHORT).show();
// Resetting for additional audits
items = new ArrayList<>();
listAdapter.notifyDataSetChanged();
finish();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
});
}
/**
* Determines an audit has been created for the current audit.
* @return true or false.
*/
private boolean dateExists()
{
readInWasteList();
for (Waste wa : wasteList)
{
System.out.println(wa.toString());
}
//wasteList.sort(sorter);
for (Waste w : wasteList)
{
if (w.getDate().equals(dateText.getText().toString()))
{
return true;
}
}
return false;
}
/**
* Determines if a line is a date.
* @param line the line to be evaluated.
* @return true or false.
*/
private Boolean isDate(String line)
{
try
{
df.parse(line);
return true;
}
catch (ParseException e)
{
return false;
}
}
/**
* Reads into the wasteList from the file.
*/
private void readInWasteList()
{
ArrayList<String> lines = new ArrayList<>();
String date = "";
wasteList = new ArrayList<>();
// Reading in file
try
{
File journalFile = getBaseContext().getFileStreamPath("Journal.txt");
Scanner reader = new Scanner(journalFile);
// Reading File
while (reader.hasNextLine())
{
lines.add(reader.nextLine());
}
}
catch (FileNotFoundException ex)
{
// Do nothing, already handled.
}
// Processing information to fill list
for (String line : lines)
{
if (isDate(line))
{
date = line;
}
// Empty line
else if (line.equals("")){}
// Header
else if (line.contains("Material")){}
// Audit Separator
else if (line.contains("--")){}
// Process data
else
{
Waste waste = new Waste();
Scanner lineReader = new Scanner(line);
waste.setDate(date);
waste.setWasteMaterial(lineReader.next());
waste.setWasteCategory(lineReader.next());
waste.setAmount(lineReader.nextDouble());
wasteList.add(waste);
lineReader.close();
}
}
}
}
I don't like how you're assuming the ArrayAdapter
always keeps its reference to the same list you passed on the constructor. There are scenarios -- for example when you are using getFilter()
-- that the ArrayAdapter
will change its reference to a new list.
Change
items.remove(info.position);
listAdapter.notifyDataSetChanged();
to
listAdapter.remove(info.position); // automatically calls notifyDataSetChanged
If that works, you should go through and modify the code everywhere you change the items list and assume the ArrayAdapter
also changes under the hood.
Also keep in mind that ArrayList.remove()
assumes the equals()
method is defined correctly for your usage. You may want to check if your equals()
implementation is causing heartburn.