Tengo un Fragment que contiene ListView. Estoy agregando algunos valores a la base de datos con un cuadro de diálogo y quiero actualizar esto ListView después de cerrar el cuadro de diálogo. Además, cuando cambio la pestaña, ListView no se actualiza, pero cuando la aplicación se enciende y apaga, se actualiza ListView.

Las clases Fragment y Dialog son las siguientes:

Fragmento:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_teams, container, false);

    listViewTeams = rootView.findViewById(R.id.listView_teams);

    TeamDatabase teamDatabase = new TeamDatabase(getContext());
    teamDatabase.open();
    arrayListTeam = teamDatabase.getAllTeams();
    teamDatabase.close();

    int resID = R.layout.team_list_item;
    teamListArrayAdapter = new TeamListArrayAdapter(getContext(), resID, arrayListTeam);
    listViewTeams.setAdapter(teamListArrayAdapter);

    return rootView;
}

Diálogo Método onClick:

@Override
public void onClick(View view) {
   int id = view.getId();

   switch (id){
       case R.id.button_alertDialogAddTeam_cancel:
           this.dismiss();
           break;
       case R.id.button_alertDialogAddTeam_ok:
           Team team = new Team();
           team.setName(editTextTeamName.getText().toString());
           team.setCode(editTextTeamCode.getText().toString());

           TeamDatabase teamDatabase = new TeamDatabase(getContext());
           teamDatabase.open();
           if(teamDatabase.addNewTeam(team)) {
               Toast.makeText(getContext(), team.getCode() + " - " +
                       team.getName() + " was added successfully", Toast.LENGTH_SHORT).show();
           }

           this.dismiss();
           break;
   }
}

Clase TeamDatabase:

    public static final String TABLE_NAME = "team";

private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
private static final String KEY_CODE = "code";
private static final String KEY_EMBLEM = "emblem";

private Context context;

public static final String CREATE_TABLE = "CREATE TABLE "+
        TABLE_NAME + " ("+
        KEY_ID  + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, "+
        KEY_NAME + " TEXT NOT NULL, "+
        KEY_CODE + " TEXT NOT NULL, " +
        KEY_EMBLEM + " TEXT);";


public TeamDatabase(Context context) {
    super(context);
    this.context = context;
}

public boolean addNewTeam(Team team){
    ContentValues contentValues = new ContentValues();

    contentValues.put(KEY_NAME, team.getName());
    contentValues.put(KEY_CODE, team.getCode());

    return db.insert(TABLE_NAME, null, contentValues) > 0;
}

public ArrayList<Team> getAllTeams()
{
    ArrayList<Team> teams = new ArrayList<Team>();

    Cursor cursor = db.query(TABLE_NAME, new String[]{KEY_ID,
            KEY_NAME,
            KEY_CODE}, null, null, null, null, null);

    while(cursor.moveToNext()) {

        Team team = new Team();

        team.setId(cursor.getInt(cursor.getColumnIndex(KEY_ID)));
        team.setName(cursor.getString(cursor.getColumnIndex(KEY_NAME)));
        team.setCode(cursor.getString(cursor.getColumnIndex(KEY_CODE)));

        teams.add(team);
    }
    return teams;
}

Clase DatabaseHelper:

private static final String DATABASE_NAME = "fixtureCreator.db";
private static final int DATABASE_VERSION = 1;

public SQLiteDatabase db;

public DatabaseHelper(Context context){
    super(context, DATABASE_NAME, null, DATABASE_VERSION);

}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
    sqLiteDatabase.execSQL(TeamDatabase.CREATE_TABLE);
}



@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersinon) {
    Log.w("TaskDBAdapter", "Upgrading from version " +
            oldVersion + " to " + newVersinon + ", which will destroy all old data");

    sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TeamDatabase.TABLE_NAME);
    onCreate(sqLiteDatabase);
}

public DatabaseHelper open() throws SQLException {
    try{
        db = this.getWritableDatabase();
    }catch (SQLException e){
        db = this.getReadableDatabase();
    }
    return this;
}

public void close(){
    db.close();
}
1
Oguz OZSOY 24 feb. 2018 a las 20:37

4 respuestas

La mejor respuesta

El problema se puede resolver mediante la obtención de los datos después de guardarlos cada vez que haga clic en Dialog y luego llame a notifyDataSetChanged() en su adaptador. Sin embargo, hay una forma más elegante de lograr este tipo de comportamiento, que resolverá ambos problemas usando el observador de contenido.

En caso de tener un observador de contenido en su tabla de base de datos, primero debe declarar un URI que haga referencia a su tabla.

public static final Uri DB_TABLE_TEAM_URI = Uri
            .parse("sqlite://" + Constants.ApplicationPackage + "/" + DB_TABLE_TEAM);

// DB_TABLE_TEAM refers to the database table that you have for storing teams.

