如何从完全不相关的类更新ListView

时间:2014-05-27 00:20:39

标签: android multithreading android-listview android-ui

我已经阅读了很多关于如何更新ListView的问题。他们几乎都说adapter.notifyDataSetChanged()(如果在runOnUiThread的单独线程中)。

我的问题早一点开始:我如何获得我需要的适配器或者调用runOnUiThread的Activity?

这是我当前代码的一个非常简化的版本:

我有一个数据类,可以随时随地更新。 update方法需要启动一个新的Thread,这就是我不能等待返回值的原因。

class Data {
private static double[] data = new double[7]

public static void update(final Context context) {

    new Thread(new Runnable() {
        @Override
        public void run() {
              //do lots of complicated stuff
        }
    }).start();
}

public double[] getData {
    return data;
}

我有一个Activity(不是主Activity),除其他外,还包含ListView

public class ListViewActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_ListView);
    ListView listView = (ListView) findViewById(R.id.MyListView);
    listView.setAdapter(new CustomListViewAdapter(this));
}

然后我使用自定义适配器来设置ListView我想要的方式。

class CustomListViewAdapter extends BaseAdapter {

private final LayoutInflater layoutInflater;

public CustomListViewAdapter(Context context) {
    layoutInflater = LayoutInflater.from(context);
}

@Override
public View getView(int position, View view, ViewGroup parent) {
    ViewHolder viewHolder = new ViewHolder();
    if (view == null) {
        view = layoutInflater.inflate(R.layout.listView_row_layout, parent, false);
        viewHolder.value = (TextView) view.findViewById(R.id.listViewDataTextField);
        view.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) view.getTag();
    }
    double data = Data.getData()[position];
    viewHolder.value.setText(data+"");

    return view;
}
private class ViewHolder {
    TextView value;
}

现在我想在update()方法中的Thread完成获取新数据后立即更新ListView。获取数据可能需要几秒钟,因此无法预测,到那时活动将是什么活动。如果我的ListViewActivity处于活动状态,我希望ListView立即更改为新数据。

那么如何在另一个线程中从另一个不是Activity的类更新ListView呢?我不认为将适配器放在静态字段中是一个好主意,因为ListViewActivity可能一直在创建和销毁?但我还有其他选择吗?

2 个答案:

答案 0 :(得分:1)

定义回调接口。使您的更新方法将此回调的实例作为参数,并在更新完成后回调它。

public interface UpdateCallback {
    public void onUpdateFinished();
}

public void update(final Context context, final UpdateCallback callback) {

    new Thread(new Runnable() {
        @Override 
        public void run() { 
            // do lots of complicated stuff
            callback.onUpdateFinished();
        } 
    }).start();
}

然后在您的Activity中,您可以通知适配器数据已更改:

Data.update(this, new UpdateCallback() {
    public void onUpdateFinished() {
        adapter.notifyDatasetChanged();
    }
});

答案 1 :(得分:0)

extendIt看起来你的主要问题可以很快制定为“我如何获得适配器”,所以我会尝试解决这个问题。让我们尝试使用旧的优秀Java单例来解决问题。我们的想法是为您需要更新的所有视图创建全局配置和预创建适配器:

    public class GlobalConfig {

        private static GlobalConfig config = null;
        private CustomBaseAdapterOne adapter1 = null;
        private CustomBaseAdapterTwo adapter2 = null;
        public GlobalConfig getAdapterOne() {return adapter1;}
        public GlobalConfig getAdapterTwo() {return adapter2;}

        public static synchronized GlobalConfig getInstance() {
            if (config == null) {
                config = new GlobalConfig();
                config.adapter1 = new CustomBaseAdapterOne();
                config.adapter2 = new CustomBaseAdapterTwo();
            }
            return config;
        }
    }

ListViewActivity需要扩展DataSetObserver类并在启动时注册观察者。你的CustomListAdapter需要在它启动时注册观察者,它还需要能够通过一个函数(例如setContext)初始化init params(在你的情况下为Context),而不是通过构造函数,所以在你的ListViewActivity中你'我需要做类似下面的事情:

GlobalConfig cfg = GlobalConfig.getInstance();
CustomerAdapterOne ad = cfg.getAdapterOne();
ad.setContext(this);
ad.registerDataSetObserver(this);

从需要更新ListView的单独线程中,您将运行:

GlobalConfig cfg = GlobalConfig.getInstance();
try {
    cfg.getAdapterOne().notifyDataSetChanged();
}
catch{... }

我认为,在这里尝试/捕获是一个好主意,因为我不知道如果ListView在您需要通知时已经死亡会发生什么。

总结一下:您需要为每个需要更新的视图预先创建一个适配器,并使其全局可供所有需要它的人使用。