首页 > 解决方案 > 我的数据库应用程序已停止工作并且无法打开

问题描述

我目前正在开发一个使用 SQLite 数据库的 Android Studio 应用程序,该数据库可以存储汽车购买的客户记录,一旦单击 ADD 按钮,该应用程序就会停止。显然,有一个空对象引用。该应用程序有一个 MainActivity,它有一个添加按钮,允许用户添加客户数据库条目。单击时,应用程序应转到 CustomerRcrdActivity 以允许数据库条目,从那里用户应该能够添加、查看、更新或删除条目,所有这些条目应显示在屏幕上的原因。

我正在学习如何为 Android 创建应用程序,所以请善待。我不是要求你为我做任何事情,但请指出我正确的方向。我到处搜索输入,但担心我忽略了逻辑错误,我可以使用第二双眼睛。

任何有关此事的意见或提示将不胜感激。

非常感谢你,

下面是我怀疑可能有问题的代码,(我将包含 XML,以防万一我做错了什么)。

content_main.xml (它包括我想在添加条目时更新的列表视图)如果有更简单的方法,我不是一成不变的。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">

<TextView
    android:id="@+id/ContentMain_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:fontFamily="sans-serif-smallcaps"
    android:text="@string/content_main_title"
    android:textAlignment="center"
    android:textSize="20sp"
    android:textStyle="bold"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.027" />

<Button
    android:id="@+id/button_CR_add"
    android:layout_width="112dp"
    android:layout_height="wrap_content"
    android:layout_marginBottom="416dp"
    android:layout_marginEnd="8dp"
    android:layout_marginTop="7dp"
    android:onClick="buttonClicked"
    android:text="@string/ContentMain_button_CD_add"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.054"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/ContentMain_title"
    app:layout_constraintVertical_bias="0.022" />

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="486dp"
    android:layout_marginTop="8dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/button_CR_add">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
</android.support.constraint.ConstraintLayout>

省略了 CustomerRcrdActivity 的 XML

CustomerRcrdActivity.java

public class CustomerRcrdActivity extends AppCompatActivity
{

private EditText FName, LName, CarMake, CarModel, CarCost;
private String F_Name;
private String L_Name;
private String Car_Make;
private String Car_Model;
private double d_Car_Cost;
private DatabaseHandler dh;
private dataAdapter da;
private Customer dataModel;
private ListView lv;
private long mId;

//<<<<<<<<<< new class variables
private String original_FName, original_LName, original_CarMake, original_CarModel, original_CarCost;
private boolean mLoaded = false;
private Button mUpdateButton;
private Button mAddButton;
private Button mDeleteButton;
private ArrayList<Customer> mCustomers = new ArrayList<>();
private List<EditText> mAlleditTexts = new ArrayList<>();

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_customer_rcrd);

    // GET Intent THAT STARTED ACTIVITY
    Intent intent = getIntent();

    // INSTANTIATE DATABASE HANDLER
    dh = new DatabaseHandler(this);

    FName = findViewById(R.id.editText2_FName);
    LName = findViewById(R.id.editText2_LName);
    CarMake = findViewById(R.id.editText2_CarMake);
    CarModel = findViewById(R.id.editText2_CarModel);
    CarCost = findViewById(R.id.editText2_CarCost);
    lv = findViewById(R.id.listView);
    //<<<<<<<<<<< ADDED
    mAlleditTexts.add(FName);
    mAlleditTexts.add(LName);
    mAlleditTexts.add(CarMake);
    mAlleditTexts.add(CarModel);
    mAlleditTexts.add(CarCost);

    //<<<<<<<<<< END OF ADDED

    Button mViewButton = findViewById(R.id.button_CR_view);
    mAddButton = findViewById(R.id.button_CR_add);
    mUpdateButton = findViewById(R.id.button_CR_update);
    mDeleteButton = findViewById(R.id.button_CR_delete);

    mViewButton.setVisibility(View.GONE);                        // never Show and free screen space
    mViewButton.setText(R.string.mViewButton_setText);           // Hijack View Button for clear data
    mViewButton.setVisibility(View.VISIBLE);                     // Show the View (now CLEAR)
    mAddButton.setEnabled(false);                                // Can't click Add as nothing to add
    mUpdateButton.setEnabled(false);                             // Can't click Update nothing to update
    mDeleteButton.setEnabled(false);                             // Can't click Delete as nothing to delete
    setOriginalValues();
    ShowRecords();                                               //<<<< Always show the list no need for View button
    setEditTextFocusChangedListener(mAlleditTexts);
}