Ahora en su función addNewTeam necesita hacer lo siguiente.

public boolean addNewTeam(Team team) {
    // .. Save the team in database
    // Notify the observer about the change in the content
    context.getContentResolver().notifyChange(DBConstants.DB_TABLE_TEAM_URI, null);
}

Debe llamar a la función notifyChange() cada vez que agrega o actualiza una entrada en la tabla de su equipo.

Ahora en su Activity o Fragment necesita registrar a su observador en su cursor para obtener los datos del equipo de su tabla de equipo.

cursor = teamDatabase.getAllTeamsInCursor();
this.registerContentObserver(cursor, DBConstants.DB_TABLE_TEAM_URI);

Ahora complete su ListView usando cursor pasándolo a su adaptador de ListView. La lista se actualizará automáticamente una vez que se hayan insertado nuevos datos en la tabla de su equipo.

Actualizar

Modifique la función addNewTeam en su clase TeamDatabase de la siguiente manera.

public static final Uri DB_TABLE_TEAM_URI = Uri
        .parse("sqlite://" + Constants.ApplicationPackage + "/" + DB_TABLE_TEAM);

public boolean addNewTeam(Team team){
    ContentValues contentValues = new ContentValues();

    contentValues.put(KEY_NAME, team.getName());
    contentValues.put(KEY_CODE, team.getCode());

    boolean success = db.insert(TABLE_NAME, null, contentValues) > 0;
    context.getContentResolver().notifyChange(DBConstants.DB_TABLE_TEAM_URI, null);
    return success;
}

Para implementar las funcionalidades con LoaderCallbacks primero necesita implement la interfaz de LoaderCallbacks en su Fragment. Así se verá la declaración de su Fragment.

public class TeamsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
    // .... Code
}

Ahora necesita anular las funciones que vienen junto con la interfaz de LoaderCallbacks.

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    return new SQLiteCursorLoader(getActivity()) {
        @Override
        public Cursor loadInBackground() {
            // Initialize your database
            TeamDatabase teamDatabase = new TeamDatabase(getActivity());

            Cursor cursor = teamDatabase.getAllTeams();

            if (cursor != null) {
                // Register the content observer here
                this.registerContentObserver(cursor, DBConstants.DB_TABLE_TEAM_URI);
            }

            return cursor;
        }
    };
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // Set the cursor in your adapter. Handle null values in your setCursor function in your adapter. The cursor might return null when the table is empty.
    teamAdapter.setCursor(cursor);
    teamAdapter.notifyDataSetChanged();
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
}

Ahora en su función onCreateView en Fragment, debe iniciar el cargador para obtener datos de la tabla.

getLoaderManager().initLoader(0, null, this).forceLoad();

Y destruya el cargador y anule el registro del receptor en la función onDestroyView.

@Override
public void onDestroyView() {
    getLoaderManager().destroyLoader(0);
    super.onDestroyView();
}

Me faltaba la clase SQLiteCursorLoader que se agregaría aquí.

package com.wooz.observer.databases;

import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;

public abstract class SQLiteCursorLoader extends AsyncTaskLoader<Cursor> {
    private final ForceLoadContentObserver mObserver;

    private Uri mUri;
    private String[] mProjection;
    private String mSelection;
    private String[] mSelectionArgs;
    private String mSortOrder;

    private Cursor mCursor;

    /* Runs on a worker thread */
    @Override
    public abstract Cursor loadInBackground();

    /**
     * Registers an observer to get notifications from the content provider
     * when the cursor needs to be refreshed.
     */
    public void registerContentObserver(Cursor cursor, Uri observerUri) {
        cursor.registerContentObserver(mObserver);
        cursor.setNotificationUri(getContext().getContentResolver(), observerUri);
    }

