2015-07-09 170 views
2

所以我的应用程序使用本地SQLite数据库通过ContentProvider的 在它的Android notifyDataSetChanged的mainActivity我有一个ListView从上面的数据库显示表的内容。从自定义适配器

我使用自定义适配器来显示列表视图。每个项目都有一个按钮(自定义)布局,当按下时,会显示一个自定义对话框,在该表格中插入新记录,然后该对话框被取消。 为了实现这种行为,我在customAdapter中放置了按钮点击处理程序。 我希望能够在插入完成后刷新listView(因此当对话被解除时)

我该怎么做到这一点? 我应该可能需要从定制适配器内部以某种方式调用notifyDataSetChanged,但是我不能。

总之,我的自定义适配器是这样的:

public class DisplayStuffAdapter extends BaseAdapter { 
    private Context mContext; 
    private ArrayList<String> id; 
    private ArrayList<String> iduser; 
    private ArrayList<String> product; 


    public DisplayStuffAdapter(Context c){ 
     this.mContext = c; 
    } 

    public DisplayStuffAdapter(Context c, ArrayList<String> id, ArrayList<String> userid, ArrayList<String> product) { 
     this.mContext = c; 
     this.id = id; 
     this.userid = userid; 
     this.product = product; 
    } 

public int getCount() { 
     return id.size(); 
    } 

    public Object getItem(int position) { 
     return null; 
    } 

    public long getItemId(int position) { 
     return 0; 
    } 

    public class Holder { 
     TextView txt_id; 
     TextView txt_userid; 
     TextView txt_prod; 
    } 


    public View getView(int pos, View child, ViewGroup parent) { 
     Holder mHolder; 
     LayoutInflater layoutInflater; 
     if (child == null) { 
      layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      child = layoutInflater.inflate(R.layout.myitem, null); 
      mHolder = new Holder(); 
      mHolder.txt_id = (TextView) child.findViewById(R.id.tv_MkId); 
      mHolder.txt_userid = (TextView) child.findViewById(R.id.tv_MkUserId); 
      mHolder.txt_prod = (TextView) child.findViewById(R.id.tv_MkProduct); 
      child.setTag(mHolder); 
     } else { 
      mHolder = (Holder) child.getTag(); 
     } 
     mHolder.txt_id.setText(id.get(pos)); 
     mHolder.txt_userid.setText(userid.get(pos)); 
     mHolder.txt_prod.setText(product.get(pos)); 

    Button bt = (Button) child.findViewById(R.id.itemButton); 
     bt.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       LayoutInflater li = LayoutInflater.from(mContext); 
       final View promptsView = li.inflate(R.layout.bid_dialog, null); 
       AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mContext); 
       alertDialogBuilder.setView(promptsView); 
alertDialogBuilder.setMessage("Input data") 
       .setIcon(R.drawable.add_red_24) 
       .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 
           @Override 
           public void onClick(DialogInterface dialogInterface, int i) { 
            dialogInterface.dismiss(); 
           } 
          }) 
       .setPositiveButton("Add new record", new DialogInterface.OnClickListener() { 
        @Override 
        public void onClick(DialogInterface dialogInterface, int i) { 
       ContentValues values = new ContentValues(); 
       values.put(MyProvider.TCOL_ID, myid); 
       values.put(MyProvider.TCOL_OTHERID, Integer.toString(getActiveUserId())); 
       Uri uri = mContext.getContentResolver().insert(MyProvider.CONTENT_URI_TABLE, values); 
       values = new ContentValues(); 
       dialogInterface.dismiss(); 
         } 
        } 
        } 
       }); 

       // create alert dialog 
       final AlertDialog alertDialog = alertDialogBuilder.create(); 
       // show it 
       alertDialog.show(); 
       alertDialog.setCanceledOnTouchOutside(false); 
.... 
     } 
    }); 
.... 

我从代码中删除某些部分,以使其更具可读性。 现在,在我的MainActivity,我设置适配器这样的:

public class MainActivity extends Activity{ 
    private ArrayList<String> id = new ArrayList<String>(); 
    private ArrayList<String> userid = new ArrayList<String>(); 
    private ArrayList<String> product = new ArrayList<String>(); 
... 
@Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     fillListView(); 
    } 
... 

