1

我有一個ListFragment與自定義CursorAdapter連接到數據庫。數據庫中的項目沒有出現在ListView中,包括ListHeader,而是我只看到一個旋轉輪。在ListFragment中的ListView不加載項目

我有我的應用程序工作正常與ListCragment之前的SimpleCursorAdapter。我已經在非空數據庫上進行了測試。 我唯一的線索,爲什麼這不起作用的是,當我嘗試ContextActionMenu中的「全部刪除」選項時,我在LogCat中出現以下錯誤。

ViewRootImpl sendUserActionEvent() == null

這裏是ListFragment:

import com.actionbarsherlock.app.SherlockListFragment; 
import com.actionbarsherlock.view.ActionMode; 
import com.actionbarsherlock.view.ActionMode.Callback; 
import com.actionbarsherlock.view.Menu; 
import com.actionbarsherlock.view.MenuInflater; 
import com.actionbarsherlock.view.MenuItem; 

import info.mariegrap.dancejournal.R.id; 
import info.mariegrap.database.DanceContentProvider; 
import info.mariegrap.database.DanceDatabaseHelper; 
import info.mariegrap.database.StyleCursorAdapter; 
import info.mariegrap.database.StyleTable; 
import info.mariegrap.model.Style; 
import android.app.Activity; 
import android.content.ContentValues; 
import android.content.Context; 
import android.net.Uri; 
import android.os.Bundle; 
import android.support.v4.app.LoaderManager; 
import android.support.v4.content.CursorLoader; 
import android.support.v4.content.Loader; 
import android.util.Log; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.AdapterView.OnItemLongClickListener; 
import android.widget.ListView; 
import android.database.Cursor; 
import android.database.SQLException; 

public class StyleFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>{ 

    private static final int LOADER_ID = 0; 

    private Context context; 
    private OnStyleSelectedListener callback; 
    private StyleCursorAdapter styleAdapter; 
    private DanceDatabaseHelper myDbHelper; 
    private Callback mActionModeCallback; 
    private ActionMode mActionMode; 
    private long selectedId; 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState){ 
     super.onActivityCreated(savedInstanceState); 
     context = this.getActivity(); 
     setHasOptionsMenu(true); 
     //setRetainInstance(true); 
     this.getListView().setBackgroundColor(getResources().getColor(R.color.style_background)); 
     //this.getListView().setDividerHeight(0); 
     this.getListView().setScrollingCacheEnabled(true); 
     this.getListView().addHeaderView(new ListHeader(context, 
       this.getResources().getString(R.string.list_header_style_title), 
       this.getResources().getString(R.string.list_header_style_subtitle))); 
     this.setActionModeCallback(); 
     this.setLongClickListener(); 

     /*myDbHelper = new DanceDatabaseHelper(this.context, null, 
       null, 1); 
     try { 
      myDbHelper.openDataBase();; 
     }catch(SQLException sqle){ 
       throw sqle; 
     }*/ 



     this.styleAdapter = new StyleCursorAdapter(context, null, 0); 
     getLoaderManager().initLoader(LOADER_ID, null, this); 
     this.getListView().setAdapter(this.styleAdapter); 
     Log.d("mgrap", "Adapter: " + styleAdapter); 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 

     try { 
      callback = (OnStyleSelectedListener) activity; 
     } catch (ClassCastException e) { 
      throw new ClassCastException(activity.toString() 
        + " must implement OnStyleSelectedListener"); 
     } 
    } 

    @Override 
    public void onListItemClick(ListView l, View v, int position, long id){ 
     if (position == 0){ 
      return; 
     } 
     this.setListAdapter(null); 
     this.getListView().getChildAt(position); 
     callback.onStyleSelected(position); 
    } 


    public interface OnStyleSelectedListener { 
     /** Called by StyleFragment when a list item is selected */ 
     public void onStyleSelected(int position); 
    } 

    @Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     inflater.inflate(R.menu.style_actionbar, menu); 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     switch (item.getItemId()) { 
      case R.id.style_add: 
       ContentValues cv = new ContentValues(); 
       cv.put(StyleTable.STYLE_KEY_NAME, "Tada!"); 
       Uri uri = Uri.parse("content://info.mariegrap.dancejournal.provider/style_table/0"); 
       Uri idUri = context.getContentResolver().insert(uri, cv); 
       //styleAdapter.notifyDataSetChanged(); 
       fillData(); 
       return true; 
      case R.id.style_delete_all: 
       Uri delete_uri = Uri.parse("content://info.mariegrap.dancejournal.provider/style_table"); 
       context.getContentResolver().delete(delete_uri, null, null); 
       //styleAdapter.notifyDataSetChanged(); 
       fillData(); 
       return true; 
      default: 
       return super.onOptionsItemSelected(item); 
     } 
    } 

    protected void fillData() { 
     this.getSherlockActivity().getSupportLoaderManager().restartLoader(LOADER_ID, null, this); 
     this.getListView().setAdapter(styleAdapter); 
    } 

    protected void deleteStyle(long id) { 
     Uri uri = Uri.parse("content://info.mariegrap.dancejournal.provider/style_table/" + id); 
     this.getSherlockActivity().getContentResolver().delete(uri, null, null); 
     //styleAdapter.notifyDataSetChanged(); 
     fillData(); 
    } 

    @Override 
    public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
     String[] projection = { StyleTable.STYLE_KEY_ID, StyleTable.STYLE_KEY_NAME }; 
     return new CursorLoader(this.context, 
      DanceContentProvider.CONTENT_URI_STYLE, projection, null, null, null); 
    } 

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

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

    private void setActionModeCallback(){ 
     mActionModeCallback = new Callback() { 

      @Override 
      public boolean onCreateActionMode(ActionMode mode, Menu menu) { 
       MenuInflater inflater = mode.getMenuInflater(); 
       inflater.inflate(R.menu.style_context_menu, menu); 
       return true; 
      } 

      @Override 
      public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 
       return false; 
      } 

      @Override 
      public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 
       switch (item.getItemId()) { 
        case R.id.style_delete: 
         deleteStyle(selectedId); 
         mode.finish(); 
         return true; 

        default: 
         return false; 
       } 
      } 

      @Override 
      public void onDestroyActionMode(ActionMode mode) { 
       mActionMode = null; 
      } 
     }; 
    } 

    private void setLongClickListener(){ 
     this.getListView().setOnItemLongClickListener (new OnItemLongClickListener() { 

      public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 
       if (mActionMode != null || position == 0) { 
        return false; 
       } 
       mActionMode = getSherlockActivity().startActionMode(mActionModeCallback); 
       selectedId = id; 
       return true; 
      } 
     }); 
    } 
} 

