1

Cant Refresh ListView and TextView

The app: I have an app that creates multiple machines with:

  • _id, name and location

each of these machines I have to let the user input the income

  • _id, note, date, money, machines_id

The Problem: Can't refresh ListView AND TextView simultaneously after OnLongClickListener.

What I have tried: Cursor Adapter, swapCursor.

My Question: What is the best approach to accomplish the update of both things simultaneously in the same activity?

If you need any other class or have any feedback, please dont hesitate to indulge me!

DBHelper

    public class DBHelpter extends SQLiteOpenHelper {

    private static final String DB_NAME = "machines.db";
    private static final int DB_VERSION = 1;

    public static final String TABLE_MACHINES = "machines";
    public static final String MACHINES_COLUMN_NAME = "name";
    public static final String MACHINES_COLUMN_LOCATION = "location";
    public static final String MACHINES_ID = "id";

    public static final String TABLE_INCOME = "income";
    public static final String INCOME_COLUMN_MONEY = "money";
    public static final String INCOME_COLUMN_DATE = "date";
    public static final String INCOME_COLUMN_NOTE = "note";
    public static final String INCOME_ID = "id";
    public static final String INCOME_COLUMN_MACHINES_ID = "machines_id";

    private Context mContext;

public DBHelpter(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

@Override
public void onCreate(SQLiteDatabase db) {
    String query1 = String.format("CREATE TABLE " + TABLE_MACHINES + "("
        + MACHINES_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
        + MACHINES_COLUMN_NAME + " TEXT NOT NULL, "
        + MACHINES_COLUMN_LOCATION + " TEXT NOT NULL)",
            TABLE_MACHINES, MACHINES_COLUMN_NAME, MACHINES_COLUMN_LOCATION, MACHINES_ID);

    String query2 = String.format("CREATE TABLE " + TABLE_INCOME + "("
        + INCOME_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
        + INCOME_COLUMN_MONEY + " REAL NOT NULL, "
        + INCOME_COLUMN_DATE + " DATE NOT NULL, "
        + INCOME_COLUMN_NOTE + " TEXT NOT NULL, "
        + INCOME_COLUMN_MACHINES_ID + " INTEGER NOT NULL)",
            TABLE_INCOME, INCOME_ID, INCOME_COLUMN_MONEY, INCOME_COLUMN_DATE, INCOME_COLUMN_NOTE, INCOME_COLUMN_MACHINES_ID);
    db.execSQL(query1);
    db.execSQL(query2);

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    String query1 = String.format("DROP TABLE IF EXISTS " + TABLE_MACHINES);
    String query2 = String.format("DROP TABLE IF EXISTS " + TABLE_INCOME);
    db.execSQL(query1);
    db.execSQL(query2);
    onCreate(db);

}
public void insertNewMachine(String name, String location){
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(MACHINES_COLUMN_NAME, name);
        values.put(MACHINES_COLUMN_LOCATION, location);
        db.insertWithOnConflict(TABLE_MACHINES, null, values, SQLiteDatabase.CONFLICT_REPLACE);
        db.close();
    }
public void insertNewIncome(Double money, String date, String note, long machines_id){
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(INCOME_COLUMN_MONEY, money);
        values.put(INCOME_COLUMN_DATE, date);
        values.put(INCOME_COLUMN_NOTE, note);
        values.put(INCOME_COLUMN_MACHINES_ID, machines_id);
        db.insertWithOnConflict(TABLE_INCOME, null, values, SQLiteDatabase.CONFLICT_REPLACE);
        db.close();
    }
public void getIncomeOfMachine(long machinesId){
        SQLiteDatabase db = getReadableDatabase();
    Cursor cursor = db.rawQuery("SELECT machines_id, SUM(money) AS total FROM income WHERE machines_id = "+machinesId+"", null);
    cursor.moveToFirst();
    double total_amount = cursor.getDouble(cursor.getColumnIndex("total"));
    return total_amount;
    }
public ArrayList<MachinesClass> getAllMachines(){
        ArrayList<MachinesClass> machinesList = new ArrayList<>();
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery("SELECT * FROM "+ TABLE_MACHINES, null);
        while (cursor.moveToNext()){
            final long id = cursor.getLong(cursor.getColumnIndex(MACHINES_ID));
            final String name = cursor.getString(cursor.getColumnIndex(MACHINES_COLUMN_NAME));
            final String location = cursor.getString(cursor.getColumnIndex(MACHINES_COLUMN_LOCATION));
            machinesList.add(new MachinesClass(id, name, location));
        }
        cursor.close();
        db.close();
        return machinesList;
    }

public void deleteIncome(long id){
    SQLiteDatabase db = this.getWritableDatabase();
    db.delete(TABLE_INCOME, INCOME_ID+ "=?", new String[]{id + ""});
    db.close();
}

public Cursor getInfoOfMachine(long machinesId){
    SQLiteDatabase db = getReadableDatabase();
    Cursor cursor = db.rawQuery("SELECT _id, note, date, money FROM income WHERE machines_id = "+machinesId+" ORDER BY date ASC",null);
    return cursor;
}

CursorAdapter

public class ListAdapter extends CursorAdapter {


public ListAdapter(Context context, Cursor c) {
    super(context, c);
}

public View newView(Context context, Cursor cursor, ViewGroup parent) {
    return LayoutInflater.from(context).inflate(R.layout.notes_list, parent, false);
}

@Override
public void bindView(View view, final Context context, final Cursor cursor) {

    final DBHelpter mDBHelper = new DBHelpter(context);

    TextView mNote = (TextView) view.findViewById(R.id.tvNote);
    TextView mNotesDate = (TextView) view.findViewById(R.id.tvFecha);
    TextView mMoney = (TextView) view.findViewById(R.id.tvMoney);
    RelativeLayout mRelativeLayout = (RelativeLayout) view.findViewById(R.id.rlNotesList);

    final Long id = cursor.getLong(cursor.getColumnIndex("_id"));
    String note = cursor.getString(cursor.getColumnIndex("note"));
    String date = cursor.getString(cursor.getColumnIndex("date"));
    double money = cursor.getDouble(cursor.getColumnIndex("money"));

    mNote.setText(note);
    mNotesDate.setText(date);
    DecimalFormat formatter = new DecimalFormat("$#,##0.000");
    String formatted = formatter.format(money);
    mMoney.setText(formatted);

    mNote.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            AlertDialog alertDialog = new AlertDialog.Builder(v.getContext())
                    .setTitle("Confirmación")
                    .setMessage(Html.fromHtml("Segura de "+"<b>"+"BORRAR"+"</b>"+" la información?"))
                    .setNegativeButton("No", null)
                    .setPositiveButton("Si", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            mDBHelper.deleteIncome(id);
                            notifyDataSetChanged();
                        }
                    })
                    .create();
            alertDialog.show();
            return true;
        }
    });

}

}

