質問

I have an expandable list, with a custom adapter, two cursor (from base expandable list adapter), and a content provider.

Now, my main objective is to refresh this expandable list, after inserting new data with a activity that is called with a intent. I'm trying a Content Observer, but with no success, because no refresh is done.

I put the relevant code (I think). Thank you very much.

public class ActPlacesManagement extends Activity{
private static final int DELETE_ID = Menu.FIRST;

private static final String TAG = null; 

public Cursor mPlacesCursor;
public Cursor mBoxesCursor;
ExpandableListView lstCategorias;
AdpPlacesManagement adapter;
String message, message1, message2;
String novo_local, nova_caixa;
Button btnNewPlace, btnNewBox;
Handler handler;

private static final String[] PROJECTION_PLACES = new String[] {
    ProvPersonalArchive.KEY_ROWID_PLACES,
    ProvPersonalArchive.KEY_DESIG_PLACES,
};

private static final String[] PROJECTION_BOXES = new String[] {
    ProvPersonalArchive.KEY_ROWID_BOXES,
    ProvPersonalArchive.KEY_DESIG_BOXES,
    ProvPersonalArchive.KEY_PLACE_BOXES,
};



protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.act_places_management);       

    mPlacesCursor = getContentResolver().query(ProvPersonalArchive.CONTENT_URI_PLACES, 
            PROJECTION_PLACES, null, null, null);

    mBoxesCursor = getContentResolver().query(ProvPersonalArchive.CONTENT_URI_BOXES, 
            PROJECTION_BOXES, null, null, null);



    lstCategorias = (ExpandableListView)this.findViewById(R.id.expandableGestaoCategorias);

    adapter = new AdpPlacesManagement(this, mPlacesCursor, mBoxesCursor, this);     

    lstCategorias.setAdapter(adapter);

    lstCategorias.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {

        @Override
        public boolean onGroupClick(ExpandableListView parent, View v,
                int groupPosition, long id) {
            return lstCategorias_onGroupClick(parent, v, groupPosition, id);
        }
    });

    lstCategorias.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {

        @Override
        public boolean onChildClick(ExpandableListView parent, View v,
                int groupPosition, int childPosition, long id) {
            return lstCategorias_onChildClick(parent, v, groupPosition, childPosition, id);
        }
    });



    btnNewPlace = (Button)this.findViewById(R.act_gestao_categorias.novo_lugar);
    btnNewBox = (Button)this.findViewById(R.act_gestao_categorias.nova_caixa);

    btnNewPlace.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            btnNewPlace_onClick(v);
        }
    });

    btnNewBox.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            btnNewBox_onClick(v);
        }
    });

    registerForContextMenu(lstCategorias);


    mPlacesCursor.registerContentObserver(new ObsPersonalArchive(handler));
    mBoxesCursor.registerContentObserver(new ObsPersonalArchive(handler));

}


// Eventos da lista de locais e caixas

public boolean lstCategorias_onGroupClick(ExpandableListView parent, View v,
        int groupPosition, long id) {
    return false;
}

public boolean lstCategorias_onChildClick(ExpandableListView parent, View v,
        int groupPosition, int childPosition, long id) {        
    return false;
}

// Termina a actividade e volta à ActInicial, levando o local

public void finish() {
  // Prepare data intent 
  Intent data = new Intent();
  setResult(RESULT_OK, data);
  data.putExtra("local", message);
  // Activity finished ok, return the data
  super.finish();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.act_start, menu);
    return true;
}


// Eventos dos botões para criar novo local e caixa

public void btnNewPlace_onClick(View view) {
    Intent intent = new Intent(this, ActNewPlace.class);
    startActivityForResult(intent, 1);
}

public void btnNewBox_onClick(View view) {
    Intent intent = new Intent(this, ActNewBox.class);
    startActivityForResult(intent, 2);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (resultCode == RESULT_OK && requestCode == 1) {
        if (data.hasExtra("novo_local") && data.hasExtra("nova_caixa")) {

            // Chama o método para gravar o local na base de dados
            Toast.makeText(this, "New place created!", Toast.LENGTH_LONG).show();
        }
      }
      if (resultCode == RESULT_OK && requestCode == 2) {
        if (data.hasExtra("novo_local") && data.hasExtra("nova_caixa")) {
            String novo_local = data.getExtras().getString("novo_local");
            String nova_caixa = data.getExtras().getString("nova_caixa");
            Toast.makeText(this, novo_local + nova_caixa, Toast.LENGTH_LONG).show();
        }
      }
    }




