如何使用动态数据实时更新Android ListView?

如何使用动态数据实时更新Android ListView?,android,performance,listview,background,redraw,Android,Performance,Listview,Background,Redraw,我有一个后台线程加载数据,我想在Android ListView中显示。数据变化非常频繁(即每秒1-2次)。有时数据集中的行数也会发生变化(但肯定不会像单元格中的数据变化那样频繁) 据我所知,有两种方法可以更新单元格中的数据: 让后台线程通知UI线程新数据已准备就绪,然后UI线程可以调用BaseAdapter.notifyDataSetChanged()。然而,我在不止一个地方读到过,如果经常调用该方法,它会很慢,因为ListView必须重新构造其所有子视图 如果数据集计数没有更改,我可能会找到

我有一个后台线程加载数据,我想在Android ListView中显示。数据变化非常频繁(即每秒1-2次)。有时数据集中的行数也会发生变化(但肯定不会像单元格中的数据变化那样频繁)

据我所知,有两种方法可以更新单元格中的数据:

  • 让后台线程通知UI线程新数据已准备就绪,然后UI线程可以调用BaseAdapter.notifyDataSetChanged()。然而,我在不止一个地方读到过,如果经常调用该方法,它会很慢,因为ListView必须重新构造其所有子视图

  • 如果数据集计数没有更改,我可能会找到与更改的数据关联的所有可见ListView单元格,并在不调用notifyDataSetChanged()的情况下手动更新这些值。这可能会起作用,但我认为不幸的是,当列表适配器应该在我通知它时为我处理更新通知和机制时,我必须手动更新视图。如果数据集计数随时间变化(即,不仅ListView中每个单元格内的数据发生变化,而且ListView中的单元格总数可能会根据提供实时数据的后台线程而增加或减少),则此方法也不起作用


  • 我当然会感谢其他实现此场景的人的想法,以及他们如何优化代码的简单性和最重要的性能。

    我曾经使用
    notifyDataSetChanged()
    实现过类似代码beolow的过滤器,并且没有任何问题

    我还手动修改了移动列表的视图。两者都运作良好。在某些情况下,我倾向于手动修改数据,因为它速度更快,而且不会影响整个列表

    无论如何,当视图需要在屏幕上显示时,视图会在移动中创建,当视图离开屏幕时,视图会被删除。因此,如果您修改用于创建视图的数据,如果用户滚动ListView并将视图移出屏幕,理论上,当视图再次进入屏幕时,将使用新数据创建视图

    我建议您尝试下面的代码,以了解
    notifyDataSetChanged()
    是如何工作的,并确定它是否适合您

    public class ListText extends Activity {
    
    
        private ListView lv1;
        private Followed followedFriends[];
        ListView lst;
        EditText edt;
        FollowedFilterableAdapter arrad;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            lv1=(ListView)findViewById(R.id.listView1);
            edt = (EditText) findViewById(R.id.editText1);
    
            followedFriends = new Followed[10];
            followedFriends[0] = new Followed("Alan Walder", "0123456789", "1");
            followedFriends[1] = new Followed("Alberto Levi", "123456789", "1");
            followedFriends[2] = new Followed("David Rodan", "23456789", "1");
            followedFriends[3] = new Followed("David Stern", "3456789", "1");
            followedFriends[4] = new Followed("Elias Jawa", "456789", "1");
            followedFriends[5] = new Followed("Elian Moreno", "56789", "1");
            followedFriends[6] = new Followed("Jonathan Rodan", "6789", "1");
            followedFriends[7] = new Followed("Klara Rodan", "789", "1");
            followedFriends[8] = new Followed("Willy Rosales", "89", "1");
            followedFriends[9] = new Followed("ZZZ ZZZ", "9", "1");
    
    
            arrad =  new FollowedFilterableAdapter(followedFriends);
            lv1.setAdapter(arrad);
    
            addTextChangeList();
        }
    
        private void addTextChangeList()
        {
            edt.addTextChangedListener(new TextWatcher()
            {
    
    
                public void onTextChanged( CharSequence arg0, int arg1, int arg2, int arg3)
                {
                    // TODO Auto-generated method stub
    
                }
    
                public void beforeTextChanged( CharSequence arg0, int arg1, int arg2, int arg3)
                {
                    // TODO Auto-generated method stub
    
                }
    
    
    
                public void afterTextChanged( Editable arg0)
                {
                    // TODO Auto-generated method stub
                    ListText.this.arrad.getFilter().filter(arg0);
                }
            });
    
        }
    
    
        ///////////////////////////////////Internal classes ////////////////////////
    
        private class Followed
        {
            private String _name;
            private String _id;
            private boolean _followed;
            private String _picToDelete = "http://images.wikia.com/tibia/en/images/7/72/Skeleton.gif";
    
            private Followed(String name, String id, String followed)
            {
                this._name = name;
                this._id = id;
                this._followed = followed.equals("1");
            }
    
            public String toString(){return _name;}
            public String getName(){return _name;}
            public String getId(){return _id;}
            public boolean idFollowed(){return _followed;}
            public String getURL(){return _picToDelete;}
        }
    
        /////////////////////////////////////////Adapter//////////////////////////////////
    
        private class FollowedFilterableAdapter extends BaseAdapter implements Filterable
        {
            /**
             * Lock used to modify the content of {@link #mObjects}. Any write operation
             * performed on the array should be synchronized on this lock. This lock is also
             * used by the filter (see {@link #getFilter()} to make a synchronized copy of
             * the original array of data.
             */
            private final Object _Lock = new Object();
    
            /*/**
             * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever
             * {@link #mObjects} is modified.
             */
            //private boolean _NotifyOnChange = true;
    
            private List<Followed> _Objects;
    
            private ArrayList<Followed> _followedFriends;
            private ArrayFilter _Filter;
    
            public FollowedFilterableAdapter(Followed[] followedFriends)
            {
                _Objects = Arrays.asList(followedFriends);
            }
    
            public int getCount() {
                return _Objects.size();
            }
    
            public Followed getItem(int position) {
                return _Objects.get(position);
            }
    
            public long getItemId(int position) {
                return position;
            }
    
            public View getView(int position, View convertView, ViewGroup parent) {
                int px = 2;
    
                //Creating the CategoryRow that represents the row
                LinearLayout lstItem = new LinearLayout(ListText.this);
                lstItem.setLayoutParams(new ListView.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT,1));
                lstItem.setOrientation(LinearLayout.HORIZONTAL);
                //lstItem.setPadding(px,px,px,px);
                lstItem.setGravity(Gravity.CENTER_VERTICAL);
                /*<LinearLayout android:layout_width="fill_parent"
                                android:layout_height="wrap_content" android:orientation="horizontal"
                                android:padding="2dp" android:gravity="center_vertical">*/
    
                //Adding the Image
                ImageView icon = new ImageView(ListText.this);
                icon.setLayoutParams(new LayoutParams(50,50));
                icon.setImageResource(R.drawable.icon);
                icon.setScaleType(ScaleType.CENTER_CROP);
                //icon.setImage(tag.getId());
                /*<ImageView android:layout_width="50dp" android:id="@+id/iconFollList"
                                    android:src="@drawable/icon" android:layout_height="40dp"></ImageView>*/
    
                //Adding the Linear Layout for the text
                RelativeLayout lstTextx = new RelativeLayout(ListText.this);
                lstTextx.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT,1));
                lstTextx.setGravity(Gravity.CENTER_VERTICAL);
                lstTextx.setPadding(5, px, px, px);
                /*<LinearLayout android:layout_width="fill_parent"
                                    android:layout_height="wrap_content" android:orientation="vertical"
                                    android:padding="2dp" android:paddingLeft="5dp">*/
    
                //Adding the Name of the person who commented
                TextView txtCommenter = new TextView(ListText.this);
                txtCommenter.setLayoutParams(
                        new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                        LayoutParams.WRAP_CONTENT));
                txtCommenter.setTextSize(10);
                txtCommenter.setTypeface(Typeface.create("Sans Serif", Typeface.BOLD));
                txtCommenter.setText(_Objects.get(position).getName());
                /*<TextView android:text="TextView" android:id="@+id/FollListCategory"
                                        android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>*/
    
    
                ImageView btnFollowed = new ImageView(ListText.this);
                RelativeLayout.LayoutParams params = 
                    new RelativeLayout.LayoutParams(80,30);
                params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                btnFollowed.setLayoutParams(params);
                btnFollowed.setImageResource(R.drawable.icon);
                btnFollowed.setScaleType(ScaleType.FIT_XY);
    
                //Arming the View
                lstItem.addView(icon, 0);
                lstTextx.addView(txtCommenter, 0);
                lstTextx.addView(btnFollowed,1);
                lstItem.addView(lstTextx,1);
    
                return lstItem;
            }
    
            /**
             * {@inheritDoc}
             */
            @Override
            public void notifyDataSetChanged() {
                super.notifyDataSetChanged();
                //_NotifyOnChange = true;
            }
    
            /*public void setNotifyOnChange(boolean notifyOnChange) {
                _NotifyOnChange = notifyOnChange;
            }*/
    
            public Filter getFilter() {
                if (_Filter == null) {
                    _Filter = new ArrayFilter();
                }
                return _Filter;
            }
    
            /////////////////////Second Level Internal classes //////////////////////////
    
            private class ArrayFilter extends Filter {
                @Override
                protected FilterResults performFiltering(CharSequence prefix) {
                    FilterResults results = new FilterResults();
    
                    if (_followedFriends == null) {
                        synchronized (_Lock) {
                            _followedFriends = new ArrayList<Followed>(_Objects);
                        }
                    }
    
                    if (prefix == null || prefix.length() == 0) {
                        synchronized (_Lock) {
                            ArrayList<Followed> list = new ArrayList<Followed>(_followedFriends);
                            results.values = list;
                            results.count = list.size();
                        }
                    } else {
                        String prefixString = prefix.toString().toLowerCase();
    
                        final ArrayList<Followed> values = _followedFriends;
                        final int count = values.size();
    
                        final ArrayList<Followed> newValues = new ArrayList<Followed>(count);
    
                        for (int i = 0; i < count; i++) {
                            final Followed value = values.get(i);
                            final String valueText = value.toString().toLowerCase();
    
                            // First match against the whole, non-splitted value
                            if (valueText.startsWith(prefixString)) {
                                newValues.add(value);
                            } else {
                                final String[] words = valueText.split(" ");
                                final int wordCount = words.length;
    
                                for (int k = 0; k < wordCount; k++) {
                                    if (words[k].startsWith(prefixString)) {
                                        newValues.add(value);
                                        break;
                                    }
                                }
                            }
                        }
    
                        results.values = newValues;
                        results.count = newValues.size();
                    }
    
                    return results;
                }
    
                @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    //no inspection unchecked
                    _Objects = (List<Followed>) results.values;
                    if (results.count > 0) {
                        notifyDataSetChanged();
                    } else {
                        notifyDataSetInvalidated();
                    }
                }
            }
        }
    
    公共类ListText扩展活动{
    私有ListView lv1;
    私人跟随的朋友[];
    ListView lst;
    编辑文本edt;
    以下是可过滤适配器阵列;
    /**在首次创建活动时调用*/
    @凌驾
    创建时的公共void(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    lv1=(ListView)findViewById(R.id.listView1);
    edt=(EditText)findViewById(R.id.editText1);
    followeredfriends=新跟随[10];
    followeredfriends[0]=新跟随者(“Alan Walder”,“0123456789”,“1”);
    followeredfriends[1]=新跟随者(“Alberto Levi”、“123456789”、“1”);
    followeredfriends[2]=新跟随者(“David Rodan”、“23456789”、“1”);
    followeredfriends[3]=新跟随者(“大卫•斯特恩”、“3456789”、“1”);
    followeredfriends[4]=新跟随者(“Elias Jawa”、“456789”、“1”);
    followeredfriends[5]=新跟随者(“Elian Moreno”、“56789”、“1”);
    followeredfriends[6]=新跟随者(“Jonathan Rodan”、“6789”、“1”);
    followeredfriends[7]=新跟随者(“Klara Rodan”、“789”、“1”);
    followeredfriends[8]=新跟随者(“威利·罗萨莱斯”、“89”、“1”);
    followeredfriends[9]=新跟随者(“ZZZ-ZZZ”、“9”、“1”);
    arrad=新的FollowedFilterableAdapter(followedFriends);
    lv1.设置适配器(arrad);
    addTextChangeList();
    }
    私有void addTextChangeList()
    {
    edt.addTextChangedListener(新的TextWatcher()
    {
    public void onTextChanged(字符序列arg0、int arg1、int arg2、int arg3)
    {
    //TODO自动生成的方法存根
    }
    更改前的公共void(字符序列arg0、int arg1、int arg2、int arg3)
    {
    //TODO自动生成的方法存根
    }
    public void PostTextChanged(可编辑arg0)
    {
    //TODO自动生成的方法存根
    ListText.this.arrad.getFilter().filter(arg0);
    }
    });
    }
    ///////////////////////////////////内部类////////////////////////
    随后是私人阶级
    {
    私有字符串\u名称;
    私有字符串_id;
    私有布尔型;
    专用字符串_picToDelete=”http://images.wikia.com/tibia/en/images/7/72/Skeleton.gif";
    后跟私有(字符串名称、字符串id、字符串后跟)
    {
    这个。_name=name;
    这个。_id=id;
    这个._followed=followed.equals(“1”);
    }
    公共字符串toString(){return\u name;}
    公共字符串getName(){return\u name;}
    公共字符串getId(){return\u id;}
    公共布尔idFollowed(){return\u followed;}
    公共字符串getURL(){return\u picToDelete;}
    }
    /////////////////////////////////////////适配器//////////////////////////////////
    私有类FollowedFilterableAdapter扩展BaseAdapter实现Filterable
    {
    /**
    *用于修改{@link#mObjects}内容的锁。任何写入操作
    *在阵列上执行的操作应在此锁上同步。此锁也是
    *由筛选器使用(请参见{@link#getFilter()}来创建
    *原始数据数组。
    */
    私有最终对象_Lock=新对象();
    /*/**
    *指示在任何时候是否必须调用{@link#notifyDataSetChanged()}
    *{@link#mObjects}已修改。
    */
    //私有布尔值_NotifyOnChange=true;
    公共关系
    
        <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <EditText android:text="" android:layout_height="wrap_content"
        android:id="@+id/editText1" android:layout_width="match_parent"></EditText>
        <ListView android:id="@+id/listView1" android:layout_height="fill_parent"
        android:layout_width="match_parent" android:layout_weight="1"></ListView>
    
    </LinearLayout>