這是自定義的CursorAdapter:

import view.StyleListItem; 
import info.mariegrap.model.Style; 
import android.content.Context; 
import android.database.Cursor; 
import android.support.v4.widget.CursorAdapter; 
import android.util.Log; 
import android.view.View; 
import android.view.ViewGroup; 

public class StyleCursorAdapter extends CursorAdapter { 

    public StyleCursorAdapter(Context context, Cursor c, int flags) { 
     super(context, c, flags); 
    } 

    @Override 
    public void bindView(View arg0, Context arg1, Cursor arg2) { 
     int id = arg2.getInt(StyleTable.STYLE_COL_ID); 
     String name = arg2.getString(StyleTable.STYLE_COL_NAME); 

     Style style = new Style(name, id); 
     StyleListItem listItem = (StyleListItem) arg0; 
     listItem.setStyle(style); 
    } 

    @Override 
    public View newView(Context arg0, Cursor arg1, ViewGroup arg2) { 
     int id = arg1.getInt(StyleTable.STYLE_COL_ID); 
     String name = arg1.getString(StyleTable.STYLE_COL_NAME); 

     Style style = new Style(name, id); 
     StyleListItem listItem = new StyleListItem(arg0, style); 
     listItem.setStyle(style); 
     Log.d("mgrap", "Adapter view: " + listItem.getStyleId()); 
     return listItem; 
    } 

} 

這裏是列表項查看:

public class StyleListItem extends LinearLayout { 

    private TextView styleView; 

    private Style style; 

    public StyleListItem(Context context, Style style) { 
     super(context); 
     LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     inflater.inflate(R.layout.style_row, this, true); 

     styleView = (TextView)findViewById(R.id.style_label); 
     Log.d("mgrap", "Style View: " + styleView); 
     setStyle(style); 
    } 

    public void setStyle(Style style) { 
     this.style = style; 
     displayStyle(this.style); 
    } 

    public Style getStyle(){ 
     return style; 
    } 

    private void displayStyle(Style style) { 
     if (style != null) { 
      styleView.setText(style.getName()); 
     } 
    } 

