简体   繁体   中英

Update ListView in Fragment when SQLite database is updated in another Fragment

I've got two Fragments

AddActivityFragment - This Fragment is responsible for adding data into my SQLite database.

and

ActivityListFragment - This Fragment is responsible for displaying the data in a ListView

The problem is that whenever data is added to the SQLite table, the table is not updated until the application is restarted. Because of this, if I try to add some data into the table, it is not updated in the ListView until I restart the application.

I've come across adapter.notifyDataSetChanged() on multiple threads regarding similar problems but I can not for the life of me figure out how I'm supposed to implement this into my own code.

AddActivityFragment.java :

public class AddActivityFragment extends Fragment implements View.OnClickListener {

    private static final String TAG = "AddActivityFragment";

    private TextInputLayout activityNameTextField, activityDateTextField;
    private TextInputEditText activityNameInput, activityDateInput;
    public DatabaseHelper mDatabaseHelper;
    private LocationRequest mLocationRequest;
    private FusedLocationProviderClient mFusedLocationProviderClient;
    private Location mLastLocation;
    private ActivityListFragment mActivityListFragment;
    private DatePicker mDatePicker;
    Context mContext;

    private double activityLocationLat;
    private double activityLocationLong;

    public AddActivityFragment() {
        // Required empty public constructor
    }
    @Override
    public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container,
                                          Bundle savedInstanceState) {
        View activityViewFragment = inflater.inflate(R.layout.fragment_add_activity, container, false);
        // Get context from fragment.
        this.mContext = activityViewFragment.getContext();

        mDatabaseHelper = new DatabaseHelper(mContext);

        // Find the layout components.
        activityNameTextField = activityViewFragment.findViewById(R.id.activityNameTextField);
        activityNameInput = activityViewFragment.findViewById(R.id.activityNameInput);
        mDatePicker = activityViewFragment.findViewById(R.id.datePicker);


        Button addActivityButton = activityViewFragment.findViewById(R.id.addActivityButton);

        // Set listener to addActivityButton in this view.
        addActivityButton.setOnClickListener(this);
        // Set hints for text fields.
        activityNameTextField.setHint("Activity Name");


        return activityViewFragment;
    }

    @Override
    public void onClick(View v) {
        switch(v.getId()) {
            case R.id.addActivityButton:
                StringBuilder sb = new StringBuilder();
                int day = mDatePicker.getDayOfMonth();
                int month = mDatePicker.getMonth() + 1;
                int year = mDatePicker.getYear();
                sb.append(day);
                sb.append("-");
                sb.append(month);
                sb.append("-");
                sb.append(year);

                String activityName = activityNameInput.getText().toString();
                String activityDate = sb.toString();


                activityNameInput.setText("");

                //Add the activity data to the SQL database

                mDatabaseHelper.addData(activityName,activityDate,activityLocationLat,activityLocationLong);


                break;
            default:
                break;
        }

    @Override
    public void onResume(){
        super.onResume();
        Log.d(TAG,"Log when activity is swiped to.");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG, "List paused.");
    }
}

ActivityListFragment.java :

public class ActivityListFragment extends Fragment {

    //Class tag
    private static final String TAG = "ActivityListFragment";
    private static final String ACTIVITY_LIST_FRAGMENT_TAG = "ACTIVITY_LIST_FRAGMENT";

    DatabaseHelper mDatabaseHelper;
    Context mContext;
    private ListView mListView;
    public ArrayAdapter adapter;
    private ArrayList<ArrayList> listData;

    public ActivityListFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View listViewFragment = inflater.inflate(R.layout.fragment_activity_list, container, false);
        this.mContext = listViewFragment.getContext();
        mListView = listViewFragment.findViewById(R.id.activity_list_view);

        mDatabaseHelper = new DatabaseHelper(mContext);
        listData = new ArrayList<>();

        for(int i = 0; i < mDatabaseHelper.getRowCount(); i++) {
            listData.add(mDatabaseHelper.getDataFromIndex(i));
        }

        adapter = new ArrayAdapter<>(mContext, android.R.layout.simple_list_item_1, listData);
        mListView.setAdapter(adapter);
        handleOnItemClick();
        return listViewFragment;
    }
    @Override
    public void onResume(){
        super.onResume();
        Log.d(TAG,"Log when activity is swiped to.");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG, "List paused.");
    }

ViewPagerAdapter.java :


public class ViewPagerAdapter extends FragmentStateAdapter {

    public ViewPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {

        switch (position) {
            case 0:
                return new MapViewFragment();
            case 1:
                return new AddActivityFragment();
            case 2:
                return new ActivityListFragment();
        }
        return null;
    }

    @Override
    public int getItemCount() {
        return 3;
    }
}

DataBaseHelper.java :

public class DatabaseHelper extends SQLiteOpenHelper {

    private static final String TAG = "DatabaseHelper";

    //Table name, column names.
    private static final String TABLE_NAME = "activity_table";
    private static final String COL_ID = "ID";
    private static final String COL_NAME = "name";
    private static final String COL_DATE = "date";
    private static final String COL_LOCATION_LAT = "location_lat";
    private static final String COL_LOCATION = "location_long";

    private Cursor mCursor;
    ArrayList latLongList;
    public DatabaseHelper(Context context) {
        super(context, TABLE_NAME, null, 1);
    }

