1

目前,我開始在Android開發,我想學習如何開發應用程序和應用良好的規則和建議,不能訪問內的ContentProvider光標數據。在某處我讀到,正確的做法是使用CursorLoader加載列表以加載視圖中異步的數據。此前,由於一個教程中,我創建了一個簡單的應用程序,顯示了SQLite數據庫表中的數據的列表,使用自定義適配器,我從SimpleCursorAdapter擴展,以顯示不同的圖標基礎上查詢的每一行的某些字段的值(光標)。我的自定義接口的代碼是下一個:安卓:使用CursorLoader

public class MarcaCursorAdapter extends SimpleCursorAdapter { 

private Context ctx; 
private Cursor cur; 

public MarcaCursorAdapter(Context context, int layout, Cursor c, 
     String[] from, int[] to) { 
    super(context, layout, c, from, to, 0); 
    this.ctx = context; 
    this.cur = c; 
    // TODO Auto-generated constructor stub 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    if(convertView == null) 
     convertView = View.inflate(ctx, R.layout.template_marcas, null); 
    View row = convertView; 

    ImageView imgRk = (ImageView)convertView.findViewById(R.id.tipoRanking); 
    //Dependiendo del ranking, cargaremos la imagen de mario o de wario 
    if(cur.getInt(3) % 2 == 0) 
     imgRk.setImageResource(R.drawable.btn1_pressed); 
    else 
     imgRk.setImageResource(R.drawable.btn1_focus); 

    return row; 
} } 

而且template_marcas.xml的內容是下一個:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:paddingLeft="10dp" 
android:background="#002EB8" 
android:paddingTop="20dp" > 

<TextView 
    android:id="@+id/nomMarca" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignParentLeft="true" 
    android:layout_alignParentTop="true" 
    android:textColor="#FFFFFF" /> 

<TextView 
    android:id="@+id/textView69" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignBottom="@+id/nomMarca" 
    android:layout_toRightOf="@+id/nomMarca" 
    android:text=" es la numero " 
    android:textColor="#FFFFFF" /> 

<TextView 
    android:id="@+id/rankMarca" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignBottom="@+id/textView69" 
    android:layout_toRightOf="@+id/textView69" 
    android:textColor="#FFFFFF" /> 

<ImageView 
    android:id="@+id/tipoRanking" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignParentRight="true" 
    android:layout_alignTop="@+id/textView69" 
    android:layout_marginRight="56dp" /></RelativeLayout> 

因此,爲了使用CursorLoader和ContentProvider的,我將我的正常類這不得不查詢表來獲得該表的遊標的方法,我從ContentProvider的延伸,並在清單文件註冊類是下一個:

public class MarcaDAO extends ContentProvider { 

private ConnHandler conn; 
SQLiteDatabase dbObj; 

@Override 
public int delete(Uri uri, String selection, String[] selectionArgs) { 
    // TODO Auto-generated method stub 
    return 0; 
} 

@Override 
public String getType(Uri uri) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public Uri insert(Uri uri, ContentValues values) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public boolean onCreate() { 
    conn = new ConnHandler(getContext()); 
    dbObj = conn.getDb(); 
    return true; 
} 

@Override 
public Cursor query(Uri uri, String[] projection, String selection, 
     String[] selectionArgs, String sortOrder) { 
    Cursor cur = dbObj.query("MARCA", projection, null, null, null, null, null); 
    return cur; 
} 

@Override 
public int update(Uri uri, ContentValues values, String selection, 
     String[] selectionArgs) { 
    // TODO Auto-generated method stub 
    return 0; 
}} 

連接,然後dbObj OBJETS AR用於管理連接,這些對象起作用。最後,我有與被覆蓋的方法實現LoaderCallbacs和活動初始化CursorLoader:

public class MarcaActivity extends Activity implements 

LoaderManager.LoaderCallbacks {

//MarcaDAO dao; 
MarcaCursorAdapter crsAdap; 

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

    final ListView lstMarcas = (ListView)findViewById(R.id.lstMarcas); 
    //Sacamos los datos de las marcas para mostrarlos en el listview 
    //dao = new MarcaDAO(this); 
    //Cursor cur = dao.getList(); 
    getLoaderManager().initLoader(0, null, this); 
    crsAdap = new MarcaCursorAdapter(this, R.layout.template_marcas, null , 
      new String[]{"hip_nombre", "hip_ranking"}, new int[]{R.id.nomMarca, R.id.rankMarca}); 
    lstMarcas.setAdapter(crsAdap); 
} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Inflate the menu; this adds items to the action bar if it is present. 
    getMenuInflater().inflate(R.menu.marca, menu); 
    return true; 
} 

@Override 
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { 
    return new CursorLoader(this, Uri.parse("content://com.example.crudapp.marcaData"), 
      new String[]{"_id", "hip_nombre", "hip_codigo", "hip_ranking"}, null, null, null); 
} 

@Override 
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) { 
    crsAdap.swapCursor(arg1); 
} 

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

但是,當我運行應用程序(4.2.2)我得到在MarcaCursorAdapter的方法getView一個NullPointerException在這一行:

if(cur.getInt(3) % 2 == 0) 

因爲光標的行值是空的,並且如果刪除該代碼,列表加載行的確切數字,但沒有值(textviews nomMarca和rankMarca是空的),所以我不知道我做錯了。以前它沒有內容提供商,沒有光標加載器,但我想開發出好的代碼,所以我改變了我的課程。

問候。

UPDATE:對了,我忘了說,如果在活動,而不是使用MarcaCursorAdapter我只是使用SimpleCursorAdapter(失去我的方法getView的定製)的列表負載沒有問題,而且顯示的數據,所以我覺得我的問題在於我編寫了我的MarcaCursorAdapter類,但我不知道錯誤是什麼。再次

問候。

回答

2

因爲光標的行值是空的,

Cursor值不爲空(或至少這不是錯誤的原因)它是cur參考是零。當你第一次初始化適配你用空Cursor這樣做(在這一點上cur爲空)。當您的裝載機,它的工作,並加載你打電話swapCursor()和適配器將開建行的數據,不幸的是你的cur參考仍將null作爲它不會神奇地與新Cursor參考更新。

對了,我忘了說,如果在活動,而不是使用 MarcaCursorAdapter我只是使用SimpleCursorAdapter(失去 定製我的方法getView的)名單負荷沒有問題 和顯示數據,

這是因爲您執行getView()方法而發生的。首先,對於基於Cursor的適配器,您希望覆蓋負責構建行的兩種方法newView()(創建實際行視圖)和bindView()(將先前構建的行視圖與光標數據綁定)。如果您只想更改該圖像資源,那麼您有兩個選擇:

  • 在適配器上使用ViewBinder(推薦)。
  • 擴展SimpleCursorAdapter並且只覆蓋它的bindView()方法:

    //... 
    @Override 
    public void bindView(View view, Context context, Cursor cursor) { 
        super.bindView(view, context, cursor); // let the default implementation populate our views 
        // change the image 
        ImageView imgRk = (ImageView)view.findViewById(R.id.tipoRanking); 
        //Dependiendo del ranking, cargaremos la imagen de mario o de wario 
        if(cursor.getInt(3) % 2 == 0) { 
         imgRk.setImageResource(R.drawable.btn1_pressed); 
        } else { 
         imgRk.setImageResource(R.drawable.btn1_focus); 
        } 
    } 
    
0

謝謝你,它的工作。好了,幾個小時來閱讀你的答案之前,我開始閱讀關於NewView的,bindView和getView,我試圖用NewView的和它的工作,在未來的道路:

@Override 
public View newView(Context context, Cursor cursor, ViewGroup parent) { 
    View view = View.inflate(ctx, R.layout.template_marcas, null); 
    ImageView imgRk = (ImageView)view.findViewById(R.id.tipoRanking); 
    //Dependiendo del ranking, cargaremos la imagen de mario o de wario 
    if(getCursor().getInt(3) % 2 == 0) 
     imgRk.setImageResource(R.drawable.btn1_pressed); 
    else 
     imgRk.setImageResource(R.drawable.btn1_focus); 

    return view; 
} 

不過,我不是太清楚關於什麼時候我必須使用newView,以及何時需要使用bindView或哪一個更適合我的應用程序。但是,如果在性能或開發意義上更好,我將搜索關於使用ViewBinder的建議。

問候。

+0

您的更改很小,所以'ViewBinder'更適合(更容易)使用。這兩種方法共同負責構建該行。如果你對其中一個的默認實現感到滿意,那麼你可以放棄實現另一個。 – Luksprog

+0

但是,重寫newView或bindView有什麼不同? 此致敬禮。 –

+1

是的,他們服務於不同的目的。一個構建行,一個綁定數據。你不想混在一起。 – Luksprog