public class ObsPersonalArchive extends ContentObserver {

    public ObsPersonalArchive(Handler handler) {
        super(handler);        
        }
       @Override
       public void onChange(boolean selfChange) {
            super.onChange(selfChange);
       }        
}

}

Michael, the new class I wrote:

import android.app.Activity;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.Button;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.Toast;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;


public class ActPlacesManagement extends FragmentActivity
implements LoaderManager.LoaderCallbacks<Cursor>{


private static final int DELETE_ID = Menu.FIRST;

private static final String TAG = null;


public Cursor mPlacesCursor;
public Cursor mBoxesCursor;
ExpandableListView lstCategorias;
AdpPlacesManagement adapter;
String message, message1, message2;
String novo_local, nova_caixa;
Button btnNewPlace, btnNewBox;
Handler handler;
LoaderManager loaderManager = getSupportLoaderManager();

private static final String[] PROJECTION_PLACES = new String[] {
    ProvPersonalArchive.KEY_ROWID_PLACES, // 0
    ProvPersonalArchive.KEY_DESIG_PLACES, // 1
};

private static final String[] PROJECTION_BOXES = new String[] {
    ProvPersonalArchive.KEY_ROWID_BOXES, // 0
    ProvPersonalArchive.KEY_DESIG_BOXES, // 1
    ProvPersonalArchive.KEY_PLACE_BOXES, // 2
};

private static final int PLACES_LOADER = 1;
private static final int BOXES_LOADER = 2;


private LoaderManager.LoaderCallbacks<Cursor> mCallbacks;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.act_places_management);       

    mPlacesCursor = getContentResolver().query(ProvPersonalArchive.CONTENT_URI_PLACES, 
            PROJECTION_PLACES, null, null, null);

    mBoxesCursor = getContentResolver().query(ProvPersonalArchive.CONTENT_URI_BOXES, 
            PROJECTION_BOXES, null, null, null);


    // Lista de locais e caixas

    lstCategorias = (ExpandableListView)this.findViewById(R.id.expandableGestaoCategorias);

    adapter = new AdpPlacesManagement(this, mPlacesCursor, mBoxesCursor, this);     

    lstCategorias.setAdapter(adapter);

    lstCategorias.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {

        @Override
        public boolean onGroupClick(ExpandableListView parent, View v,
                int groupPosition, long id) {
            return lstCategorias_onGroupClick(parent, v, groupPosition, id);
        }
    });

    lstCategorias.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {

        @Override
        public boolean onChildClick(ExpandableListView parent, View v,
                int groupPosition, int childPosition, long id) {
            return lstCategorias_onChildClick(parent, v, groupPosition, childPosition, id);
        }
    });


    // Botões para novo lugar e caixa

    btnNewPlace = (Button)this.findViewById(R.act_gestao_categorias.novo_lugar);
    btnNewBox = (Button)this.findViewById(R.act_gestao_categorias.nova_caixa);

    btnNewPlace.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            btnNewPlace_onClick(v);
        }
    });

    btnNewBox.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            btnNewBox_onClick(v);
        }
    });

    registerForContextMenu(lstCategorias);

    getSupportLoaderManager().initLoader(BOXES_LOADER, null, mCallbacks);
    getSupportLoaderManager().initLoader(PLACES_LOADER, null, mCallbacks);

}


// Eventos da lista de locais e caixas

public boolean lstCategorias_onGroupClick(ExpandableListView parent, View v,
        int groupPosition, long id) {
    return false;
}

public boolean lstCategorias_onChildClick(ExpandableListView parent, View v,
        int groupPosition, int childPosition, long id) {
    return false;
}


public void finish() { 
  Intent data = new Intent();
  setResult(RESULT_OK, data);
  data.putExtra("local", message);
  super.finish();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.act_start, menu);
    return true;
}


