动态显示listview的数据,同步机制

来源:互联网 发布:传奇3 网络传输异常 编辑:程序博客网 时间:2024/06/03 17:41


不知道怎么上传动图,下面这张是在动态跳出数据的时候截出来的图。下面记录一下,怎么做出灵活的动态显示listview数据的效果。


这是在动态显示的过程中截的一张效果图,接下来记录一下如何做出动态显示listview数据的效果.


涉及到的知识点包括:

1.AyncTask机制

2.synchronize同步代码块


关于AsyncTask这里不做过多讲述,不是很了解的童鞋建议先去看一下相关的使用方法。

关于synchronize同步代码块的相关知识点(简单描述):

1.每个java对象都有一个实现同步的锁,这些锁称为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

2.锁分为类锁和对象锁:修饰静态方法时为类锁,当A线程访问X类的静态方法时,B线程不能访问X类的任何被synchronize修饰的静态方法(但是可以访问未被synchronize修饰的静态方法),只能等待(处于阻塞状态)A线程执行完该同步方法后才能执行该方法。修饰普通方法或代码块时为对象锁,当A线程访问X类的一个实例对象的静态方法或代码块时,B线程不能访问同一个对象的所有被synchronize修饰的普通方法或代码块(但是可以访问未被synchronize修饰的方法或代码块),只能等待A线程执行完该同步方法或同步代码块后释放内置锁,处于阻塞状态的B线程才可开始访问。

3.类锁和对象锁不是互斥的。当A线程访问X类的同步静态方法时,B线程可以访问X类对象实例的同步方法或代码块。

待会我会说明一下为什么我们会用到synchronize这个知识点,下面我上一段关键的代码片段:

</pre><pre class="java" name="code">public class AsyncAddressBook extends AsyncTask<String, Integer, Object> {    private TextView tv_progress;    private ProgressBar progressBar;    private ContactArrayList contacts;    private AddressBookAdapter contactAdapter;    private SwipeMenuListView swipeMenuListView;    private int action = -1;    private Context context;    public AsyncAddressBook(TextView tv_progress, ProgressBar progressBar, ContactArrayList contacts, AddressBookAdapter contactAdapter, SwipeMenuListView swipeMenuListView) {        this.tv_progress = tv_progress;        this.progressBar = progressBar;        this.contacts = contacts;        this.contactAdapter = contactAdapter;        this.swipeMenuListView = swipeMenuListView;    }    public AsyncAddressBook(Context context,ContactArrayList contacts, AddressBookAdapter contactAdapter, SwipeMenuListView swipeMenuListView) {        this.contacts = contacts;        this.context=context;        this.contactAdapter = contactAdapter;        this.swipeMenuListView = swipeMenuListView;    }    /**     * 0展示全部数据  1展示与编辑框匹配的数据     *     * @param action     */    public void setAction(int action) {        this.action = action;    }    @Override    protected void onPreExecute() {        super.onPreExecute();        if (progressBar != null && tv_progress != null) {            tv_progress.setVisibility(View.VISIBLE);            tv_progress.setText("0/0");            progressBar.setVisibility(View.VISIBLE);            progressBar.setProgress(0);        }    }    @Override    protected Object doInBackground(String... params) {        switch (action) {            case 0:                //查询所有数据                selectAllContacts();                break;            case 1:                //模糊查询                selectMatchContacts(params[0]);                break;        }        return null;    }    @Override    protected void onPostExecute(Object o) {        super.onPostExecute(o);        contactAdapter.sort();        contactAdapter.notifyDataSetChanged();        if (progressBar != null && tv_progress != null) {            progressBar.setVisibility(View.GONE);            tv_progress.setVisibility(View.GONE);        }        swipeMenuListView.setSelection(0);    }    @Override    protected void onProgressUpdate(Integer... values) {        super.onProgressUpdate(values);        if (progressBar != null && tv_progress != null) {            progressBar.setProgress(values[0]);            tv_progress.setText(values[0] + "/" + progressBar.getMax());        }        contactAdapter.notifyDataSetChanged();        swipeMenuListView.setSelection(values[0]);    }    /**     * 获取数据库所有联系人     */    public void selectAllContacts() {        contacts.clear();        SQLiteDatabase sql_read = new DB_Helper(tv_progress.getContext()).getReadableDatabase();        Cursor cursor = sql_read.query(DB_Constants.AddressBook_TableName, DB_Constants.AddressBookColumns, null, null, null, null, null);        if (cursor.getCount() > 0) {            progressBar.setMax(cursor.getCount());            sql_read.beginTransaction();            while (cursor.moveToNext()) {                Contact contact = new Contact();                contact.setContact_id(cursor.getInt(cursor.getColumnIndex(DB_Constants.Contact_ID)));                contact.setContact_user_id(cursor.getInt(cursor.getColumnIndex(DB_Constants.Contact_User_ID)));                contact.setNick_name(cursor.getString(cursor.getColumnIndex(DB_Constants.Nick_Name)));                contact.setComp_name(cursor.getString(cursor.getColumnIndex(DB_Constants.Comp_Name)));                contact.setUser_image(cursor.getString(cursor.getColumnIndex(DB_Constants.User_Image)));                contact.setArea(cursor.getString(cursor.getColumnIndex(DB_Constants.Area)));                contact.setCreate_time(cursor.getString(cursor.getColumnIndex(DB_Constants.Create_Time)));                contact.setUser_role(cursor.getString(cursor.getColumnIndex(DB_Constants.User_Role)));                contacts.add(contact);                try {                    Thread.sleep(200);                } catch (InterruptedException e) {                    e.printStackTrace();                }                publishProgress(contacts.size());            }            sql_read.setTransactionSuccessful();            sql_read.endTransaction();        }        cursor.close();        sql_read.close();    }    /**     * 查询包含S的所有联系人     */    public void selectMatchContacts(String s) {        contacts.clear();        SQLiteDatabase sql_read = new DB_Helper(context).getReadableDatabase();        Cursor cursor = sql_read.query(DB_Constants.AddressBook_TableName, DB_Constants.AddressBookColumns, DB_Constants.Nick_Name + " like '%" + s + "%' ", null, null, null, null);        if (cursor.getCount() > 0) {            sql_read.beginTransaction();            while (cursor.moveToNext()) {                Contact contact = new Contact();                contact.setContact_id(cursor.getInt(cursor.getColumnIndex(DB_Constants.Contact_ID)));                contact.setContact_user_id(cursor.getInt(cursor.getColumnIndex(DB_Constants.Contact_User_ID)));                contact.setNick_name(cursor.getString(cursor.getColumnIndex(DB_Constants.Nick_Name)));                contact.setComp_name(cursor.getString(cursor.getColumnIndex(DB_Constants.Comp_Name)));                contact.setUser_image(cursor.getString(cursor.getColumnIndex(DB_Constants.User_Image)));                contact.setArea(cursor.getString(cursor.getColumnIndex(DB_Constants.Area)));                contact.setCreate_time(cursor.getString(cursor.getColumnIndex(DB_Constants.Create_Time)));                contact.setUser_role(cursor.getString(cursor.getColumnIndex(DB_Constants.User_Role)));                contacts.add(contact);                if (contacts.size() > 0) {                    publishProgress(contacts.size());                }            }            sql_read.setTransactionSuccessful();            sql_read.endTransaction();        }        cursor.close();        sql_read.close();    }}







说一下在测试过程中遇到的问题及解决办法:

问题:contactAdapter的数据源是contacs,contacts的数据改变(contacts.add(XXX))是在子线程中进行的,而listview数据的刷新(contactAdapter.notifyDataSetChanged())是在主线程中进行的。当异步任务的后台线程(简称A线程)执行完contacts.add(xxx)方法后,立即调用publishProgress(contacts.size());在主线程(简称B线程)更新进度条。这是两个不同的线程,A线程在调用publishProgress(contacts.size())后仍然会往下执行。而B线程现在正在刷新listview的数据,这个时候肯定会调用contacts.get(position)方法,而因为A线程因为继续在执行,所以这个时候很有可能A线程正在调用contacts.add(XXX)方法。此时,两个线程访问的是同一个对象,但是读到的数据却可能会不一致,所以如果上述代码中的contacts假设是一个普通的ArrayList类型,运行的时候偶尔会出现异常奔溃,奔溃原因是“在另一个线程改变了数据源,却没有即时告知adapter在主线程刷新数据”,产生的原因就是我们在adapter刷新数据时,数据源的值又变化了。

解决办法:这个时候可以考虑用同步机制了。这种情况可以用对象锁。分析可得,可能会产生异常奔溃的原因在于contacts这个数据源的add方法和get方法。所以我们用synchronize修饰add方法和get方法,这样当线程A访问add方法时,线程B不能再访问这个对象的get方法,只能等线程A执行完add方法后,线程B才能访问这个对象的get方法。这样就可以避免两个线程访问到的数据源不一致的问题。下面上一段自定义的ArrayList类.

<pre class="java" name="code">public class ContactArrayList extends ArrayList<Contact> {    @Override    public void add(int index, Contact object) {        //对象锁,this指当前对象        synchronized (this) {            //被上锁的代码块            super.add(index, object);        }    }    @Override    public Contact get(int index) {        synchronized (this) {            return super.get(index);        }    }}


现在就可以实现灵活的数据刷新啦!~synchronize要谨慎使用,因为它是阻塞线程的,会消耗性能。

转载请注明出处!

                                                                                                                                                            

                                                                                                                                                                                                           与    君    共   勉   

0 0