安卓 ListView 刷新

7
我有一个Listview,它从sqlite数据库中提取和显示数据。数据库的第一列中的数据显示在Listview中,单击后,会启动一个Activity,显示与第一列相关联的其余列。当编辑数据时,ListView需要更新以反映这一点,但除非重新启动应用程序,否则不会显示更新。
我尝试在我的onResume()方法中调用notifyDataSetChanged()startActivityForResult(),但没有成功。在当前代码中,我应该使用什么方法来更新ListView
我了解到可以使用SimpleCursorAdapter,我已经尝试实现该代码,但没有成功。作为一个新手,我需要实际的代码才能理解需要完成的任务。
public class LoginList extends Activity implements OnClickListener, OnItemClickListener {
    private ListView loginList;
    private Button webLogin;

    private ListAdapter loginListAdapter;

    private ArrayList<LoginDetails> loginArrayList;

    @Override 
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.login_listview);
        loginList = (ListView)
        findViewById(R.id.loginlist);
        loginList.setOnItemClickListener(this);

        webLogin = (Button)
        findViewById(R.id.button3);
        webLogin.setOnClickListener(this);

        loginArrayList = new ArrayList<LoginDetails>();
        loginListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, populateList());
        loginList.setAdapter(loginListAdapter);
    }

    @Override
    public void onClick (View v) {
        Intent webLoginIntent = new Intent (this, LoginPlusActivity.class);
        startActivity(webLoginIntent);
    }

    public List<String> populateList () {
        List<String> webNameList = new ArrayList<String>();

        dataStore openHelperClass = new dataStore (this);

        SQLiteDatabase sqliteDatabase = openHelperClass.getReadableDatabase();

        Cursor cursor = sqliteDatabase.query(dataStore.TABLE_NAME_INFOTABLE, null, null, null, null, null, dataStore.COLUMN_NAME_SITE, null);

        startManagingCursor(cursor);

        while (cursor.moveToNext()) {
            String sName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_SITE));
            String wUrl = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_ADDRESS));
            String uName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_USERNAME));
            String pWord = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_PASSWORD));
            String lNotes = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_NOTES));

            LoginDetails lpDetails = new LoginDetails();

            lpDetails.setsName(sName);
            lpDetails.setwUrl(wUrl);
            lpDetails.setuName(uName);
            lpDetails.setpWord(pWord);
            lpDetails.setlNotes(lNotes);

            loginArrayList.add(lpDetails);
            webNameList.add(sName);
        }

        sqliteDatabase.close();
        return webNameList;
    }


    @Override
    protected void onResume() {
        super.onResume();

        loginListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, populateList());
        loginList.setAdapter(loginListAdapter);  

    }


@Override
    public void onItemClick(AdapterView<?> arg0 , View arg1, int arg2, long arg3) {
        Toast.makeText(getApplicationContext(), "Selected ID :" + arg2, Toast.LENGTH_SHORT).show();

        Intent updateDeleteLoginInfo = new Intent (this, UpdateDeleteLoginList.class);
        LoginDetails clickedObject = loginArrayList.get(arg2);

        Bundle loginBundle = new Bundle();
        loginBundle.putString("clickedWebSite",clickedObject.getsName());
        loginBundle.putString("clickedWebAddress",clickedObject.getwUrl());
        loginBundle.putString("clickedUserName",clickedObject.getuName());
        loginBundle.putString("clickedPassWord",clickedObject.getpWord());
        loginBundle.putString("clickedNotes",clickedObject.getlNotes());

        updateDeleteLoginInfo.putExtras(loginBundle);

        startActivityForResult(updateDeleteLoginInfo, 0);   
    }
}

1
你试过使用SimpleCursorAdapter而不是ArrayAdapter吗? - Glenn
嗯,你的onResume中的代码没有问题这一事实意味着你在UpdateDeleteLoginList中没有正确地编辑数据库。当然,为了正确性和性能,你可能应该使用游标适配器;不过,我认为这仍然是一个选择的问题。 - Sherif elKhatib
7个回答