// Eventos dos botões para criar novo local e caixa

public void btnNewPlace_onClick(View view) {
    Intent intent = new Intent(this, ActNewPlace.class);
    startActivityForResult(intent, 1);
}

public void btnNewBox_onClick(View view) {
    Intent intent = new Intent(this, ActNewBox.class);
    startActivityForResult(intent, 2);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (resultCode == RESULT_OK && requestCode == 1) {
        if (data.hasExtra("novo_local") && data.hasExtra("nova_caixa")) {
            Toast.makeText(this, "New place created!", Toast.LENGTH_LONG).show();
        }
      }
      if (resultCode == RESULT_OK && requestCode == 2) {
        if (data.hasExtra("novo_local") && data.hasExtra("nova_caixa")) {
            String novo_local = data.getExtras().getString("novo_local");
            String nova_caixa = data.getExtras().getString("nova_caixa");
            Toast.makeText(this, novo_local + nova_caixa, Toast.LENGTH_LONG).show();
        }
      }
    }



// Menu de contexto

public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
ExpandableListView.ExpandableListContextMenuInfo info;

try {
    // Casts the incoming data object into the type for AdapterView objects.
    info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
} catch (ClassCastException e) {
    // If the menu object can't be cast, logs an error.
    Log.e(TAG, "bad menuInfo", e);
    return;
}


int place = ExpandableListView.getPackedPositionGroup(info.packedPosition);
int box = ExpandableListView.getPackedPositionChild(info.packedPosition);
int tipo_clic = ExpandableListView.getPackedPositionType(info.packedPosition);
String titulo = null;

if (tipo_clic == ExpandableListView.PACKED_POSITION_TYPE_CHILD){
    titulo = (String) adapter.getChild(place, box);
    menu.add(0, DELETE_ID, 0, R.string.delete_box);
}

if (tipo_clic == ExpandableListView.PACKED_POSITION_TYPE_GROUP){
    titulo = (String) adapter.getGroup(place);
    menu.add(0, DELETE_ID, 0, R.string.delete_place);
}

if (titulo == null) {
    // For some reason the requested item isn't available, do nothing
    return;
}
menu.setHeaderTitle(titulo);

}


public boolean onContextItemSelected(MenuItem item) {
ExpandableListView.ExpandableListContextMenuInfo info =     
(ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();
int tipo_clic = ExpandableListView.getPackedPositionType(info.packedPosition);
switch(item.getItemId()) {
case DELETE_ID:
    if (tipo_clic == ExpandableListView.PACKED_POSITION_TYPE_CHILD){
        Toast.makeText(this, "The box was deleted", Toast.LENGTH_LONG).show();
    }

    if (tipo_clic == ExpandableListView.PACKED_POSITION_TYPE_GROUP){
        Toast.makeText(this, "The place was deleted", Toast.LENGTH_LONG).show();
    }
    return true;
}
return super.onContextItemSelected(item);
}


public Loader<Cursor> onCreateLoader(int id, Bundle arg1) {

CursorLoader cursorLoader = new CursorLoader(getBaseContext());

if (id == BOXES_LOADER){
    cursorLoader = new CursorLoader(ActPlacesManagement.this,
 ProvPersonalArchive.CONTENT_URI_BOXES, PROJECTION_BOXES, null, null, null);
 };

 if (id == PLACES_LOADER){
     cursorLoader = new CursorLoader(ActPlacesManagement.this,
  ProvPersonalArchive.CONTENT_URI_PLACES, PROJECTION_PLACES, null, null, null);
  };

return cursorLoader;
}



public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

switch (loader.getId()) {
case BOXES_LOADER:
    mPlacesCursor = cursor;
  break;
case PLACES_LOADER:
    mBoxesCursor = cursor;
    break;
} 

adapter = new AdpPlacesManagement(this, mPlacesCursor, mBoxesCursor, this);     

lstCategorias.setAdapter(adapter);
}



public void onLoaderReset(Loader<Cursor> loader) {
switch (loader.getId()) {
case BOXES_LOADER:
    mPlacesCursor = null;
  break;
case PLACES_LOADER:
    mBoxesCursor = null;
    break;
} 

adapter = new AdpPlacesManagement(this, mPlacesCursor, mBoxesCursor, this);

}

