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