EDIT: Non ho inserito il mio XML per questa finestra di dialogo.Android 4.0.3 CursorAdapter non popola ListView su changeCursor
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tag_layout"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="@dimen/min_dialog_width"
android:padding="5dp"
android:animateLayoutChanges="true"
>
<!-- Here is the view to show if the list is emtpy -->
<TextView
android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="50dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_centerInParent="true"
android:gravity="center"
android:text="@string/no_items"
android:visibility="invisible"
/>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
/>
<ProgressBar
android:id="@+id/tag_spin_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"
/>
</RelativeLayout>
Sto usando l'android.support.v4.CursorLoader e CursorAdapter e sto cercando di farlo per aggiornare i dati del cursore. In Android 2.3.3 funziona perfettamente. Tuttavia, quando lo provo sul mio dispositivo 4.0.3, il ListView non si aggiorna e il metodo newView nel mio adattatore non viene mai chiamato. So che il cursore contiene dati in quanto posso vederlo sul mio dispositivo 2.3.3.
Se ruoto il mio dispositivo, ListView mostra quello che voglio. Ho provato a invalidare il ListView ma questo non risolve il problema.
Se non reimposta l'adattatore di ListView, l'elenco non diventa vuoto, ma non aggiorna l'elenco.
Sto facendo tutto questo all'interno di un AlertDialog esteso che è incorporato in un DialogFragment.
Ecco l'intera classe
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;
import org.lds.ldssa.service.MLDatabase;
import org.lds.ldssa.service.aws.Annotation;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class TagDialog extends AlertDialog implements LoaderManager.LoaderCallbacks<Cursor>,AdapterView.OnItemClickListener {
private static final String TAG = "ldssa.tagdialog";
public static final int TAGLOADERID = 0;
// View Items
private EditText mEditText;
private ListView mListView;
private TextView mEmptyView;
private ProgressBar mProgressBar;
private ImageButton mNewTagButton;
private ImageButton mSortTagButton;
private TextView mTitle;
private String mTagTitle;
private String mNewTagTitle;
private Annotation mAnnotation;
private ContentFragment mContentFragment;
private boolean isNewTagView;
private static final String KEY_NEWTAGVIEW = "new_tag_view";
private static final String POSITION_KEY = "TAG_POSITION";
private static final String Y_KEY = "TAG_Y";
private static final String SORT_KEY = "TAG_SORT";
private static final String CHECKED_STATE_KEY = "TAG_CHECKED_STATE";
private static final int NOT_SET = -1;
private int mPosition;
private int mY;
private TagSuggestionAdapter mSuggestionAdapter;
private TagListAdapter mTagAdapter;
private MLDatabase mlDatabase;
private boolean mSortAlpha;
private HashMap<Long, CheckedState> mCheckedState;
protected TagDialog(Context context) {
super(context);
}
public void onCreate(Bundle savedInstanceState){
Context context = getContext();
Resources r = context.getResources();
final LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.dialog_tag, null);
// Main parts of the view
mEditText = (EditText) view.findViewById(R.id.tag_new_tag);
mListView = (ListView) view.findViewById(android.R.id.list);
mProgressBar = (ProgressBar) view.findViewById(R.id.tag_spin_progress_bar);
mEmptyView = (TextView) view.findViewById(android.R.id.empty);
mEmptyView.setVisibility(View.INVISIBLE);
// Titlebar
View titleBar = inflater.inflate(R.layout.dialog_tag_title, null);
mNewTagButton = (ImageButton) titleBar.findViewById(R.id.tag_new_icon);
mSortTagButton = (ImageButton) titleBar.findViewById(R.id.tag_sort_icon);
mTitle = (TextView) titleBar.findViewById(R.id.tag_title);
mTagTitle = r.getString(R.string.tag_dialog_title);
mNewTagTitle = r.getString(R.string.tag_new_dialog_title);
this.setCustomTitle(titleBar);
// Buttons
final String OK = r.getString(R.string.ok);
final String CANCEL = r.getString(R.string.cancel);
this.setButton(BUTTON_POSITIVE, OK, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) { /*Never Used*/}});
this.setButton(BUTTON_NEGATIVE, CANCEL, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) { /*Never Used*/}});
// Setup Button Listeners
setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
Button ok = getButton(BUTTON_POSITIVE);
ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(isNewTagView){
hideIMM();
addNewTag();
mEditText.setText("");
setupTagDialog();
} else {
Collection<CheckedState> changes = mCheckedState.values();
boolean success = true;
MLDatabase db = getDatabase();
db.beginAnnotationTransaction();
for(CheckedState change : changes){
if(!change.checked()){
//Detag
db.detagAnnotation(mAnnotation.getDbKey(), change.tagID());
} else {
mAnnotation.saveHighlightsToDatabase(db);
if(mAnnotation.getDbKey().intValue() != MLDatabase.NOT_SET_INT &
change.tagID() != MLDatabase.NOT_SET_INT){
success = db.tagAnnotation(mAnnotation.getDbKey(), change.tagID(), change.changed());
}
}
}
if(success){
db.setAnnotationTransactionSuccessful();
}
db.endAnnotationTransaction();
mCheckedState.clear();
dismiss();
}
}
});
Button cancel = getButton(BUTTON_NEGATIVE);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(isNewTagView){
hideIMM();
setupTagDialog();
mEditText.setText("");
} else {
mCheckedState.clear();
dismiss();
}
}
});
}
});
mNewTagButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setupNewTagDialog();
}
});
mSortTagButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mSortAlpha = !mSortAlpha;
restartLoader();
}
});
mListView.setOnItemClickListener(TagDialog.this);
mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
LoaderManager lm = getLoaderManager();
if(lm != null){
Loader l = lm.getLoader(TAGLOADERID);
if(l != null){
l.forceLoad();
} else {
restartLoader();
}
} else {
restartLoader();
}
}
});
//Handle Rotations
if(savedInstanceState == null){
//New
mPosition = NOT_SET;
mY = NOT_SET;
mSortAlpha = false;
mCheckedState = getCheckedState(mAnnotation.getDbKey());
isNewTagView = false;
} else {
//rotated
isNewTagView = savedInstanceState.getBoolean(KEY_NEWTAGVIEW, false);
mPosition = savedInstanceState.getInt(POSITION_KEY, NOT_SET);
mY = savedInstanceState.getInt(Y_KEY, NOT_SET);
mSortAlpha = savedInstanceState.getBoolean(SORT_KEY, false);
restoreCheckedState(savedInstanceState);
}
mTagAdapter = new TagListAdapter(context, null, mCheckedState);
mSuggestionAdapter = new TagSuggestionAdapter(context, null, 0);
LoaderManager lm = getLoaderManager();
if(lm != null){
lm.initLoader(TAGLOADERID, null, this);
}
this.setView(view);
super.onCreate(savedInstanceState);
}
private void addNewTag() {
String tag = mEditText.getText().toString().trim();
if(!tag.equals("")){
getDatabase();
Integer langID = mAnnotation.getLanguageId();
try{
long tagID = mlDatabase.insertTag(langID, tag);
if(mAnnotation.getDbKey().intValue() != MLDatabase.NOT_SET_INT &&
tagID != MLDatabase.NOT_SET_INT){
mCheckedState.put(tagID, new CheckedState(tagID, true, true));
}
} catch (Exception e) {
Log.d(TAG, "Problem saving new tag: " + tag + " : " + e.getMessage());
e.printStackTrace();
}
}
}
public void onStart(){
if(isNewTagView){
setupNewTagDialog();
} else {
setupTagDialog();
}
restartLoader();
}
@Override
public Bundle onSaveInstanceState(){
Bundle bundle = super.onSaveInstanceState();
//Save What dialog we are in.
bundle.putBoolean(KEY_NEWTAGVIEW, isNewTagView);
bundle.putBoolean(SORT_KEY, mSortAlpha);
//Save position
bundle.putInt(POSITION_KEY, mListView.getFirstVisiblePosition());
final View v = mListView.getChildAt(0);
bundle.putInt(Y_KEY, (v == null) ? 0 : v.getTop());
//Save Checked State
Iterator it = mCheckedState.entrySet().iterator();
int i = 0;
while(it.hasNext()){
Map.Entry pair = (Map.Entry)it.next();
bundle.putSerializable(CHECKED_STATE_KEY + i, (CheckedState)pair.getValue());
i++;
}
bundle.putInt(CHECKED_STATE_KEY, i);
return bundle;
}
private void restoreCheckedState(Bundle bundle){
int count = bundle.getInt(CHECKED_STATE_KEY);
mCheckedState = new HashMap<Long, CheckedState>();
boolean success = true;
for(int i = 0; i < count; i++){
CheckedState cs = (CheckedState)bundle.getSerializable(CHECKED_STATE_KEY+i);
if(cs == null){
success = false;
break;
}
mCheckedState.put(cs.tagID(), cs);
}
if(!success){
mCheckedState = getCheckedState(mAnnotation.getDbKey());
}
}
@Override
public void onBackPressed(){
if(isNewTagView){
hideIMM();
setupTagDialog();
} else {
this.dismiss();
}
}
private void setupTagDialog() {
isNewTagView = false;
mTitle.setText(mTagTitle);
mNewTagButton.setVisibility(View.VISIBLE);
mSortTagButton.setVisibility(View.VISIBLE);
mEmptyView.setVisibility(View.INVISIBLE);
mEditText.setVisibility(View.GONE);
mListView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
mListView.setAdapter(mTagAdapter);
restartLoader();
}
private void setupNewTagDialog() {
isNewTagView = true;
mTitle.setText(mNewTagTitle);
mNewTagButton.setVisibility(View.INVISIBLE);
mSortTagButton.setVisibility(View.INVISIBLE);
mEmptyView.setVisibility(View.INVISIBLE);
mEditText.setVisibility(View.VISIBLE);
mListView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
mListView.setAdapter(mSuggestionAdapter);
restartLoader();
}
public void setAnnotation(Annotation a) {
mAnnotation = a;
}
public void setContentViewInterface(ContentFragment contentFragment) {
mContentFragment = contentFragment;
}
private MLDatabase getDatabase() {
if(mlDatabase == null){
GospelLibraryApplication app = (GospelLibraryApplication) getContext().getApplicationContext();
mlDatabase = app.getMlDatabase();
}
return mlDatabase;
}
public String getFilter() {
return mEditText.getText().toString().trim();
}
public Integer getAnnotationID(){
if(mAnnotation != null){
return mAnnotation.getDbKey();
}
return MLDatabase.NOT_SET_INT;
}
private LoaderManager getLoaderManager(){
if(mContentFragment == null){
Log.d(TAG, "ContentFragment is NULL!");
return null;
}
return mContentFragment.getContentActivity().getSupportLoaderManager();
}
private void restartLoader(){
LoaderManager lm = getLoaderManager();
if(lm != null){
lm.restartLoader(TAGLOADERID, null, this);
}
}
private void hideIMM(){
InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}
private HashMap<Long, CheckedState> getCheckedState(Integer annotationID) {
HashMap<Long, CheckedState> checkedState = new HashMap<Long, CheckedState>();
MLDatabase db = getDatabase();
Cursor cursor = db.queryAllTagsWithAnnotation(annotationID);
if(cursor != null){
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()){
Long tagID = cursor.getLong(cursor.getColumnIndex(MLDatabase.CL_ID));
boolean isChecked = !cursor.isNull(cursor.getColumnIndex(MLDatabase.CL_ANNOTATION));
checkedState.put(tagID, new CheckedState(tagID, isChecked, false));
}
}
return checkedState;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
TagCursorLoader loader = new TagCursorLoader(getContext(), this);
return loader;
}
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
if(isNewTagView) {
mSuggestionAdapter.changeCursor(data);
if(mListView.getAdapter() == null){
mListView.setAdapter(mSuggestionAdapter);
}
} else {
mTagAdapter.changeCursor(data);
if(mListView.getAdapter() == null){
mListView.setAdapter(mTagAdapter);
}
}
if(mPosition != NOT_SET && mY != NOT_SET){
mListView.setSelectionFromTop(mPosition, mY);
mPosition = mY = NOT_SET;
}
if (mListView.getAdapter() != null) {
if (mListView.getAdapter().getCount() > 0) {
mEmptyView.setVisibility(View.INVISIBLE);
}
else {
mEmptyView.setVisibility(View.VISIBLE);
}
}
else {
mEmptyView.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
mListView.setVisibility(View.VISIBLE);
mListView.invalidate();
}
@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
if(mSuggestionAdapter != null) {
mSuggestionAdapter.changeCursor(null);
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(isNewTagView){
TextView tv = (TextView)view;
mEditText.setText(tv.getText());
Button ok = getButton(BUTTON_POSITIVE);
if(ok != null){
ok.performClick();
}
} else {
CheckedTextView ctv = (CheckedTextView)view;
boolean checked = !ctv.isChecked();
ctv.setChecked(checked);
mCheckedState.put(id, new CheckedState(id, checked, true));
}
}
public static class TagCursorLoader extends CursorLoader {
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
private TagDialog dialog;
private MLDatabase mlDatabase;
private Cursor mCursor;
private String mFilter;
private Integer mAnnotationID;
// Runs on worker thread
@Override
public Cursor loadInBackground(){
Cursor cursor = null;
if(dialog.isNewTagView){
mFilter = dialog.getFilter();
cursor = mlDatabase.getTagSuggestions(mFilter);
} else {
cursor = mlDatabase.queryTags(dialog.mSortAlpha);
}
if(cursor != null){
cursor.registerContentObserver(mObserver);
}
return cursor;
}
//Runs on UI thread
@Override
public void deliverResult(Cursor cursor){
//Handle if canceled in the middle.
if(isReset()){
if(cursor != null){
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if(isStarted()) {
super.deliverResult(cursor);
}
if(oldCursor != null && !oldCursor.equals(cursor) && !oldCursor.isClosed()) {
oldCursor.close();
}
}
public TagCursorLoader(Context context, TagDialog dialog) {
super(context);
this.dialog = dialog;
mlDatabase = dialog.getDatabase();
}
@Override
public void onStartLoading(){
if(mCursor == null) {
forceLoad();
} else {
if(dialog.isNewTagView && mFilter.equals(dialog.getFilter())) {
deliverResult(mCursor);
} else {
forceLoad();
}
}
}
@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;
}
}
/**
* Class is used to store the temporary checked state of the tags.
*/
public class CheckedState implements Serializable {
private static final long serialVersionUID = 1263560458217339487L;
/**
* @serialField
*/
private long tagID;
/**
* @serialField
*/
private boolean checked;
/**
* @serialField
*/
private boolean changed;
/**
* Constructor for CheckedState.
* @param tagID The tag ID
* @param checked The Current Checked State
* @param changed Ture if changed in the dialog. False if pulling from database.
*/
public CheckedState(long tagID, boolean checked, boolean changed){
this.tagID = tagID;
this.checked = checked;
this.changed = changed;
}
public long tagID(){
return tagID;
}
public boolean checked() {
return checked;
}
public boolean changed() {
return changed;
}
}
}
[Questo commento] (http://stackoverflow.com/a/9063814/1348379) di CommonsWare mi ha aiutato quando avevo problemi simili. Non penso che dovresti scambiare gli adattatori come stai facendo. Scorrimento del cursore tramite '' '' swapCursore (cursore) '' '' - sì, elenca gli adattatori- no. Crea un frammento separato con un altro caricatore per quella informazione e inizializza sia l'adattatore (tramite '' '' setAdapter (...) '' '' e caricatore ('' '' initLoader'''' durante onActivityCreated. – OceanLife
@OceanLife Non sto utilizzando un'attività, lo sto facendo tutto in un AlertDialog esteso. – Ge3ng
hai provato initLoader (...). ForceLoad()? Ho avuto alcuni problemi con ICS e sono riuscito a risolverli. –