5

编辑

private ArrayList<LoginDetails> loginArrayList = new ArrayList<LoginDetails>();;

@Override 
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.login_listview);
    loginList = (ListView)
    findViewById(R.id.loginlist);
    loginList.setOnItemClickListener(this);

    webLogin = (Button)
    findViewById(R.id.button3);
    webLogin.setOnClickListener(this);


    loginListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,loginArrayList );
    loginList.setAdapter(loginListAdapter);
    populateList();
}

@Override
public void onClick (View v) {
    Intent webLoginIntent = new Intent (this, LoginPlusActivity.class);
    startActivity(webLoginIntent);
}

public void populateList () {
    loginListAdapter.clear();
    loginArrayList.clear();
    dataStore openHelperClass = new dataStore (this);

    SQLiteDatabase sqliteDatabase = openHelperClass.getReadableDatabase();

    Cursor cursor = sqliteDatabase.query(dataStore.TABLE_NAME_INFOTABLE, null, null, null, null, null, dataStore.COLUMN_NAME_SITE, null);

    startManagingCursor(cursor);

    while (cursor.moveToNext()) {
        String sName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_SITE));
        String wUrl = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_ADDRESS));
        String uName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_USERNAME));
        String pWord = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_PASSWORD));
        String lNotes = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_NOTES));

        LoginDetails lpDetails = new LoginDetails();

        lpDetails.setsName(sName);
        lpDetails.setwUrl(wUrl);
        lpDetails.setuName(uName);
        lpDetails.setpWord(pWord);
        lpDetails.setlNotes(lNotes);

        loginArrayList.add(lpDetails);
        webNameList.add(sName);
    }
    loginListAdapter.notifyDatasetChanged();
    sqliteDatabase.close();
}

你正在失去对列表视图的引用,这就是为什么你的列表没有更新的原因...

在你的代码中进行以下修改: 1. 在声明时(全局变量)初始化你的ArrayList。

ArrayList loginArrayList = new ArrayList<LoginDetails>();
  1. 在 onCreate() 中可以直接将列表分配给适配器。

    loginListAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1, loginArrayList);

  2. 在 onCreate() 中调用 populateList() 方法。

  3. populateList() 方法中,不要将数据添加到新的列表中,而是添加到与适配器相关联的现有列表中,即 loginArrayList

如果列表是全新的,请在 populateList() 方法中调用 adapter.clear()loginArrayList.clear(),然后再将数据添加到 loginArrayList 中。添加完数据后,调用 adapter.notifyDataSetChanged() 方法。

这样应该就可以了...


你能提供第二步和第三步的示例吗? - user1165694
我已经对你的代码进行了一些更改,请查看... 我已经用我的数据库尝试了相同的代码,它完美地运行着。 - Pragnani
1
关于 adapter.notifyDataSetChanged() 的一个小语法提示:如果您无法找到适配器,请考虑使用 ((BaseAdapter) getListView().getAdapter()).notifyDataSetChanged() - abriggs

5
这正是Loader的用武之地。建议您创建一个SimpleCursorAdapter将数据库绑定到UI(在此例中为ListView),再创建一个ContentProvider与数据库进行交互,以及一个CursorLoader用于监测数据库变化并在必要时更新UI。通过更新适配器,Loader将处理所有数据库更改并更新您的ListView。虽然一开始似乎需要大量工作,但一旦配置完成,它就非常强大,并且能够在整个Android生命周期内运行。
以下教程应该会有所帮助:

0
这是我的示例代码,用于编辑每一行以及列表视图的数据库,希望能对您有所帮助。
首先创建一个名为 "ListAdapterItem.java" 的适配器。
     import java.util.ArrayList;
     import java.util.HashMap;

     import android.content.Context;
     import android.view.LayoutInflater;
     import android.view.View;
     import android.view.ViewGroup;
     import android.widget.BaseAdapter;
     import android.widget.RelativeLayout;
     import android.widget.TextView;

     public class ListAdapterItem extends BaseAdapter {

private ArrayList<HashMap<String, Object>> list;
private Context context;
private RelativeLayout ll;
// used to keep selected position in ListView
private int selectedPos = -1; // init value for not-selected
private TextView label,label_id;
String name,id;

public ListAdapterItem (Context context,ArrayList<HashMap<String, Object>> list) {
    this.list = list;
    this.context = context;
}
public void setSelectedPosition(int pos) {
    selectedPos = pos;
    // inform the view of this change
    notifyDataSetChanged();
}
public int getSelectedPosition() {
    return selectedPos;
}
public View getView(int position, View convertView, ViewGroup parent) {
    ll = (RelativeLayout) LayoutInflater.from(this.context).inflate(R.layout.data_list_item, null);
    // get text view
    label = (TextView) ll.findViewById(R.id.txtview_country_name);
    label_id=(TextView) ll.findViewById(R.id.txtview_id);

    id=list.get(position).get("Id").toString();
    name = list.get(position).get("Name").toString();

    label.setText(name);
    label_id.setText(id);
    return ll;
}
public int getCount() {
    return this.list.size();
}
public Object getItem(int position) {
    return position;
}
public long getItemId(int position) {
    return position;
}
}

这是我的data_list_item

                            <?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="fill_parent"
                android:orientation="vertical"
                android:padding="5dp">
                 <TextView
                    android:id="@+id/txtview_id"
                    android:layout_width="wrap_content"
                    android:layout_height="fill_parent"
                    android:layout_margin="8dp"
                    android:layout_marginRight="2dp"
                    android:textColor="@android:color/black"
                    android:textSize="22dp"
                    android:visibility="invisible"/>
                <TextView
                    android:id="@+id/txtview_country_name"
                    android:layout_width="wrap_content"
                    android:layout_height="fill_parent"
                    android:layout_margin="8dp"
                    android:layout_marginRight="2dp"
                    android:textColor="@android:color/black"
                    android:textSize="22dp" />


            </RelativeLayout>