private void fillListView(){ 
     id.clear(); 
     userid.clear(); 
     product.clear(); 

     String[] col = {MyProvider.TCOL_ID_ID, MyProvider.TCOL_USERID, MyProvider.TCOL_PROD}; 
     String where = "done = 1"; 
     Cursor mCursor = MainActivity.this.getContentResolver().query(MyProvider.CONTENT_URI_TABLE, col, where, null, MyProvider.TCOL_DATE + " desc"); 
     if (mCursor != null) { 
      if (mCursor.moveToFirst()) { 
       do { 
        id.add(Integer.toString(mCursor.getInt(0))); 
        userid.add(Integer.toString(mCursor.getInt(1))); 
        product.add(mCursor.getString(2)); 
       } while (mCursor.moveToNext()); 
      } 
     } 

     DisplayStuffAdapter disadpt = new DisplayStuffAdapter(MainActivity.this,id,userid,product); 
     disadpt.notifyDataSetChanged(); 
     ListView lv = (ListView) findViewById(R.id.mylistView); 
     lv.setAdapter(disadpt); 
    } 

所以,当我添加一个新的记录使用上述customdialog表这一切的伟大工程,除了...对话框关闭,并且列表视图保持不变。

如何刷新listView?

+0

为什么你不能在DisplayStuffAdapter中调用notifyDataSetChanged?即使在anonyoums类,你可以这样做:DisplayStuffAdapter.this.notifyDataSetChanged() – Lester

+0

莱斯特:我已经尝试过,但列表视图不会刷新 – user1137313

+0

马克,你的解决方案听起来很有趣,但是,我对这种新的,所以我宁愿看到一些代码而不是理论。代码总是让我明白更好的想法 – user1137313

回答

0
public class DisplayStuffAdapter extends BaseAdapter { 
    private Context mContext; 
    private ArrayList<String> id; 
    private ArrayList<String> iduser; 
    private ArrayList<String> product; 

    public DisplayStuffAdapter(Context c){ 
     this.mContext = c; 
    } 

    public void loadData(){ 
     id.clear(); 
     userid.clear(); 
     product.clear(); 

     String[] col = {MyProvider.TCOL_ID_ID, MyProvider.TCOL_USERID, MyProvider.TCOL_PROD}; 
     String where = "done = 1"; 
     Cursor mCursor = MainActivity.this.getContentResolver().query(MyProvider.CONTENT_URI_TABLE, col, where, null, MyProvider.TCOL_DATE + " desc"); 
     if (mCursor != null) { 
      if (mCursor.moveToFirst()) { 
       do { 
        id.add(Integer.toString(mCursor.getInt(0))); 
        userid.add(Integer.toString(mCursor.getInt(1))); 
        product.add(mCursor.getString(2)); 
       } while (mCursor.moveToNext()); 
      } 
     } 
     notifyDataSetChanged(); 
    } 
... 
} 

public class MainActivity extends Activity{ 
    private DisplayStuffAdapter disadpt = null; 

    ContentObserver displayStuffObserver = new ContentObserver(new Handler()){ 
     @Override 
     public void onChange(boolean selfChange) { 
      if(disadpt != null) { 
       disadpt.loadData(); 
      } 
     }  
    } 

    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     disadpt = new DisplayStuffAdapter(this); 
     ListView lv = (ListView) findViewById(R.id.mylistView); 
     lv.setAdapter(disadpt); 
     disadpt.loadData(); 
      getContentResolver().registerContentObserver(MyProvider.CONTENT_URI_TABLE,true, displayStuffObserver); 
    } 
} 

不要忘记注销您的内容观察者

+0

这将是如此简单......但没有任何变化。我还在setAdapter之后放置了notifyDatasetChanged,结果相同... listView不刷新 – user1137313

+0

对不起...我完全错过了fillCreate()在onCreate中被调用的事实。每次在内容提供者中修改或插入记录时,都必须重新查询内容解析器。请在DisplayStuffAdapter中移动fillListView(),并在从内容解析器加载列表后调用notifyDataSetChanged()。另外,在onClick中,插入记录后,调用fillListView()。 – yfranz

+0

另一种方法是上面Mimmo Grottoli建议的方法。使用ContentObserver并在onChange()中调用fillListView()和notifyDataSetChanged() – yfranz

0

一般情况下,当你从数据库中查询数据时,你应该使用ContentProviderCursorLoader。您可以配置您的内容提供者,以便在使用ContentResolver notifyChange()方法时在某些数据更改时自动通知加载器。在你的ContentProvider实现中调用这个方法(例如在插入之后)。这是您可以使用的适配器的示例(但您也可以使用SimpleCursorAdapter提供视图绑定器)。