//<<<<<<<<<< NEW METHOD
private void setEditTextFocusChangedListener(List<EditText> edit_texts)
{
    for (EditText e: edit_texts)
    {
        e.setOnFocusChangeListener(new View.OnFocusChangeListener()
        {
            @Override
            public void onFocusChange(View view, boolean b)
            {
                if (areOriginalValuesChanged())
                {
                    if (mLoaded)
                    {
                        mUpdateButton.setEnabled(true);
                        mDeleteButton.setEnabled(false);
                        mAddButton.setEnabled(false);
                    } else
                    {

                    }
                } else
                {
                    if (!mLoaded)
                    {
                        mAddButton.setEnabled(true);
                    } else
                    {
                        mAddButton.setEnabled(false);
                    }
                }
            }
        });
    }
}

//<<<<<<<<<< NEW METHOD
private void setOriginalValues()
{
    original_FName = FName.getText().toString();
    original_LName = LName.getText().toString();
    original_CarMake = CarMake.getText().toString();
    original_CarModel = CarModel.getText().toString();
    original_CarCost = CarCost.getText().toString();
}

//<<<<<<<<<< NEW METHOD
private boolean areOriginalValuesChanged()
{
    /*if (original_FName.equals(FName.getText().toString())
            && original_LName.equals(LName.getText().toString())
            && original_CarMake.equals(CarMake.getText().toString())
            && original_CarModel.equals(CarModel.getText().toString())
            && original_CarCost.equals(CarCost.getText().toString())
            )
    {
        return false;
    }
    return true;*/
    return !original_FName.equals(FName.getText().toString())
            || !original_LName.equals(LName.getText().toString())
            || !original_CarMake.equals(CarMake.getText().toString())
            || !original_CarModel.equals(CarModel.getText().toString())
            || !original_CarCost.equals(CarCost.getText().toString());
}

//<<<<<<<<<< NEW METHOD
private void clearEditTexts(List<EditText> editTexts)
{
    for (EditText e: editTexts)
    {
        e.setText("");
    }
    setOriginalValues();
    mLoaded = false;
}

public void buttonClicked(View view)
{
    int id = view.getId();

    switch (id)
    {
        case R.id.button_CR_update:
            // CALL updateCustomer() TO UPDATE CUSTOMER RECORDS
            updateCustomer();
            mLoaded = false;
            break;

        case R.id.button_CR_add:
            // CALL addCustomer() TO ADD TO DATABASE
            addCustomer();
            // CLEAR FIELDS
            clearEditTexts(mAlleditTexts);
            mLoaded = false;
            break;

        case R.id.button_CR_delete:
            // CALL deleteCustomer() TO DELETE CUSTOMER RECORD
            deleteCustomer();
            break;

        case R.id.button_CR_view:
            // CLEAR FIELDS
            clearEditTexts(mAlleditTexts);
            mLoaded = false;
            mAddButton.setEnabled(true);
            mUpdateButton.setEnabled(false);
            mDeleteButton.setEnabled(false);
            break;
    }
    // UPDATE LIST IRRESPECTIVE OF BUTTON CLICKED
    ShowRecords();
}

// UPDATE CUSTOMER RECORD
private void updateCustomer()
{
    getValues();
    if (dh.updateCustomer(dataModel, mId)>0)
    {
        Toast.makeText(getApplicationContext(), "Customer Updated Successfully", Toast.LENGTH_LONG).show();
    } else
    {
        Toast.makeText(getApplicationContext(), "Customer Not Updated", Toast.LENGTH_LONG).show();
    }
}
// INSERT DATA INTO DATABASE
private void addCustomer()
{
    boolean ok_to_add = true;
    // GET VALUES FROM EditText
    getValues();
    if (F_Name == null || F_Name.length() < 1) ok_to_add = false;
    if (L_Name == null || L_Name.length() < 1) ok_to_add = false;
    if (Car_Make == null || Car_Make.length() < 1) ok_to_add = false;
    if (Car_Model == null || Car_Model.length() < 1) ok_to_add = false;
    if (ok_to_add)
    {
        dh.addCustomers(new Customer(F_Name, L_Name, Car_Make, Car_Model, d_Car_Cost));
        Toast.makeText(getApplicationContext(), "Customer Added Successfully", Toast.LENGTH_LONG).show();
    } else
    {
        Toast.makeText(getApplicationContext(), "Unable To Add - Some Data hasn't been given", Toast.LENGTH_LONG).show();
    }
}
// DELETE CUSTOMER RECORD
private void deleteCustomer()
{
    getValues();
    if (dh.deleteCustomer(mId))
    {
        Toast.makeText(getApplicationContext(), "Customer Deleted Successfully", Toast.LENGTH_LONG).show();
    } else
    {
        Toast.makeText(getApplicationContext(), "Customer Not Deleted", Toast.LENGTH_LONG).show();
    }
}