而主类是“Main.java”

                    public class Main extends Activity implements OnClickListener {

                    String name;
                    SQLiteDatabase db;
                    Cursor cursor;

                    private ProgressDialog progressDialog;

                    public ListAdapterItem list_adapter;
                    private ArrayList<HashMap<String, Object>> lst_data;
                    private HashMap<String, Object> hm;
                    private ListView listview;
                    private String list_id;
                    private int counter_id,selectedPosition;
                    private View selectedView;

                    public void onCreate(Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);
                        setContentView(R.layout.main_layout);
                        lst_data = new ArrayList<HashMap<String, Object>>();
                        listview = (ListView) findViewById(R.id.list);
                        new FetchDB().execute();
                        }
                    private class FetchDB extends AsyncTask<String, Void,ArrayList<HashMap<String, Object>>> {
                        protected void onPreExecute() {
                            progressDialog = ProgressDialog.show(Main.this,"Fetching Data", "Loading,Please wait...", true);
                        }

                        protected ArrayList<HashMap<String, Object>> doInBackground(String... lstStrings)throws IllegalArgumentException {
                            try {
                                db = openOrCreateDatabase("MyDB", MODE_PRIVATE, null);
                                cursor = db.rawQuery("SELECT * FROM person WHERE Id <> ''",null);

                                if (cursor != null && cursor.getCount() > 0) {

                                    if (cursor.moveToFirst()) {
                                        do {
                                            hm = new HashMap<String, Object>();
                                            hm.put("Id",cursor.getInt(cursor.getColumnIndex("Id")));
                                            hm.put("Name", cursor.getString(cursor.getColumnIndex("Name")));
                                            lst_data.add(hm);

                                        } while (cursor.moveToNext());
                                    }// end of cursor.moveToFirst()
                                    cursor.close();
                                }

                            } catch (Exception e) {
                                e.getMessage();
                            }
                            db.close();// database close
                            return lst_data;
                        }// end of doInbackgournd

                        @Override
                        protected void onPostExecute(ArrayList<HashMap<String, Object>> result) {
                            progressDialog.dismiss();
                            list_adapter = new ListAdapterItem(Main.this,result);
                            listview.setAdapter(list_adapter);
                            listview.setOnItemClickListener(new OnItemClickListener() {

                                public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
                                    list_adapter.setSelectedPosition(arg2);
                                    selectedPosition = arg2;
                                    selectedView = arg1;
                                    list_id=((TextView) selectedView.findViewById(R.id.txtview_id)).getText().toString();
                                }

                            });
                        }
                    }// end of FetchDBTask
                        private class SaveTask extends AsyncTask<String, Void,ArrayList<HashMap<String, Object>>> {
                        @Override
                        protected void onPreExecute() {
                            progressDialog = ProgressDialog.show(Main.this,"Saving Data", "Loading,Please wait...", true);
                        }
                        protected ArrayList<HashMap<String, Object>> doInBackground(String... arg0)throws IllegalArgumentException {
                            counter_id++;
                            name = editext_name.getText().toString();

                            hm = new HashMap<String, Object>();
                            hm.put("Id",counter_id);
                            hm.put("Name",name);
                            lst_data.add(hm);
                            saveDB();
                            return lst_data;
                        }// end of doInbackgournd

                        protected void onPostExecute(ArrayList<HashMap<String, Object>> result) {
                            progressDialog.dismiss();
                            list_adapter = new ListAdapterItem(Main.this,result);
                            listview.setAdapter(list_adapter);
                            listview.setOnItemClickListener(new OnItemClickListener() {
                                public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
                                    list_adapter.setSelectedPosition(arg2);
                                    selectedPosition = arg2;
                                    selectedView = arg1;
                                    list_id=((TextView) selectedView.findViewById(R.id.txtview_id)).getText().toString();

                                }
                            });

                        }

                    }// end of saveTask
                    public void saveDB(){
                        String sql;
                        db = openOrCreateDatabase("MyDB", MODE_PRIVATE, null);
                        // create table if not e exist
                        db.execSQL("CREATE TABLE IF NOT EXISTS person(Name VARCHAR ,Id INT(3));");
                        sql = "SELECT * FROM person WHERE Id="+list_id; //selected or click row in list item
                        Cursor cursor = db.rawQuery(sql, null);

                        if (cursor.moveToFirst()) {
                            String sqlUpdate = "UPDATE person SET Name=? WHERE Id="+db_id;
                            db.execSQL(sqlUpdate, new Object[] {db_name});
                            cursor.close();
                            db.close();// database close
                        } else {// empty insert
                            String sqlInsert = "INSERT INTO person VALUES (?,"+null+")";
                            db.execSQL(sqlInsert, new Object[] {db_name,db_address,db_phone,db_email,db_license,db_comments,db_company,db_policy,db_phone_insurance,vehc_year,vehc_make,vehc_model,vehc_license,vehc_vinnum,vehc_color,db_position });
                            cursor.close();
                            db.close();// database close

                        }
                    }
                    //Edit by row
                    private class EditData extends AsyncTask<String, Void,ArrayList<HashMap<String, Object>>> {
                        protected void onPreExecute() {
                            progressDialog = ProgressDialog.show(Main.this,"Saving Data", "Loading Please wait...", true);
                        }
                        protected ArrayList<HashMap<String, Object>> doInBackground(String... id)throws IllegalArgumentException {
                            name = editext_name.getText().toString();


                            hm = new HashMap<String, Object>();
                            hm.put("Id",counter_id);
                            hm.put("Name",name);

                            lst_data.set(selectedPosition, hm); //specific row update
                            list_id=Integer.parseInt(edit_counter);
                            saveDB();

                            return lst_data;
                        }// end of doInbackgournd
                        protected void onPostExecute(ArrayList<HashMap<String, Object>> result) {
                            progressDialog.dismiss();
                            list_adapter = new ListAdapterItem(Main.this,result);
                            listview.setAdapter(list_adapter);

                        }
                    }
                }