MachineInfo

public class MachineInfo extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{

private TextView mLocation, mMoney;
private DBHelpter mDBHelpter;
private ListView mNotesList;
private FloatingActionButton mFAB;
private SQLiteDatabase db;
private Cursor mCursor;
private ListAdapter mAdapter;
private Context mContext;
private static final int LOADER_INTEGER = 1;

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

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    mDBHelpter = new DBHelpter(getApplicationContext());
    db = mDBHelpter.getWritableDatabase();

    mLocation = (TextView) findViewById(R.id.tvLocation);
    mMoney = (TextView) findViewById(R.id.tvMoney);
    mFAB = (FloatingActionButton) findViewById(R.id.fabAddIncome);
    mNotesList = (ListView) findViewById(R.id.lvNotes);

    SharedPreferences mSharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    final Long machines_id = mSharedPreferences.getLong("machines_id", 0);

    double total_amount = mDBHelpter.getIncomeOfMachine(machines_id);
    DecimalFormat formatter = new DecimalFormat("$#,##0.000");
    String formatted = formatter.format(total_amount);
    mMoney.setText(formatted);

    String location = mSharedPreferences.getString("location", null);
    mLocation.setText(location);

    mAdapter = new ListAdapter(this, mDBHelpter.getInfoOfMachine(machines_id));
    mAdapter.notifyDataSetChanged();
    mNotesList.setAdapter(mAdapter);

    getLoaderManager().initLoader(LOADER_INTEGER, null, this);

    mFAB.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent i = new Intent(getApplicationContext(), IncomeCreation.class);
            startActivity(i);
        }
    });
}


@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    SharedPreferences mSharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    final Long machines_id = mSharedPreferences.getLong("machines_id", 0);
    String[] projection = new String[]{"_id", "note", "date", "money"};
    String selection = "machines_id = "+machines_id;
    String sortOrder = "date ASC";
    return new CursorLoader(this, IncomeProvider.CONTENT_URI, projection, selection, null, sortOrder);
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    mAdapter.swapCursor(cursor);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    mAdapter.swapCursor(null);
}

}

IncomeProvider

public class IncomeProvider extends ContentProvider {

private static final int INCOME = 1;
private static final int INCOME_ID = 2;
private static final String PROVIDER = "tech.destinum.machines.incomeprovider";
static final Uri CONTENT_URI = Uri.parse("content://"+ PROVIDER + "/income");
public static final UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static{
    mUriMatcher.addURI(PROVIDER, "income", INCOME);
    mUriMatcher.addURI(PROVIDER, "income/#", INCOME_ID);
}
private DBHelpter mDBHelper;
private SQLiteDatabase db;


@Override
public boolean onCreate() {
    Context context = getContext();
    mDBHelper = new DBHelpter(context);
    SQLiteDatabase db = mDBHelper.getWritableDatabase();
    return (db == null)? false:true;
}

@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
    queryBuilder.setTables(DBHelpter.TABLE_INCOME);