// FUNCTION TO GET VALUES FROM EditText
private void getValues()
{
    F_Name = FName.getText().toString();
    L_Name = LName.getText().toString();
    Car_Make = CarMake.getText().toString();
    Car_Model = CarModel.getText().toString();
    String car_Cost = CarCost.getText().toString();
    if (car_Cost.length() < 1)
    {
        car_Cost = "0.00";
    }
    d_Car_Cost = Double.parseDouble(car_Cost);

}
// RETRIEVE DATA FROM DATABASE & SET TO LIST VIEW
//<<<<<<<<<< CHANGED QUITE A BIT
// Introduced single Customer List with class scope rather than create new list and adapter every time
//      i.e. mCustomers
// Always clear mCustomers and rebuild from database
// if da (the adapter) is null and therefore hasn't been instantiated, instantiate it just once
// otherwise always notify the adapter that the data (mCustomer) has changed
// Added code to the Listener (added just the once now) to set the edit text's to the values
// of the clicked item in the list (load the data)
//  setting flag to say that the data has just been loaded.
//  also setting the original values to the new data
private void ShowRecords()
{
    mCustomers.clear();
    mCustomers.addAll(dh.getAllCustomers());

    if (da == null)
    {
        da = new dataAdapter(this, mCustomers);
        lv.setAdapter(da);

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
        {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)
            {
                dataModel = mCustomers.get(position);
                //<<<<<<<<<< Added
                FName.setText(dataModel.getFName());
                LName.setText(dataModel.getLName());
                CarMake.setText(dataModel.get_CarMake());
                CarModel.setText(dataModel.get_CarModel());
                CarCost.setText(String.valueOf(dataModel.get_CarCost()));
                mLoaded = true;
                setOriginalValues();
                mDeleteButton.setEnabled(true);
                mUpdateButton.setEnabled(false);
                mAddButton.setEnabled(false);
                mId = dataModel.getID();
                //<<<<<<<<<< End of Added
                Toast.makeText(getApplicationContext(), String.valueOf(dataModel.getID()), Toast.LENGTH_SHORT).show();
            }
        });
    } else
    {
        da.notifyDataSetChanged();
    }
}
}

数据库处理程序.java