    /**
     * Method: onCreate
     * @param db - The database that we are creating the table in.
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        String CREATE_ACTIVITES_TABLE = "CREATE TABLE " + TABLE_NAME + "("
                + COL_ID + " INTEGER PRIMARY KEY," + COL_NAME + " VARCHAR,"
                + COL_DATE + " VARCHAR," + COL_LOCATION_LAT + " DOUBLE," + COL_LOCATION + " DOUBLE" + ");";
        db.execSQL(CREATE_ACTIVITES_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }

    /**
     * Method: addData
     * @param name - The "name"-value which is added to the table column COL_NAME.
     * @param date - The "date"-value which is added to the table column COL_DATE.
     * @param locationLat - The "locationLat"-value which is added to the table column COL_LOCATION_LAT.
     * @param locationLong - The "locationLong"-value which is added to the table column COL_LOCATION_LONG.
     * @return true or false, depending if the addition to the table was successful or not.
     */
    public boolean addData(String name, String date, Double locationLat, Double locationLong) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put(COL_NAME, name);
        contentValues.put(COL_DATE, date);
        contentValues.put(COL_LOCATION_LAT, locationLat);
        contentValues.put(COL_LOCATION, locationLong);

        Log.d(TAG, "addData: Adding " + name + " to " + TABLE_NAME);
        Log.d(TAG, "addData: Adding " + date + " to " + TABLE_NAME);
        Log.d(TAG, "addData: Adding " + locationLat + " to " + TABLE_NAME);
        Log.d(TAG, "addData: Adding " + locationLong + " to " + TABLE_NAME);

        long result = db.insert(TABLE_NAME, null, contentValues);

        if(result == -1) {
            Log.d(TAG, "Something went wrong when adding data to database.");
            return false;
        } else {
            Log.d(TAG, "Data correctly added to database");
            return true;
        }
    }

    /**
     * Method: getData
     * @return mCursor - Returns entire table from database.
     */
    public Cursor getData() {
        SQLiteDatabase db = this.getWritableDatabase();
        String query = "SELECT * FROM " + TABLE_NAME;
        mCursor = db.rawQuery(query, null);
        return mCursor;
    }

    /**
     * Method: getDataFromIndex
     * @param index - Row index in activity_table table.
     * @return list - ArrayList of data at row index.
     */
    public ArrayList getDataFromIndex (int index) {
        ArrayList list = new ArrayList();

        if(mCursor == null) {
            getData();
        }
        mCursor.moveToPosition(index);
        list.add(mCursor.getString(1));
        list.add(mCursor.getString(2));
        list.add(mCursor.getDouble(3));
        list.add(mCursor.getDouble(4));
        return list;
    }

    /**
     * Method: getRowCount
     * @return mCursor.getCount - Total amount of rows in table.
     */
    public int getRowCount() {
        if(mCursor == null) {
            getData();
        }
        return mCursor.getCount();
    }

    /** TODO: This might be useless as we will need to fetch the names associated to the activity anyway, to be decided.
     * Method: latLongArrayListFromIndex
     * @param index - Row index in activity_table table.
     * @return latLongList - ArrayList of data at row index.
     */
    public ArrayList latLongArrayListFromIndex(int index) {
        latLongList = new ArrayList();
        if(mCursor == null) {
            getData();
        }
        mCursor.moveToPosition(index);
        latLongList.add(mCursor.getDouble(mCursor.getColumnIndex("location_lat")));
        latLongList.add(mCursor.getDouble(mCursor.getColumnIndex("location_long")));

        return latLongList;
    }

    /**
     * Method getItemId
     */
    public Cursor getItemId(String name) {
        SQLiteDatabase db = this.getWritableDatabase();
        String query = "SELECT " + COL_ID + " FROM " + TABLE_NAME + " WHERE " + COL_NAME + " = '" + name + "'";
        Cursor data = db.rawQuery(query, null);
        return data;
    }

    /**
     * Method: updateName
     * @param newName
     * @param id
     * @param oldName
     */
    public void updateName(String newName, int id, String oldName) {
        SQLiteDatabase db = this.getWritableDatabase();
        String query = "UPDATE " + TABLE_NAME + " SET " + COL_NAME + " = '" + newName + "' WHERE " + COL_ID + " = '" + id + "'" + " AND " + COL_NAME + " = '" + oldName + "'";
        Log.d(TAG, "updateName: query: " + query);
        Log.d(TAG, "updateName: Setting new name of activity to: " + newName);
        db.execSQL(query);
    }

    public void deleteActivity(int id, String name) {
        SQLiteDatabase db = this.getWritableDatabase();
        String query = "DELETE FROM " + TABLE_NAME + " WHERE " + COL_ID + " = '" + id + "'" + " AND " + COL_NAME + " = '" + name + "'";
        Log.d(TAG, "deleteActivity: query: " + query);
        Log.d(TAG, "deleteActivity: Deleting " + name + " from table");
        db.execSQL(query);
    }
}

You can achieve the desired behaviour just by observing the SQLite data using content observer. I have a Github project here , that might help you to understand how this works.

The first step would be defining a content URI that is unique. The URI might look something as follows.

public static final Uri DB_TABLE_USER_URI = Uri
    .parse("sqlite://" + com.package.your.app + "/" + "user_table");

Then use the LoaderManager.LoaderCallbacks<Cursor> in your ActivityListFragment to load the users in that fragment using CursorLoader callback functions (ie onCreateLoader , onLoadFinished , etc.). Also register for content observer in your onCreateLoader .

this.registerContentObserver(cursor, DBConstants.DB_TABLE_USER_URI);

And after you add/update a user in your DataBaseHelper class, you might also want to notify the observer that the data is changed in your database, so that it refreshes the data automatically in the RecyclerView .

context.getContentResolver().notifyChange(DBConstants.DB_TABLE_USER_URI, null);

I would recommend forking the Github project and run the code to see how it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM