我试图在一个理财应用中添加一个新的费用,当我点击类别按钮添加类别时,该应用关闭了。 我在Android Studio中得到了一个错误消息,看到这个图像:在这里输入图像描述
NewEntryFragment.Class:
public class NewEntryFragment extends Fragment {
private static final String TAG = "NewEntryFragment";
public static final String DATE = "_date";
private View view;
private TextView expenseCategoryInput;
private EditText expenseAmountInput;
private TextView expenseDateInput;
private EditText expenseNoteInput;
private DatePickerDialog.OnDateSetListener onDateSetListener;
private ExpenseDAO expenseDAO;
private CategoryDAO categoryDAO;
private DatabaseHandler databaseHandler;
private Fragment fragment;
private ListView categoryListView;
private AlertDialog.Builder showBuilder;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.new_entry_layout, container, false);
// Instantiate database
expenseDAO = new ExpenseDAO(getActivity());
// Get UI
expenseCategoryInput = (TextView) view.findViewById(R.id.expenseCategoryInput);
expenseAmountInput = (EditText) view.findViewById(R.id.expenseAmountInput);
expenseDateInput = (TextView) view.findViewById(R.id.expenseDateInput);
expenseNoteInput = (EditText) view.findViewById(R.id.expenseNoteInput);
Button saveButton = (Button) view.findViewById(R.id.saveButton);
// Get HomeFragment
fragment = getFragmentManager().findFragmentByTag("HomeFragment");
if(fragment == null) {
fragment = new HomeFragment();
}
// Set onClickListeners
expenseCategoryInput.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showCategoryDialog();
}
});
expenseDateInput.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Calendar calendar = Calendar.getInstance();
// Get current year, month and day
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(getActivity(), android.R.style.Theme_Holo_Light_Dialog,
onDateSetListener, year, month, day);
datePickerDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
datePickerDialog.show();
}
});
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Add expense to database and return to HomeFragment
saveButtonClicked();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentContainer, fragment);
transaction.commit();
}
});
// Set date listener
onDateSetListener = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker datePicker, int year, int month, int day) {
month++; // since MONTH starts from 0
String date = day + "/" + month + "/" + year;
expenseDateInput.setText(date);
}
};
return view;
}
@Override
public void onStart() {
super.onStart();
Bundle bundle = getArguments();
if (bundle != null) {
String calendarDate = bundle.getString(DATE);
expenseDateInput.setText(calendarDate);
} else {
expenseDateInput.setText((new HomeFragment()).getTodayDate());
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
view = null;
}
private void saveButtonClicked() {
// If category and amount is not empty
if (expenseCategoryInput.getText().toString().length() != 0 && expenseAmountInput.length() != 0) {
double expenseAmountInputDouble = Double.parseDouble(expenseAmountInput.getText().toString());
double expenseAmountInputRounded = Math.round(expenseAmountInputDouble * 100.0) / 100.0; // Round to 2 decimal places
long expenseAmountInputInCents = (long) (expenseAmountInputRounded * 100); // Store amount in cents
Expense expense = new Expense(
expenseCategoryInput.getText().toString(),
expenseAmountInputInCents,
expenseDateInput.getText().toString(),
expenseNoteInput.getText().toString());
expenseDAO.addExpense(expense);
} else {
Toast.makeText(getActivity(), "You must select a category and enter an amount!", Toast.LENGTH_LONG).show();
}
}
private void showCategoryDialog() {
showBuilder = new AlertDialog.Builder(getActivity());
showBuilder.setTitle("Select a Category");
showBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int id) {
dialogInterface.cancel();
}
});
showBuilder.setPositiveButton("+ New Category", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// Create another dialog
AlertDialog.Builder newBuilder = new AlertDialog.Builder(getActivity());
LayoutInflater newLayoutInflater = getActivity().getLayoutInflater();
View newCategoryView = newLayoutInflater.inflate(R.layout.new_category_dialog_layout, null);
newBuilder.setView(newCategoryView);
final EditText newCategoryInput = (EditText) newCategoryView.findViewById(R.id.newCategoryInput);
newBuilder.setTitle("Add New Category");
newBuilder.setPositiveButton("Save", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// Make sure category is not empty, add category and return
if (newCategoryInput.getText().toString().length() != 0) {
categoryDAO.addCategory(newCategoryInput.getText().toString());
} else {
Toast.makeText(getActivity(), "Please enter a category name!", Toast.LENGTH_LONG).show();
}
dialogInterface.dismiss();
}
});
newBuilder.show();
}
});
populateCategoryListView();
showBuilder.show();
}
private void populateCategoryListView() {
// Get categories
Cursor cursor = categoryDAO.getCategory();//this is where the debugger shows the cate,goryDAO is null
// Store categories in an ArrayList
ArrayList<String> categoryArrayList = new ArrayList<>();
if (cursor.moveToFirst()) {
do {
String categoryName = cursor.getString(0);
categoryArrayList.add(categoryName);
} while (cursor.moveToNext());
}
// Create and set ArrayAdapter
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.select_dialog_item, categoryArrayList);
showBuilder.setAdapter(arrayAdapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
String categoryName = arrayAdapter.getItem(i);
expenseCategoryInput.setText(categoryName);
dialogInterface.dismiss();
}
});
}
}
DatabaseHandler.class:
public class DatabaseHandler extends SQLiteOpenHelper {
private static DatabaseHandler databaseHandler;
// Database info
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "account.db";
// Tables
public static final String TABLE_ACCOUNT = "account";
public static final String TABLE_EXPENSE = "expense";
public static final String TABLE_INCOME = "income";
public static final String TABLE_CATEGORY = "category";
public static final String COLUMN_USER = "_user";
public static final String COLUMN_PASSWORD = "_password";
// Expense and income table columns
public static final String COLUMN_ID = "_id";
public static final String COLUMN_AMOUNT = "_amount";
public static final String COLUMN_DATE = "_date";
public static final String COLUMN_NOTE = "_note";
// Common columns
public static final String COLUMN_CATEGORY = "_category";
// Create expense table statement
private static final String CREATE_EXPENSE = "CREATE TABLE " + TABLE_EXPENSE + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_CATEGORY + " TEXT NOT NULL, " +
COLUMN_AMOUNT + " INTEGER NOT NULL, " +
COLUMN_DATE + " TEXT NOT NULL, " +
COLUMN_NOTE + " TEXT" +
");";
private static final String CREATE_INCOME = "CREATE TABLE " + TABLE_INCOME + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_CATEGORY + " TEXT NOT NULL, " +
COLUMN_AMOUNT + " INTEGER NOT NULL, " +
COLUMN_DATE + " TEXT NOT NULL, " +
COLUMN_NOTE + " TEXT" +
");";
// Create category table statement
private static final String CREATE_CATEGORY = "CREATE TABLE " + TABLE_CATEGORY + " (" +
COLUMN_CATEGORY + " TEXT PRIMARY KEY NOT NULL " +
");";
private static final String CREATE_ACCOUNT = "CREATE TABLE " + TABLE_ACCOUNT + " (" +
COLUMN_USER + " TEXT PRIMARY KEY NOT NULL, " +
COLUMN_PASSWORD + " TEXT NOT NULL" +
");";
public static DatabaseHandler getInstance(Context context) {
if (databaseHandler == null) {
databaseHandler = new DatabaseHandler(context.getApplicationContext());
}
return databaseHandler;
}
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(CREATE_ACCOUNT);
sqLiteDatabase.execSQL(CREATE_EXPENSE);
sqLiteDatabase.execSQL(CREATE_INCOME);
sqLiteDatabase.execSQL(CREATE_CATEGORY);
addDefaultCategories(sqLiteDatabase);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_EXPENSE);
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_INCOME);
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_CATEGORY);
onCreate(sqLiteDatabase);
}
public void addDefaultCategories(SQLiteDatabase sqLiteDatabase) {
ContentValues contentValues = new ContentValues();
String[] defaultCategories = {"food", "clothing", "entertainment"};
for(String defaultCategory : defaultCategories) {
contentValues.put(COLUMN_CATEGORY, defaultCategory);
sqLiteDatabase.insert(TABLE_CATEGORY, null, contentValues);
}
}
CategoryDao.class:
public class CategoryDAO {
private DatabaseHandler databaseHandler;
private SQLiteDatabase db;
public CategoryDAO(Context context) {
databaseHandler = new DatabaseHandler(context);
}
public static final String TABLE_EXPENSE = "expense";
public static final String TABLE_CATEGORY = "category";
// Common columns
public static final String COLUMN_CATEGORY = "_category";
// Category table CRUD
public void addCategory(String categoryName) {
db = databaseHandler.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COLUMN_CATEGORY, categoryName);
db.insert(TABLE_CATEGORY, null, contentValues);
}
public void deleteCategory(String categoryName) {
db = databaseHandler.getWritableDatabase();
String selection = COLUMN_CATEGORY + " LIKE ?";
String[] selectionArgs = { categoryName };
db.delete(TABLE_CATEGORY, selection, selectionArgs);
}
public void updateCategory(String oldCategoryName, String newCategoryName) {
db = databaseHandler.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COLUMN_CATEGORY, newCategoryName);
String selection = COLUMN_CATEGORY + " LIKE ?";
String[] selectionArgs = { oldCategoryName };
db.update(TABLE_CATEGORY, contentValues, selection, selectionArgs);
db.update(TABLE_EXPENSE, contentValues, selection, selectionArgs); // Also update expenses' categoryName
}
// For categoryListView
public Cursor getCategory() {
db = databaseHandler.getWritableDatabase() ;
String[] projection = {
COLUMN_CATEGORY
};
Cursor cursor = db.query(TABLE_CATEGORY, projection, null, null, null, null, COLUMN_CATEGORY + " ASC");
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}
}
那么,为什么categoryDAO为null因而游标为null呢? 如何修复?
你应该加上
// Instantiate database
expenseDAO = new ExpenseDAO(getActivity());
categoryDAO = new CategoryDAO(getActivity()); // This was missing