public class CustomCursorAdapter extends CursorAdapter { 

private LayoutInflater mInflater; 

public CustomCursorAdapter(Context context, Cursor c, int flags) { 
    super(context, c, flags); 
    mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
} 

@Override 
public void bindView(View view, Context context, Cursor cursor) { 

    if(cursor.getPosition()%2==1) { 
     view.setBackgroundColor(context.getResources().getColor(R.color.background_odd)); 
    } 
    else { 
     view.setBackgroundColor(context.getResources().getColor(R.color.background_even)); 
    } 
    TextView content = (TextView) view.findViewById(R.id.row_content); 
    content.setText(cursor.getString(cursor.getColumnIndex(Table.CONTENT))); 
} 

@Override 
public View newView(Context context, Cursor cursor, ViewGroup parent) { 
    return mInflater.inflate(R.layout.listitem, parent, false); 
} 

} 
+0

请您详细说明一下代码吗? – user1137313

+0

对于ContentProvider,请查看samples /.../ connectivity/BasicSyncAdapter/Application/src/main/java/com/example/android/basicsyncadapter/provider/FeedProvider.java。请注意,在每个更改某些数据的方法的最后,都会调用notifyChange()。通过这种方式,如果您有一个正确配置的加载器,加载器将自动重新加载数据(onLoadFinished会再次被调用),您可以替换适配器中的数据或创建一个新的数据。 –

+0

您的解决方案是通用的,我需要更接近我的方法的解决方案。本教程适用于SimpleCursorAdapter,不是自定义的。我已经在使用ContentProvider(正如我在问题中所解释的)。我感兴趣的是如何使用自定义BaseAdapter使用Loader以便能够刷新我的ListView – user1137313

0

首先,我不明白为什么你要发送三个不同的阵列列表到适配器。您可以简单地创建一个模态类,其中包含您在适配器中所需的所有字段。考虑到当前的情况下它会是这样的

public class ModalClass { 

private String id = ""; 
private String userId = ""; 
private String product = ""; 

public String getId() { 
    return id; 
} 

public void setId(String id) { 
    this.id = id; 
} 

public String getUserId() { 
    return userId; 
} 

public void setUserId(String userId) { 
    this.userId = userId; 
} 

public String getProduct() { 
    return product; 
} 

public void setProduct(String product) { 
    this.product = product; 
} 
} 

这是你与getter和setter模式类。现在,所有你需要做的就是你必须做出这个模式类的ArrayList这样

List<ModalClass> modalClassList=new ArrayList<ModalClass>(); 

,你必须将所有想要通过使用模式在此ArrayList要在列表中显示的数据class setter功能。像这样

if (mCursor != null) { 
     if (mCursor.moveToFirst()) { 
      do { 
        ModalClass modalClass=new ModalClass(); 
        modalClass.setId(Integer.toString(mCursor.getInt(0))); 
        modalClass.setUserId(Integer.toString(mCursor.getInt(1))); 
        modalClass.setProduct(mCursor.getString(2)); 
        modalClassList.add(modalClass); 
      } while (mCursor.moveToNext()); 
     } 
    } 

,现在你有你的ArrayList准备好了,这样你就可以将其设置为你的ListView这样

ListView lv = (ListView) findViewById(R.id.mylistView); 
DisplayStuffAdapter disadpt = new DisplayStuffAdapter(MainActivity.this,modalClassList); 
lv.setAdapter(disadpt); 

,因此,您必须修改您的适配器的构造,我想你可以做你自己。

另外如何在你的适配器中设置值,你可以使用你的模态类getter方法。

ModalClass modalClass=modalClassList.get(pos); 
    mHolder.txt_id.setText(modalClass.getId()); 
    mHolder.txt_userid.setText(modalClass.getUserId()); 
    mHolder.txt_prod.setText(modalClass.getProduct()); 

现在,当你想在你的适配器插入新行,你要简单地创建ModalClass的对象,并设置所有在新的价值观就像我们在MainActivity类别做了,最后补充一点,到你的modalClassList后跟notifyDataSetChanged();

ModalClass modalClass=new ModalClass(); 
    modalClass.setId(yourNewInsertedRowId); 
    modalClass.setUserId(yourNewInsertedRowUserId); 
    modalClass.setProduct(yourNewInsertedRowProduct); 
    modalClassList.add(modalClass); 
    notifyDataSetChanged(); 

而这一次您的名单将被通知肯定。欢呼声:)