还有主要的 main_layout.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="match_parent"                    
                android:orientation="vertical" >

                <ListView
                    android:id="@+id/list"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:background="@android:color/transparent"
                    android:cacheColorHint="#00000000"
                    android:dividerHeight="2dp"
                    android:paddingTop="8dp"
                    android:transcriptMode="normal" />

            </LinearLayout>

在ListView中的每个列表行中指定您的ID,希望这回答了您的问题。

我目前能够编辑我的数据,但问题是在完成编辑后如何使我的列表视图刷新而无需关闭和重新启动应用程序。 - user1165694
你是指所有行还是你单击并编辑的每一行?对于我来说,我正在使用 hashmap 自动替换 UI 视图中的每个条目。 - Cjames

0
我认为在你的populate()方法中,在while块之前,你应该调用loginListAdapter.notifyDataSetChanged()和loginListAdapter.clear()。这将清除适配器并通知它有新的数据列表。
代码块应该像这样:
 loginListAdapter.notifyDataSetChanged();
 loginListAdapter.clear();
 while (cursor.moveToNext()) {
        String sName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_SITE));
        String wUrl = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_ADDRESS));
        String uName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_USERNAME));
        String pWord = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_PASSWORD));
        String lNotes = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_NOTES));

        LoginDetails lpDetails = new LoginDetails();

        lpDetails.setsName(sName);
        lpDetails.setwUrl(wUrl);
        lpDetails.setuName(uName);
        lpDetails.setpWord(pWord);
        lpDetails.setlNotes(lNotes);

        loginArrayList.add(lpDetails);
        webNameList.add(sName);
    }

我刚刚编辑了一下,因为你调用notify和clear的顺序不正确。在我的经验中,清除操作必须在通知之后进行,否则适配器将无法重新绘制列表。


在我添加了您推荐的更改后,我收到了以下错误: - user1165694
方法 notifyDataSetChanged() 在类型 ListAdapter 中未定义,方法 clear() 在类型 ListAdapter 中未定义 - user1165694
你的ListAdapter长这样吗:public class ListAdapter extends ArrayAdapter<?> { - MonkeyDroid

0

尝试这段代码:

在公共区域添加变量:List<String> arrayList = new ArrayList<String>();

并在onCreate()中添加以下内容:

    arrayList = populateList();

//然后在适配器中像这样添加变量

loginListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, arrayList );

在 onResume() 函数中的这段代码:

@Override
protected void onResume() {
    super.onResume();

    loginArrayList.clear();

    arrayList.clear();

    arrayList = populateList();

    loginListAdapter.notifyDataSetChanged()

}

如果你解决了,请告诉我们。


0

我的建议。

  1. 不要使用循环来加载列表。如果它是一个简单的字符串列表,请尝试使用 SimpleCursorAdapter,这将使您的应用程序更快,代码更短。
  2. 一旦您更新了数据库,那么您需要查询数据库以获取 Cursor,并使用 .swapCursor(newCursor) 将其传递给 Adapter。这将在保持滚动位置的同时更新您的列表。

0

如果您正在手动创建适配器的后备数据(在这种情况下,您正在使用ArrayAdapter - 在许多情况下完全可接受),那么当数据库更改时,您需要重新查询数据库,重新创建数据集,更改适配器的后备数据集,并告诉列表数据集已更改。

一种实现此目的的方法可能是广播一个意图,让您的活动知道执行上述步骤(通过使用BroadcastReceiver捕获该意图)。


听起来很合理。有没有提到这个过程的例子?那会非常有帮助。 - user1165694

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接