    /* Runs on the UI thread */
    @Override
    public void deliverResult(Cursor cursor) {
        try {
            if (isReset()) {
                // An async query came in while the loader is stopped
                if (cursor != null) {
                    cursor.close();
                }
                return;
            }
            Cursor oldCursor = mCursor;
            mCursor = cursor;

            if (isStarted()) {
                super.deliverResult(cursor);
            }

            if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
                oldCursor.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Creates an empty unspecified CursorLoader.  You must follow this with
     * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
     * to specify the query to perform.
     */
    public SQLiteCursorLoader(Context context) {
        super(context);
        mObserver = new ForceLoadContentObserver();
    }

    /**
     * Creates a fully-specified CursorLoader.  See
     * {@link ContentResolver#query(Uri, String[], String, String[], String)
     * ContentResolver.query()} for documentation on the meaning of the
     * parameters.  These will be passed as-is to that call.
     */
    public SQLiteCursorLoader(Context context, Uri uri, String[] projection, String selection,
                              String[] selectionArgs, String sortOrder) {
        super(context);
        mObserver = new ForceLoadContentObserver();
        mUri = uri;
        mProjection = projection;
        mSelection = selection;
        mSelectionArgs = selectionArgs;
        mSortOrder = sortOrder;
    }

    /**
     * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
     * will be called on the UI thread. If a previous load has been completed and is still valid
     * the result may be passed to the callbacks immediately.
     * <p>
     * Must be called from the UI thread
     */
    @Override
    protected void onStartLoading() {
        if (mCursor != null) {
            deliverResult(mCursor);
        }
        if (takeContentChanged() || mCursor == null) {
            forceLoad();
        }
    }

    /**
     * Must be called from the UI thread
     */
    @Override
    protected void onStopLoading() {
        // Attempt to cancel the current load task if possible.
        cancelLoad();
    }

    @Override
    public void onCanceled(Cursor cursor) {
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
    }

    @Override
    protected void onReset() {
        super.onReset();

        // Ensure the loader is stopped
        onStopLoading();

        if (mCursor != null && !mCursor.isClosed()) {
            mCursor.close();
        }
        mCursor = null;
    }

    public Uri getUri() {
        return mUri;
    }

    public void setUri(Uri uri) {
        mUri = uri;
    }

    public String[] getProjection() {
        return mProjection;
    }

    public void setProjection(String[] projection) {
        mProjection = projection;
    }

    public String getSelection() {
        return mSelection;
    }

    public void setSelection(String selection) {
        mSelection = selection;
    }

    public String[] getSelectionArgs() {
        return mSelectionArgs;
    }

    public void setSelectionArgs(String[] selectionArgs) {
        mSelectionArgs = selectionArgs;
    }

    public String getSortOrder() {
        return mSortOrder;
    }

    public void setSortOrder(String sortOrder) {
        mSortOrder = sortOrder;
    }

    @Override
    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
        super.dump(prefix, fd, writer, args);
        writer.print(prefix);
        writer.print("mUri=");
        writer.println(mUri);
        writer.print(prefix);
        writer.print("mProjection=");
        writer.println(Arrays.toString(mProjection));
        writer.print(prefix);
        writer.print("mSelection=");
        writer.println(mSelection);
        writer.print(prefix);
        writer.print("mSelectionArgs=");
        writer.println(Arrays.toString(mSelectionArgs));
        writer.print(prefix);
        writer.print("mSortOrder=");
        writer.println(mSortOrder);
        writer.print(prefix);
        writer.print("mCursor=");
        writer.println(mCursor);
        //writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged);
    }

    private class CursorLoaderContentObserver extends ContentObserver {
        public CursorLoaderContentObserver() {
            super(new Handler());
        }

        @Override
        public boolean deliverSelfNotifications() {
            return true;
        }

        @Override
        public void onChange(boolean selfChange) {
            onContentChanged();
        }
    }
} 
1
Reaz Murshed 13 mar. 2019 a las 05:12

Al hacer clic en el elemento en su primera Actividad, comience su segunda Actividad con startActivityForResult()

Y luego, en la segunda actividad, después de cerrar el diálogo, en onClick de esa llamada de botón,

intent.putExtra("new data", "item text");
setResult(RESULT_OK, intent);
finish();

Ahora vuelve a su primera Actividad y aquí debe implementar la devolución de llamada onActivityResult().

Puede extraer datos de los extras de ese intento y establecer ese elemento respectivo en su matriz y llamar a notifyDataSetChanged ().

Esto es idealmente cómo debería hacerlo.

2
Ouail Bellal 24 feb. 2018 a las 17:54

Debe llamar a notifyDataSetChanged justo antes de cerrar el cuadro de diálogo

teamListArrayAdapter.notifyDataSetChanged ();

Deberías cambiar tu código algo como esto a continuación

   @Override
public void onClick(View view) {
   int id = view.getId();

   switch (id){
       case R.id.button_alertDialogAddTeam_cancel:
           this.dismiss();
           break;
       case R.id.button_alertDialogAddTeam_ok:
           Team team = new Team();
           team.setName(editTextTeamName.getText().toString());
           team.setCode(editTextTeamCode.getText().toString());

           TeamDatabase teamDatabase = new TeamDatabase(getContext());
           teamDatabase.open();
           if(teamDatabase.addNewTeam(team)) {
               Toast.makeText(getContext(), team.getCode() + " - " +
                       team.getName() + " was added successfully", Toast.LENGTH_SHORT).show();
           }
           arrayListTeam = teamDatabase.getAllTeams();
           teamListArrayAdapter.notifyDataSetChanged();
           this.dismiss();
           break;
   }
}
1
lib4 24 feb. 2018 a las 17:48

Agregue este código en onCreateView:

teamListArrayAdapter.notifyDataSetChanged();
0
armen 24 feb. 2018 a las 18:56