public class DatabaseHandler extends SQLiteOpenHelper
{
// DATABASE VERSION
private static final int DATABASE_VERSION = 1;
// DATABASE NAME
private static final String DATABASE_NAME = "CARDEALER.db";
// CUSTOMER TABLE NAME
public static final String TABLE_CUSTOMERS = "Customers";


// CUSTOMER TABLE COLUMN NAMES
private static final String KEY_ID = "ID";
private static final String KEY_FNAME = "First";
private static final String KEY_LNAME = "Last";
private static final String KEY_CAR_MAKE = "Make";
private static final String KEY_CAR_MODEL = "Model";
private static final String KEY_CAR_COST = "Cost";

DatabaseHandler(Context context)
{
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// CREATE TABLES
@Override
public void onCreate(SQLiteDatabase dh)
{
    String CREATE_TABLE_CUSTOMERS = "CREATE TABLE " + TABLE_CUSTOMERS + "("
            + KEY_ID +" INTEGER PRIMARY KEY,"
            + KEY_FNAME +" TEXT,"
            + KEY_LNAME +" TEXT,"
            + KEY_CAR_MAKE  +" TEXT,"
            + KEY_CAR_MODEL +" TEXT,"
            + KEY_CAR_COST +" NUMERIC" + ")";
    dh.execSQL(CREATE_TABLE_CUSTOMERS);
}
// UPGRADING DATABASE
@Override
public void onUpgrade(SQLiteDatabase dh, int oldVersion, int newVersion)
{
    // DROP OLDER TABLE IF EXISTED
    dh.execSQL("DROP TABLE IF EXISTS " + TABLE_CUSTOMERS);

    // CREATE TABLES AGAIN
    onCreate(dh);
}
/**
 * All CRUD (CREATE, READ, UPDATE, DELETE) OPERATIONS
 */
// INSERT VALUES TO TABLE CUSTOMERS
public void addCustomers(Customer customer)
{
    SQLiteDatabase dh = this.getReadableDatabase();
    ContentValues values = new ContentValues();

    values.put(KEY_FNAME, customer.getFName());
    values.put(KEY_LNAME, customer.getLName() );
    values.put(KEY_CAR_MAKE, customer.get_CarMake());
    values.put(KEY_CAR_MODEL, customer.get_CarModel());
    values.put(KEY_CAR_COST, customer.get_CarCost());

    dh.insert(TABLE_CUSTOMERS, null, values);
    dh.close();
}
/**
 *GETTING ALL CUSTOMERS
 **/
public List<Customer> getAllCustomers()
{
    List<Customer> customerList = new ArrayList<Customer>();
    // SELECT ALL QUERY
    String selectQuery = "SELECT  * FROM " + TABLE_CUSTOMERS;

    SQLiteDatabase dh = this.getWritableDatabase();
    Cursor cursor = dh.rawQuery(selectQuery, null);

    // LOOP THROUGH ALL ROWS & ADD TO LIST
    if (cursor.moveToFirst())
    {
        do {
            Customer customer = new Customer();
            customer.setID(Integer.parseInt(cursor.getString(0)));
            customer.setFName(cursor.getString(1));
            customer.setLName(cursor.getString(2));
            customer.set_CarMake(cursor.getString(3));
            customer.set_CarModel(cursor.getString(4));
            customer.set_CarCost(cursor.getDouble(5));

            // ADDING CUSTOMER TO LIST
            customerList.add(customer);
        } while (cursor.moveToNext());
    }
    // CLOSE OUT RAW QUERY CALL
    cursor.close();
    // RETURN CUSTOMER LIST
    return customerList;
}
/**
 *UPDATING SINGLE CUSTOMER
 **/
public int updateCustomer(Customer customer, long id)
{
    if (customer == null)
    {
        return 0;
    }
    SQLiteDatabase dh = this.getWritableDatabase();

    ContentValues values = new ContentValues();
    values.put(KEY_FNAME, customer.getFName());
    values.put(KEY_LNAME, customer.getLName());
    values.put(KEY_CAR_MAKE, customer.get_CarMake());
    values.put(KEY_CAR_MODEL, customer.get_CarModel());
    values.put(KEY_CAR_COST, customer.get_CarCost());

    // UPDATING ROW
    return dh.update(TABLE_CUSTOMERS, values, KEY_ID + " = ?",
            new String[] { String.valueOf(id) });
}
/**
 *DELETING SINGLE CUSTOMER
 **/
public boolean deleteCustomer(long Id)
{
    boolean rv = false;
    SQLiteDatabase dh = this.getWritableDatabase();
    rv = (dh.delete(TABLE_CUSTOMERS, KEY_ID + " = ?",
            new String[] { String.valueOf(Id) }) > 0);
    dh.close();
    return rv;
}
}

数据适配器.java

public class dataAdapter extends ArrayAdapter<Customer>
{


public dataAdapter(Context context, ArrayList<Customer> customers)
{
    super(context, R.layout.list_customers, customers);
    Context context1 = context;
    ArrayList<Customer> mcustomer = customers;
}

public  class  Holder
{
    TextView idV;
    TextView nameFV;
    TextView nameLV;
    TextView carmakeV;
    TextView carmodelV;
    TextView carcostV;
}

@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent)
{
    // GET DATA ITEM FOR THIS POSITION

    Customer data = getItem(position);
    // CHECK IF EXISTING VIEW IS BEING REUSED, OTHERWISE INFLATE VIEW

    // VIEW LOOKUP CACHE STORED IN TAG
    Holder viewHolder;

    if (convertView == null)
    {
        viewHolder = new Holder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.list_customers, parent, false);

        viewHolder.idV = (TextView) convertView.findViewById(R.id.textView3_CustomerID);
        viewHolder.nameFV = (TextView) convertView.findViewById(R.id.textView3_FName);
        viewHolder.nameLV = (TextView) convertView.findViewById(R.id.textView3_LName);
        viewHolder.carmakeV = (TextView) convertView.findViewById(R.id.textView3_CarMake);
        viewHolder.carmodelV = (TextView) convertView.findViewById(R.id.textView3_CarModel);
        viewHolder.carcostV = (TextView) convertView.findViewById(R.id.textView3_CarCost);

        convertView.setTag(viewHolder);
    } else
    {
        viewHolder = (Holder) convertView.getTag();
    }

    viewHolder.nameFV.setText("First Name: " + data.getFName());
    viewHolder.nameLV.setText("Last Name: " + data.getLName());
    viewHolder.carmakeV.setText("Car Make: " + data.get_CarMake());
    viewHolder.carmodelV.setText("Car Model: " + data.get_CarModel());
    viewHolder.carcostV.setText("Car Cost: " + data.get_CarCost());

    // RETURN COMPLETED VIEW TO RENDER ON SCREEN
    return convertView;
}
}

我包括 MainActivity 以防我错过了那里的东西。这是 MainActivity.java

public class MainActivity extends AppCompatActivity
{
//public ListView lv;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    // even tried ListView here (R.id.listView....)
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View view)
        {
            Snackbar.make(view, "Please, click ADD button to begin! ", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

}

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    if (id == R.id.action_about)
    {
        // possibly go to another page
        Toast.makeText(MainActivity.this,
                "SQLite Database App", Toast.LENGTH_LONG).show();
        return true;
    }

    return super.onOptionsItemSelected(item);
}

public void buttonClicked(View view)
{
    // START NEW ACTIVITY WHEN ADD BUTTON CLICKED
    Intent intent = new Intent(this, CustomerRcrdActivity.class);
    startActivity(intent);


}
}

这是 Logcat 日志:

05-30 09:02:03.253 30145-30145/edu.phoenix.mbl402.week4apppp1943_rev1 E/AndroidRuntime: FATAL EXCEPTION: main
Process: edu.phoenix.mbl402.week4apppp1943_rev1, PID: 30145
java.lang.RuntimeException: Unable to start activity ComponentInfo{edu.phoenix.mbl402.week4apppp1943_rev1/edu.phoenix.mbl402.week4apppp1943_rev1.CustomerRcrdActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6541)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
    at edu.phoenix.mbl402.week4apppp1943_rev1.CustomerRcrdActivity.ShowRecords(CustomerRcrdActivity.java:276)
    at edu.phoenix.mbl402.week4apppp1943_rev1.CustomerRcrdActivity.onCreate(CustomerRcrdActivity.java:79)
    at android.app.Activity.performCreate(Activity.java:6975)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
    at android.app.ActivityThread.-wrap11(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) 
    at android.os.Handler.dispatchMessage(Handler.java:105) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:6541) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 

另外,我已经包含了建议的修改,再次感谢您!

标签: javaandroidoopandroid-sqlite

解决方案


一些改进/考虑的例子(也许)

下面的代码可能会给您一些想法/技术,并且基于答案(我将包含所有可以帮助您解决应用程序在启动时崩溃的代码)。

第一个改进是在 Activity 启动时加载 ListView。这很简单,只需调用ShowRecords方法即可。这消除了对“查看”按钮的需要(见稍后,因为它已被劫持)。

然而,ShowRecords方法已经发生了巨大的变化。合并适配器和源客户列表的单个实例。

一些逻辑/智能(原文如此)已添加到按钮中。那些不适用的会变灰。- 最初你不能删除或更新任何东西,你只能添加(添加不添加任何数据被省略)。- 如果您单击列表中的某个项目,则该数据将加载到 EditTexts 中,并且“删除”按钮是唯一可以单击的按钮。- 如果您更改 EditText 中的值,则只能单击更新按钮。

所有操作都有效并更新列表(根据上述逻辑可用时)。因此可以添加、更新和删除记录。

View 按钮已被劫持为现在的 CLEAR 按钮。这始终可用,并将清除 EditTexts 并将“添加”按钮设置为可用(单击列表项仍会加载该记录的数据)。

为了方便上述,已经定义了一些新的类变量,还有一些已经从方法变量转移到类变量,例如适配器和客户列表(您已经声明了da,所以使用了它)。

绝大多数更改仅针对 CustomerRcrdActivity,尽管对 DatabaseHelper 进行了一些小的更改(对于 id 来说很长,这是正确的做法,因为 id 可以超过int的最大值)。

无论如何,这是代码:-

CustomerRcrdActivity :-

public class CustomerRcrdActivity extends AppCompatActivity {

    private EditText FName, LName, CarMake, CarModel, CarCost;
    private String F_Name;
    private String L_Name;
    private String Car_Make;
    private String Car_Model;
    private double d_Car_Cost;
    private DatabaseHandler dh;
    private dataAdapter da;
    private Customer dataModel;
    private ListView lv;
    private long mId;

