ListView上的notifyDataSetChanged()不使用runOnUiThread(new Runnable())

时间:2014-07-31 16:36:07

标签: android multithreading listview notifydatasetchanged

我有一个使用BaseAdapter的ListView,ListView位于ViewGroup中。 当我从另一个线程通过runOnUiThread()调用notifyDataSetChanged()时,ListView不会自行更新。只有当我触摸并拖动时,换句话说,尝试滚动,ListView更新。

当他们从另一个线程调用notifyDataSetChanged()而不是UI线程时,我得到了很多人有问题,但我没有这样做但仍然有问题。

以下代码似乎是重现问题的最低要求。

public class MyMainActivity extends Activity
{
    public MyStringViewGroup StringViewGroup = null;

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

        StringViewGroup = new MyStringViewGroup(this);
        setContentView(StringViewGroup);

        // This is the thread I'll call UpdateStringList() from
        new OtherThread(this).start();

        //UpdateStringList(); // If I call it from here, everything works
    }

    // This should post the runnable on the UI-thread so StringViewGroup.UpdateStringList() is called from the right thread
    public void UpdateStringList() {runOnUiThread(new Runnable() {public void run()
    {
        StringViewGroup.UpdateStringList();
    }});}
}

class OtherThread extends Thread
{
    MyMainActivity Main = null;

    OtherThread(MyMainActivity main)
    {
        Main = main;
    }
    @Override public void run()
    {
        // Wait 2 seconds
        try {sleep(2000);} catch (InterruptedException e) {}

        // Call the funktion that add the three rows
        Main.UpdateStringList(); // If i call it from here, It's not working
    }
}

class MyStringViewGroup extends ViewGroup
{
    ListView StreamListView = null;
    MyStringListAdapter StringListAdapter = null;
    ArrayList<String> StringArray = new ArrayList<String>();

    public MyStringViewGroup(MyMainActivity context)
    {
        super(context);

        StreamListView = new ListView(context);
        StreamListView.setId(android.R.id.list);
        addView(StreamListView);

        StringListAdapter = new MyStringListAdapter(StringArray);
        StreamListView.setAdapter(StringListAdapter);
    }

    public void UpdateStringList()
    {
        StringArray.add("Row 1");
        StringArray.add("Row 2");
        StringArray.add("Row 3");

        StringListAdapter.notifyDataSetChanged();
    }

    @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        StreamListView.layout(left, top, right, bottom);
    }

    // An ordinary Adapter, nothing special here (I hope)
    public class MyStringListAdapter extends BaseAdapter
    {
        ArrayList<String> StringArray = null;

        public MyStringListAdapter(ArrayList<String> stringArray) {StringArray = stringArray;}
        @Override public int getCount() {return StringArray.size();}
        @Override public String getItem(int position) {return StringArray.get(position);}
        @Override public long getItemId(int position) {return position;}
        @Override public View getView(int position, View convertView, ViewGroup parent)
        {
            final TextView textView;
            if (convertView == null)
            {
                textView = new TextView(MyStringViewGroup.this.getContext());
                textView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            }
            else
                textView = (TextView)convertView;

            textView.setText(StringArray.get(position));
            return textView;
        }
    }
}

我注意到调用了适配器中的getView()然后我尝试滚动而不是之前三行出现,显然适配器已更新。

那么,通过runOnUiThread()调用时会有什么不同?

如果我改为:

public void UpdateStringList() {StringViewGroup.post(new Runnable() {public void run()
{
    StringViewGroup.UpdateStringList();
}});}

并尝试致电:

UpdateStringList();

从主线程,我得到同样的问题。 我甚至试图在listview上调用invalidate()和requestLayout()而没有结果(你不应该这样做,但只是为了确保)

我在ViewGroup中需要做的是我错过了吗?

1 个答案:

答案 0 :(得分:0)

好的,我只是想通了你必须在onLayout调用的ListView上调用measure(),如:

@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
    StreamListView.measure(...);
    StreamListView.layout(left, top, right, bottom);
}

当通过runOnUiThread(new Runnable())从另一个线程调用notifyDataSetChanged()时,只会发生错误,这仍然很奇怪,但我认为measure()是必需的。