2015-07-09 207 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(); 

而這一次您的名單將被通知肯定。歡呼聲:)