    //<<<<<<<<<< new class variables
    private String original_FName, original_LName, original_CarMake, original_CarModel, original_CarCost;
    private boolean mLoaded = false;
    private Button mViewButton, mUpdateButton, mAddButton, mDeleteButton;
    private ArrayList<Customer> mCustomers = new ArrayList<>();
    private List<EditText> mAlleditTexts = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_customer_rcrd);

        // GET Intent THAT STARTED ACTIVITY
        Intent intent = getIntent();

        // INSTANTIATE DATABASE HANDLER
        dh = new DatabaseHandler(this);

        FName = (EditText) findViewById(R.id.editText2_FName);
        LName = (EditText) findViewById(R.id.editText2_LName);
        CarMake = (EditText) findViewById(R.id.editText2_CarMake);
        CarModel = (EditText) findViewById(R.id.editText2_CarModel);
        CarCost = (EditText) findViewById(R.id.editText2_CarCost);

        //<<<<<<<<<<< ADDED
        mAlleditTexts.add(FName);
        mAlleditTexts.add(LName);
        mAlleditTexts.add(CarMake);
        mAlleditTexts.add(CarModel);
        mAlleditTexts.add(CarCost);
        lv = (ListView) findViewById(R.id.lv);
        //<<<<<<<<<< END OF ADDED

        mViewButton = (Button) findViewById(R.id.button_CR_view);
        mAddButton = (Button) findViewById(R.id.button_CR_add);
        mUpdateButton = (Button) findViewById(R.id.button_CR_update);
        mDeleteButton = (Button) findViewById(R.id.button_CR_delete);

        mViewButton.setVisibility(View.GONE); // never Show and free screen space
        mViewButton.setText("CLEAR"); // Hijack View Button for clear data
        mViewButton.setVisibility(View.VISIBLE); // Show the View (now CLEAR)
        mAddButton.setEnabled(false); // Can't click Add as nothing to add
        mUpdateButton.setEnabled(false); // Can't click Update nothing to update
        mDeleteButton.setEnabled(false); // Can't click Delete as nothing to delete
        setOriginalValues();
        ShowRecords(); //<<<< Always show the list no need for View button
        setEditTextFocusChangedListener(mAlleditTexts);
    }

    //<<<<<<<<<< NEW METHOD
    private void setEditTextFocusChangedListener(List<EditText> edit_texts) {
        for (EditText e: edit_texts) {

            e.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View view, boolean b) {
                    if (areOriginalValuesChanged()) {
                        if (mLoaded) {
                            mUpdateButton.setEnabled(true);
                            mDeleteButton.setEnabled(false);
                            mAddButton.setEnabled(false);
                        } else {

                        }
                    } else {
                        if (!mLoaded) {
                            mAddButton.setEnabled(true);
                        } else {
                            mAddButton.setEnabled(false);
                        }
                    }
                }
            });
        }
    }

    //<<<<<<<<<< NEW METHOD
    private void setOriginalValues() {
        original_FName = FName.getText().toString();
        original_LName = LName.getText().toString();
        original_CarMake = CarMake.getText().toString();
        original_CarModel = CarModel.getText().toString();
        original_CarCost = CarCost.getText().toString();
    }

    //<<<<<<<<<< NEW METHOD
    private boolean areOriginalValuesChanged() {
        if (original_FName.equals(FName.getText().toString())
                && original_LName.equals(LName.getText().toString())
                && original_CarMake.equals(CarMake.getText().toString())
                && original_CarModel.equals(CarModel.getText().toString())
                && original_CarCost.equals(CarCost.getText().toString())
                ) {
            return false;
        }
        return true;
    }

    //<<<<<<<<<< NEW METHOD
    private void clearEditTexts(List<EditText> editTexts) {
        for (EditText e: editTexts) {
            e.setText("");
        }
        setOriginalValues();
        mLoaded = false;
    }

    public void buttonClicked(View view)
    {
        int id = view.getId();

        switch (id)
        {
            case R.id.button_CR_update:
                // CALL updateCustomer() TO UPDATE CUSTOMER RECORDS
                updateCustomer();
                mLoaded = false;
                break;

            case R.id.button_CR_add:
                // CALL addCustomer() TO ADD TO DATABASE
                addCustomer();
                clearEditTexts(mAlleditTexts);
                mLoaded = false;

                // START NEW ACTIVITY WHEN ADD BUTTON CLICKED
                //Intent intent = new Intent(this, DatabaseHandler.class);
                //startActivity(intent);

                break;

            case R.id.button_CR_delete:
                // CALL deleteCustomer() TO DELETE CUSTOMER RECORD
                deleteCustomer();
                break;

            case R.id.button_CR_view:
                // CALL viewCustomer() TO VIEW CUSTOMER RECORD
                // START NEW ACTIVITY WHEN ADD BUTTON CLICKED
                //Intent intent2 = new Intent(this, CustomerDBActivity.class);
                //startActivity(intent2);

                // CALL showRecords() TO VIEW CUSTOMER RECORD VIA ListView
                clearEditTexts(mAlleditTexts);
                mLoaded = false;
                mAddButton.setEnabled(true);
                mUpdateButton.setEnabled(false);
                mDeleteButton.setEnabled(false);
                break;
        }
        ShowRecords(); // Update the List irrespective of button clicked
    }


    private void updateCustomer()
    {
        getValues();
         if (dh.updateCustomer(dataModel, mId)>0) {
             Toast.makeText(getApplicationContext(), "Customer Updated Successfully", Toast.LENGTH_LONG).show();
         } else {
             Toast.makeText(getApplicationContext(), "Customer Not Updated", Toast.LENGTH_LONG).show();
         }
    }
    // INSERT DATA INTO DATABASE
    private void addCustomer()
    {
        boolean ok_to_add = true;
        getValues();
        if (F_Name == null || F_Name.length() < 1) ok_to_add = false;
        if (L_Name == null || L_Name.length() < 1) ok_to_add = false;
        if (Car_Make == null || Car_Make.length() < 1) ok_to_add = false;
        if (Car_Model == null || Car_Model.length() < 1) ok_to_add = false;
        if (ok_to_add) {
            dh.addCustomers(new Customer(F_Name, L_Name, Car_Make, Car_Model, d_Car_Cost));
            Toast.makeText(getApplicationContext(), "Customer Added Successfully", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(getApplicationContext(), "Unable To Add - Some Data hasn't been given", Toast.LENGTH_LONG).show();
        }
    }

    private void deleteCustomer()
    {
        getValues();
         if (dh.deleteCustomer(mId)) {
             Toast.makeText(getApplicationContext(), "Customer Deleted Successfully", Toast.LENGTH_LONG).show();
         } else {
             Toast.makeText(getApplicationContext(), "Customer Not Deleted", Toast.LENGTH_LONG).show();
         }
    }

    // FUNCTION TO GET VALUES FROM EditText
    private void getValues()
    {

        F_Name = FName.getText().toString();
        L_Name = LName.getText().toString();
        Car_Make = CarMake.getText().toString();
        Car_Model = CarModel.getText().toString();
        String car_Cost = CarCost.getText().toString();
        if (car_Cost.length() < 1) {
            car_Cost = "0.00";
        }
        d_Car_Cost = Double.parseDouble(car_Cost);

    }
    // RETRIEVE DATA FROM DATABASE & SET TO LIST VIEW
    //<<<<<<<<<< CHANGED QUITE A BIT
    // Introduced single Customer List with class scope rather than create new list and adapter everytime
    //      i.e. mCustomers
    // Always clear mCustomers and rebuild from database
    // if da (the adapter) is null and therefore hasn't been instantiated, instantiate it just once
    // otherwsie always notify the adapter that the data (mCustomer) has changed
    // Added code to the Listener (added just the once now) to set the edit text's to the values
    // of the clicked item in the list (load the data)
    //  setting flag to say that the data has just been loaded.
    //  also setting the original values to the new data
    private void ShowRecords()
    {
        mCustomers.clear();
        mCustomers.addAll(dh.getAllCustomers());
        //final ArrayList<Customer> customers = new ArrayList<>(dh.getAllCustomers());
        //final Customer customers = new Customer(dh.getAllCustomers());
        if (da == null) {
            da = new dataAdapter(this, mCustomers);
            //final dataAdapter data = new dataAdapter(this, mCustomers); //<<<< Shouldn't create a new adapter everytime

            lv.setAdapter(da);

            lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    dataModel = mCustomers.get(position);
                    //<<<<<<<<<< Added
                    FName.setText(dataModel.getFName());
                    LName.setText(dataModel.getLName());
                    CarMake.setText(dataModel.get_CarMake());
                    CarModel.setText(dataModel.get_CarModel());
                    CarCost.setText(String.valueOf(dataModel.get_CarCost()));
                    mLoaded = true;
                    setOriginalValues();
                    mDeleteButton.setEnabled(true);
                    mUpdateButton.setEnabled(false);
                    mAddButton.setEnabled(false);
                    mId = dataModel.getID();
                    //<<<<<<<<<< End of Added
                    Toast.makeText(getApplicationContext(), String.valueOf(dataModel.getID()), Toast.LENGTH_SHORT).show();
                }
            });
        } else {
            da.notifyDataSetChanged();
        }
    }
}