public class ObsPersonalArchive extends ContentObserver {

    public ObsPersonalArchive(Handler handler) {
        super(handler);        
        }
       @Override
       public void onChange(boolean selfChange) {
            super.onChange(selfChange);
       }        
}   
}   

And the errors

12-17 17:28:59.775: I/ActivityThread(16376): enter process activity msg = 101 12-17 17:28:59.795: I/ActivityThread(16376): exit process activity msg = 101 12-17 17:28:59.805: I/ActivityThread(16376): enter process activity msg = 100 12-17 17:28:59.905: W/dalvikvm(16376): threadid=1: thread exiting with uncaught exception (group=0x2aacc8a0) 12-17 17:28:59.915: E/AndroidRuntime(16376): FATAL EXCEPTION: main 12-17 17:28:59.915: E/AndroidRuntime(16376): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.smartmobilelife.personal.archive/com.smartmobilelife.personal.archive.ActPlacesManagement}: java.lang.NullPointerException 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2705) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2721) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.app.ActivityThread.access$2300(ActivityThread.java:132) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2071) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.os.Handler.dispatchMessage(Handler.java:99) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.os.Looper.loop(Looper.java:123) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.app.ActivityThread.main(ActivityThread.java:4669) 12-17 17:28:59.915: E/AndroidRuntime(16376): at java.lang.reflect.Method.invokeNative(Native Method) 12-17 17:28:59.915: E/AndroidRuntime(16376): at java.lang.reflect.Method.invoke(Method.java:521) 12-17 17:28:59.915: E/AndroidRuntime(16376): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:876) 12-17 17:28:59.915: E/AndroidRuntime(16376): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:634) 12-17 17:28:59.915: E/AndroidRuntime(16376): at dalvik.system.NativeStart.main(Native Method) 12-17 17:28:59.915: E/AndroidRuntime(16376): Caused by: java.lang.NullPointerException 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.support.v4.app.LoaderManagerImpl.createLoader(LoaderManager.java:487) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.support.v4.app.LoaderManagerImpl.createAndInstallLoader(LoaderManager.java:496) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:550) 12-17 17:28:59.915: E/AndroidRuntime(16376): at com.smartmobilelife.personal.archive.ActPlacesManagement.onCreate(ActPlacesManagement.java:131) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 12-17 17:28:59.915: E/AndroidRuntime(16376): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2669) 12-17 17:28:59.915: E/AndroidRuntime(16376): ... 11 more

役に立ちましたか?

解決

I'd recommend using a CursorLoader and have that update the cursor on the list adapter when it receives an update.

CursorLoaders are ContentObservers by default, you just have to be sure that your ContentProvider is setting the proper uri when returning the query cursor and also is notifying of the change in update/insert/delete.

CursorLoader documentation: http://developer.android.com/reference/android/content/CursorLoader.html

LoaderManager.LoaderCallbacks<Cursor> mLoaderCallback = new LoaderManager.LoaderCallbacks<Cursor>() {

@Override

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

    CursorLoader loader = new CursorLoader(context);

    loader.setProjection(args.getStringArray("projection"));

    loader.setSelection(args.getString("selection"));

    loader.setSelectionArgs(args.getStringArray("selectionArgs"));

    loader.setUri(Uri.parse(args.getString("uri")));



    return loader;

}



@Override

public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {

    if (cursor == null) {

       return;

    }



    YourListAdapter adapter = (YourListAdapter) getListAdapter();

    adapter.swapCursor(cursor);

}



@Override

public void onLoaderReset(Loader<Cursor> cursorLoader) {

    YourListAdapter adapter = (YourListAdapter) getListAdapter();

    adapter.swapCursor(null);

}

};



/* Calling a loader sample. */



Bundle loaderArgs = new Bundle();

loaderArgs.putString("uri", URI);

loaderArgs.putStringArray("projection", PROJECTION);



LoaderManager loaderManager = getLoaderManager();

loaderManager.initLoader(YOUR_LOADER_ID, loaderArgs, mYourLoaderCallback);
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top