    public int getStyleId() { 
     return styleView.getId(); 
    } 
} 

^h ERE是列表項的佈局XML:

<?xml version="1.0" encoding="utf-8"?> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" > 

    <ImageView 
     android:id="@+id/icon" 
     android:layout_width="30dp" 
     android:layout_height="24dp" 
     android:layout_marginLeft="4dp" 
     android:layout_marginRight="8dp" 
     android:layout_marginTop="8dp" 
     android:src="@drawable/ic_launcher" > 
    </ImageView> 

    <TextView 
     android:id="@+id/style_label" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_marginTop="6dp" 
     android:lines="1" 
     android:text="@+id/TextView01" 
     android:textSize="24sp" 
     > 
    </TextView> 
</LinearLayout> 

下面是列表標題的XML佈局:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:background="@color/list_header_background_color" 
    android:layout_marginBottom="5dip" > 
    <LinearLayout 
     android:layout_height="wrap_content" 
     android:layout_width="wrap_content" 
     android:orientation="vertical" 
     android:paddingTop="5dip" 
     android:paddingLeft="10dip" 
     android:paddingBottom="13dip" 
     android:layout_centerVertical="true" 
     android:layout_alignParentLeft="true"> 
     <TextView 
     android:id="@+id/listview_header_title" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="@string/list_header_style_title" 
     android:textSize="17sp" 
     android:textStyle="bold" 
     android:textColor="@color/list_header_title_color" 
     /> 

     <TextView 
     android:id="@+id/listview_header_subtitle" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="@string/list_header_style_subtitle" 
     android:textSize="13sp" 
     android:textColor="@color/list_header_subtitle_color" 
     /> 
    </LinearLayout> 

    <ImageView 
     android:id="@+id/list_header_button" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerHorizontal="true" 
     android:layout_alignParentRight="true" 
     android:layout_marginRight="20dp" 
     android:layout_marginTop="5dp" 
     android:layout_marginBottom="13dp" 
     android:visibility="gone" 
     android:contentDescription="@string/image_desc" 
    /> 

</RelativeLayout> 

,這裏是定義樣式數據庫表中的類:

import android.database.sqlite.SQLiteDatabase; 
import android.util.Log; 

public class StyleTable { 
    /** Style table in the database. */ 
    public static final String TABLE_STYLE = "style_table"; 

    /** Style table column names and IDs for database access. */ 
    public static final String STYLE_KEY_ID = "_id"; 
    public static final int STYLE_COL_ID = 0; 

    public static final String STYLE_KEY_NAME = "name"; 
    public static final int STYLE_COL_NAME = STYLE_COL_ID + 1; 

    /** SQLite database creation statement. Auto-increments IDs of inserted 
    * styles. Style IDs are set after insertion into the database. */ 
    public static final String DATABASE_CREATE = "create table " + 
      TABLE_STYLE + " (" + 
      STYLE_KEY_ID + " integer primary key autoincrement, " + 
      STYLE_KEY_NAME + " text);"; 

    /** SQLite database table removal statement. Only used if upgrading 
    * database. */ 
    public static final String DATABASE_DROP = "drop table if exists " + 
      TABLE_STYLE; 

    /** 
    * Initializes the database. 
    * 
    * @param database 
    * The database to initialize. 
    */ 
    public static void onCreate(SQLiteDatabase database) { 
     database.execSQL(DATABASE_CREATE); 
    } 

    /** 
    * Upgrades the database to a new version. 
    * 
    * @param database 
    * The database to upgrade. 
    * @param oldVersion 
    * The old version of the database. 
    * @param newVersion 
    * The new version of the database. 
    */ 
    public static void onUpgrade(SQLiteDatabase database, int oldVersion, 
    int newVersion) 
    { 
     Log.w("mgrap", "updating database..."); 
     database.execSQL(DATABASE_DROP); 
     onCreate(database); 
    } 
} 

回答

3

很難說沒有更多的日誌記錄,但有幾件事情會跳出來:

  1. 正在直接在列表視圖中設置適配器,而不是在ListFragment上調用setAdapter。這通常會導致問題。
  2. 您正在初始化加載程序後設置列表視圖的適配器。這可能不是一個競爭條件,因爲回調可能會在您的調用完成後在主循環中調用,但我不會指望它。
+0

#1是問題所在。非常感謝!永遠不會想到這一點。 – user2593669