数据库处理程序

public class DatabaseHandler extends SQLiteOpenHelper
{
    // DATABASE VERSION
    private static final int DATABASE_VERSION = 1;
    // DATABASE NAME
    private static final String DATABASE_NAME = "Car Dealer";
    // PREFERRED THE NAME "STAR DEALERSHIP CUSTOMER DATABASE"
// CUSTOMER TABLE NAME
    public static final String TABLE_CUSTOMERS = "Customers";


    // CUSTOMER TABLE COLUMN NAMES
    private static final String KEY_ID = "ID";
    private static final String KEY_FNAME = "First";
    private static final String KEY_LNAME = "Last";
    private static final String KEY_CAR_MAKE = "Make";
    private static final String KEY_CAR_MODEL = "Model";
    private static final String KEY_CAR_COST = "Cost";

    DatabaseHandler(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    // CREATE TABLES
    @Override
    public void onCreate(SQLiteDatabase dh)
    {
        String CREATE_TABLE_CUSTOMERS = "CREATE TABLE " + TABLE_CUSTOMERS + "("
                + KEY_ID +" INTEGER PRIMARY KEY,"
                + KEY_FNAME +" TEXT,"
                + KEY_LNAME +" TEXT,"
                + KEY_CAR_MAKE  +" TEXT,"
                + KEY_CAR_MODEL +" TEXT,"
                + KEY_CAR_COST +" NUMERIC" + ")";
        dh.execSQL(CREATE_TABLE_CUSTOMERS);
    }
    // UPGRADING DATABASE
    @Override
    public void onUpgrade(SQLiteDatabase dh, int oldVersion, int newVersion)
    {
        // DROP OLDER TABLE IF EXISTED
        dh.execSQL("DROP TABLE IF EXISTS " + TABLE_CUSTOMERS);

        // CREATE TABLES AGAIN
        onCreate(dh);
    }
    /**
     * All CRUD (CREATE, READ, UPDATE, DELETE) OPERATIONS
     */
// INSERT VALUES TO TABLE CUSTOMERS

    public void addCustomers(Customer customer)
    {
        SQLiteDatabase dh = this.getReadableDatabase();
        ContentValues values = new ContentValues();

        values.put(KEY_FNAME, customer.getFName());
        values.put(KEY_LNAME, customer.getLName() );
        values.put(KEY_CAR_MAKE, customer.get_CarMake());
        values.put(KEY_CAR_MODEL, customer.get_CarModel());
        values.put(KEY_CAR_COST, customer.get_CarCost());

        dh.insert(TABLE_CUSTOMERS, null, values);
        dh.close();
    }
    /**
     *GETTING ALL CUSTOMERS
     **/
    public List<Customer> getAllCustomers()
    {
        List<Customer> customerList = new ArrayList<Customer>();
        // SELECT ALL QUERY
        String selectQuery = "SELECT  * FROM " + TABLE_CUSTOMERS;

        SQLiteDatabase dh = this.getWritableDatabase();
        Cursor cursor = dh.rawQuery(selectQuery, null);

        // LOOP THROUGH ALL ROWS & ADD TO LIST
        if (cursor.moveToFirst())
        {
            do {
                Customer customer = new Customer();
                customer.setID(Integer.parseInt(cursor.getString(0)));
                customer.setFName(cursor.getString(1));
                customer.setLName(cursor.getString(2));
                customer.set_CarMake(cursor.getString(3));
                customer.set_CarModel(cursor.getString(4));
                customer.set_CarCost(cursor.getDouble(5));

                // ADDING CUSTOMER TO LIST
                customerList.add(customer);
            } while (cursor.moveToNext());
        }
        // CLOSE OUT RAW QUERY CALL
        cursor.close();
        // RETURN CUSTOMER LIST
        return customerList;
    }
    /**
     *UPDATING SINGLE CUSTOMER
     **/
    public int updateCustomer(Customer customer, long id)
    {
        if (customer == null) {
            return 0;
        }
        SQLiteDatabase dh = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_FNAME, customer.getFName());
        values.put(KEY_LNAME, customer.getLName());
        values.put(KEY_CAR_MAKE, customer.get_CarMake());
        values.put(KEY_CAR_MODEL, customer.get_CarModel());
        values.put(KEY_CAR_COST, customer.get_CarCost());

        // UPDATING ROW
        return dh.update(TABLE_CUSTOMERS, values, KEY_ID + " = ?",
                new String[] { String.valueOf(id) });
    }
    /**
     *DELETING SINGLE CUSTOMER
     **/
    public boolean deleteCustomer(long Id)
    {
        boolean rv = false;
        SQLiteDatabase dh = this.getWritableDatabase();
        rv = (dh.delete(TABLE_CUSTOMERS, KEY_ID + " = ?",
                new String[] { String.valueOf(Id) }) > 0);
        dh.close();
        return rv;
    }
}

