在安卓系统中,java.lang.NullPointerException,数据库可能无法启动,但为什么?

问题描述 投票:0回答:1

我试图在一个财务管理应用程序中添加一个新的费用,当我点击类别按钮添加一个类别时,应用程序关闭了,我在Android Studio中得到了一个错误信息,看到这个图片。请在这里输入图片描述

NewEntryFragment.类。

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是空的,所以游标是空的?如何解决这个问题?

android nullpointerexception
1个回答
0
投票

你应该添加

    // Instantiate database
    expenseDAO = new ExpenseDAO(getActivity());
    categoryDAO = new CategoryDAO(getActivity()); // This was missing
© www.soinside.com 2019 - 2024. All rights reserved.