问题:活动A是ListView
,其中包含ListAdapter
,并且点击适配器的任何项目都会导致活动B.活动B有一个提取新项目(或几个)的按钮从Web(使用AsyncTask
)并在按下时将其添加到活动A显示的列表中。来自B的操作未被ProgressDialog
阻止,因此用户可以在B开始完成获取数据的AsyncTask
之前移回A。
所以我需要一种从B更新A的适配器的方法。
我有一个C类,静态数据显示在ListView
A中。当按下B处的按钮时,它会将该值添加到C.该类还有来自A的适配器作为静态字段,但我认为这会泄漏Context
的内存,这很糟糕。我解决这个问题的第一个想法是从C中删除静态适配器,每次A onResume()
(如果适配器上的数据与我在C上的数据不同),我再次将数据从C加载到适配器中和notifyDatasetChanged()
。好吧,它大部分时间都可以工作,但是如果用户在B从Web获取数据之前从B返回A,则适配器不会更新,因为在获取数据之前onResume()
已经来了。 / p>
问题:是否有更好的方法从B更新A的适配器?
答案 0 :(得分:0)
不要将静态引用保存到适配器。它确实会泄漏内存并表现得很糟糕。
看来我第一次误解了。这是一个更新的答案:
第一个解决方案
最漂亮的解决方案是为数据存储实现内容提供程序并在A和B中查询该内容提供程序。使用contentProvider.insert()更新B中的数据 并使用contentProvider.query()读取数据,例如,如果它由数据库或MatrixCursor支持,则返回SQLiteCursor,如果您只是将其保存在内容提供程序的内存中。
基本步骤(没有CursorLoader):
ContentResolver.registerContentObserver(uri, true, this)
将自己注册为contentobserver,其中uri是使用您设置的某种方案的URI。ContentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
查询contentprovider来获取数据,其中projection,selection,selectionArgs和sortOrder可以适合您的contentprovider(可能为null)。 Uri是指您想要查询的数据,是您的选择。ContentResolver.insert()
。在您的contentprovider的insert
中,您调用ContentResolver.notifyChange (Uri uri, null, null)
,其中uri是您在步骤1中使用的URI。请注意,如果使用CursorLoaders,则根本不需要调用registerContentObserver! 它将在加载器中接收新游标,因为它在您通知更改时具有自动重新查询。
第二个解决方案 一个不太漂亮的解决方案是实现处理数据的单例对象。 类似的东西:
实施班级
public class DataHolder {
private static DataHolder sDataHolder;
private String data = ""; // Data represented by string.
public DataHolder getInstance() {
if (sDataHolder == null) {
sDataHolder = new DataHolder()
}
return sDataHolder;
}
private DataHolder() {} // Hidden constructor
public void setData(final String data) {
mData = data;
for (DataListener listener: mDataListeners) {
listener.onDataChanged(mData);
}
}
public void registerListener(DataListener listener) {
mDataListeners.add(listener);
}
public String unregisterListener(DataListener listener) {
mDataListeners.remove(listener);
}
public String getData() {
return mData;
}
public static interface DataListener {
public void onDataChanged(String data);
}
}
onStart()
中的数据,以确保在使用DataHolder.getInstance().getData()
B处于活动状态时进行更改时设置该数据。DataHolder.getInstance().registerListener(this);
在A的onCreate / onStart中注册监听器让监听器更新数据。DataHolder.getInstance().unregisterListener(this)
DataHolder.getInstance().setData(data)
另请注意,如果同时使setValue同步,则可以将void registerListener()
更改为synchronized String registerListenerAndGetValue()
,从而使第二个解决方案完全保持线程安全。
基于误解的旧答案
我对一般结果处理的旧答案并没有完全回答这个问题,但它是:
如果要将数据发送回活动A,则应执行以下操作:
startActivityForResult (Intent intent, int requestCode)
setResult (int resultCode)
onActivityResult (int requestCode, int resultCode, Intent data)
作为一个补充,你可以添加,所以你只能在第一次获取数据,只有savedInstanceState == null
在例如onCreate()时才能这样做。
答案 1 :(得分:0)
尝试拨打mListView.invalidate();
*的 * java-doc的强>
使整个视图无效。如果视图可见,将在某个时间点调用onDraw(android.graphics.Canvas)。必须从UI线程调用此方法。要从非UI线程调用,请调用postInvalidate()。