    switch (mUriMatcher.match(uri)) {
        case INCOME:
            break;
        case INCOME_ID:
            queryBuilder.appendWhere(DBHelpter.INCOME_ID + "="
                    + uri.getLastPathSegment());
            break;
        default:
            throw new IllegalArgumentException("Unknown URI: " + uri);
    }

    SharedPreferences mSharedPreferences = getContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    final Long machines_id = mSharedPreferences.getLong("machines_id", 0);
    db = mDBHelper.getWritableDatabase();
    projection = new String[]{"_id", "note", "date", "money"};
    selection = "machines_id = "+machines_id;
    sortOrder = "date ASC";
    Cursor cursor = queryBuilder.query(db, projection, selection,
            selectionArgs, null, null, sortOrder);

    cursor.setNotificationUri(getContext().getContentResolver(), uri);
    return cursor;
}

@Nullable
@Override
public String getType(Uri uri) {
    return null;
}

@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
    int uriType = mUriMatcher.match(uri);
    SQLiteDatabase sqlDB = mDBHelper.getWritableDatabase();
    long id = 0;
    switch (uriType) {
        case INCOME:
            id = sqlDB.insert(DBHelpter.TABLE_INCOME, null, values);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI: " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return Uri.parse("income" + "/" + id);
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    int uriType = mUriMatcher.match(uri);
    SQLiteDatabase sqlDB = mDBHelper.getWritableDatabase();
    int rowsDeleted = 0;
    switch (uriType) {
        case INCOME:
            rowsDeleted = sqlDB.delete(DBHelpter.TABLE_INCOME, selection,
                    selectionArgs);
            break;
        case INCOME_ID:
            String id = uri.getLastPathSegment();
            if (TextUtils.isEmpty(selection)) {
                rowsDeleted = sqlDB.delete(
                        DBHelpter.TABLE_INCOME,
                        DBHelpter.INCOME_ID + "=" + id,
                        null);
            } else {
                rowsDeleted = sqlDB.delete(
                        DBHelpter.TABLE_INCOME,
                        DBHelpter.INCOME_ID + "=" + id
                                + " and " + selection,
                        selectionArgs);
            }
            break;
        default:
            throw new IllegalArgumentException("Unknown URI: " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return rowsDeleted;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    int uriType = mUriMatcher.match(uri);
    SQLiteDatabase sqlDB = mDBHelper.getWritableDatabase();
    int rowsUpdated = 0;
    switch (uriType) {
        case INCOME:
            rowsUpdated = sqlDB.update(DBHelpter.TABLE_INCOME,
                    values,
                    selection,
                    selectionArgs);
            break;
        case INCOME_ID:
            String id = uri.getLastPathSegment();
            if (TextUtils.isEmpty(selection)) {
                rowsUpdated = sqlDB.update(DBHelpter.TABLE_INCOME,
                        values,
                        DBHelpter.INCOME_ID + "=" + id,
                        null);
            } else {
                rowsUpdated = sqlDB.update(DBHelpter.TABLE_INCOME,
                        values,
                        DBHelpter.INCOME_ID + "=" + id
                                + " and "
                                + selection,
                        selectionArgs);
            }
            break;
        default:
            throw new IllegalArgumentException("Unknown URI: " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return rowsUpdated;
}

}

1
  • What do you meaqn by - Can't refresh ListView AND TextView simultaneously after OnLongClickListener ? I mean which TextView are you talking about Commented Feb 4, 2017 at 8:53

1 Answer 1

1

Maybe you can try to use Loaders.

They let's you bind the data source (Content Provider or other) with the Activity or Fragment. While Loaders are active they should monitor the source of their data and deliver new results when the contents change.

I'll give you a general approach to how implement them (CursorLoader in particular) :

public class MachineInfo extends AppCompatActivity implements
    LoaderManager.LoaderCallbacks<Cursor> {

    private static final int LOADER_INTEGER = 1;

    // ... existing code

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        getLoaderManager().initLoader(LOADER_INTEGER, null, this);
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(
            this,
            ContentProvider.CONTENT_URI,
            projection,
            null,
            null,
            sortOrder
        );
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        mCursorAdapter.swapCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mCursorAdapter.swapCursor(null);
    }
}

You can read a lot on internet about this, a good start is for example here.

Hope this helps

Sign up to request clarification or add additional context in comments.

13 Comments

Sorry for the long delay, I did created a ContentProvider and it does not yet refresh the list. Going to post my other classes. Thanks for trying to help tho
When you call mDbHelper.deleteIncome(id), is your method delete (inside content provider) called? And, I can't see the method deleteIncome inside your DBHelper
Method included now. I did not call the delete method inside the content provider because I want to emulate SQLite raw query ""SELECT _id, note, date, money FROM income WHERE machines_id = "+machinesId+" ORDER BY date ASC"
Try to do this after executing the raw delete : if ( returnNum != 0 ) getContext().getContentResolver().notifyChange(uri,null); where int returnNum = db.delete(...)
I think it is not updating because you are not notifying the loader, so you have to do it when you delete some rows.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.