顾客

  • 请注意,这可能与您的完全不同,尽管可能非常接近。需要注意的主要事情是CustomerId是一个long,否则就CustomerRcrdActivity而言,它会模仿你的。

:-

public class Customer {

    private long CustomerId;
    private String FName;
    private String LName;
    private String CarMake;
    private String CarModel;
    private Double CarCost;

    public Customer(String first_name, String last_name, String make_of_car, String model, Double cost) {
        this.FName = first_name;
        this.LName = last_name;
        this.CarMake = make_of_car;
        this.CarModel = model;
        this.CarCost = cost;
    }

    public Customer() {
    }

    public void setFName(String FName) {
        this.FName = FName;
    }

    public String getFName() {
        return FName;
    }

    public void setLName(String LName) {
        this.LName = LName;
    }

    public String getLName() {
        return LName;
    }

    public void set_CarMake(String carMake) {
        CarMake = carMake;
    }

    public String get_CarMake() {
        return CarMake;
    }

    public void set_CarCost(Double carCost) {
        CarCost = carCost;
    }

    public Double get_CarCost() {
        return CarCost;
    }

    public void set_CarModel(String carModel) {
        CarModel = carModel;
    }

    public String get_CarModel() {
        return CarModel;
    }

    public void setCustomerId(long customerId) {
        CustomerId = customerId;
    }

    public long getCustomerId() {
        return CustomerId;
    }

    public long getID() {
        return this.getCustomerId();
    }

    public void setID(long id) {
        this.setCustomerId(id);
    }
}

布局 布局应该都模仿你的,所以不需要包括它们(你的可能会好得多,因为用于此的布局是最小的)。

主要活动

除了启动之外,这没有任何作用CustomerRcrdActivity,因此非常基本:-

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent i = new Intent(this,CustomerRcrdActivity.class);
        startActivity(i);
    }
}
  • 请注意,使用 back from theCustomerRcrdActivity将带您进入一个空屏幕,您无能为力。

布局是创建项目时生成的基本单个 TextView :-

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

AndroidManiFest.xml

同样,这是非常基本的,它刚刚被修改为有一个活动部分CustomerRcrdActivity:-

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".CustomerRcrdActivity">
    </activity>
</application>

请注意,如果您使用上述内容,包名称(第 3 行)可能不正确,因此需要更改。


推荐阅读