如何从其他Activity更新Activity的适配器?

时间:2012-02-17 18:54:57

标签: android android-activity

问题:活动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的适配器?

2 个答案:

答案 0 :(得分:0)

不要将静态引用保存到适配器。它确实会泄漏内存并表现得很糟糕。

看来我第一次误解了。这是一个更新的答案:

第一个解决方案

最漂亮的解决方案是为数据存储实现内容提供程序并在A和B中查询该内容提供程序。使用contentProvider.insert()更新B中的数据 并使用contentProvider.query()读取数据,例如,如果它由数据库或MatrixCursor支持,则返回SQLiteCursor,如果您只是将其保存在内容提供程序的内存中。

基本步骤(没有CursorLoader):

  1. 在onCreate of A中,您使用ContentResolver.registerContentObserver(uri, true, this)将自己注册为contentobserver,其中uri是使用您设置的某种方案的URI。
  2. 在onCreate of A中,您可以通过使用ContentResolver.query(uri, projection, selection, selectionArgs, sortOrder)查询contentprovider来获取数据,其中projection,selection,selectionArgs和sortOrder可以适合您的contentprovider(可能为null)。 Uri是指您想要查询的数据,是您的选择。
  3. 在B中加载数据时,请致电ContentResolver.insert()。在您的contentprovider的insert中,您调用ContentResolver.notifyChange (Uri uri, null, null),其中uri是您在步骤1中使用的URI。
  4. 在A中实现onChange(boolean selfChange)并在调用内容提供程序时重新查询。
  5. 请注意,如果使用CursorLoaders,则根本不需要调用registerContentObserver! 它将在加载器中接收新游标,因为它在您通知更改时具有自动重新查询。

    第二个解决方案 一个不太漂亮的解决方案是实现处理数据的单例对象。 类似的东西:

    1. 实施班级

      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);
          }
      }
      
    2. 制作工具DataListener
    3. 读取并更新DataListener的onStart()中的数据,以确保在使用DataHolder.getInstance().getData() B处于活动状态时进行更改时设置该数据。
    4. 使用DataHolder.getInstance().registerListener(this);在A的onCreate / onStart中注册监听器让监听器更新数据。
    5. 使用DataHolder.getInstance().unregisterListener(this)
    6. 取消注册A的onDestroy / onStop中的侦听器
    7. 使用DataHolder.getInstance().setData(data)
    8. 设置数据并通知B中的任何侦听器

      另请注意,如果同时使setValue同步,则可以将void registerListener()更改为synchronized String registerListenerAndGetValue(),从而使第二个解决方案完全保持线程安全。

      基于误解的旧答案

      我对一般结果处理的旧答案并没有完全回答这个问题,但它是:

      如果要将数据发送回活动A,则应执行以下操作:

      1. 始终使用startActivityForResult (Intent intent, int requestCode)
      2. 启动B.
      3. 使用setResult (int resultCode)
      4. 在B中完成设置结果
      5. 通过实施onActivityResult (int requestCode, int resultCode, Intent data)
      6. 返回A时处理结果

        作为一个补充,你可以添加,所以你只能在第一次获取数据,只有savedInstanceState == null在例如onCreate()时才能这样做。

答案 1 :(得分:0)

尝试拨打mListView.invalidate();

*的 * java-doc的

使整个视图无效。如果视图可见,将在某个时间点调用onDraw(android.graphics.Canvas)。必须从UI线程调用此方法。要从非UI线程调用,请调用postInvalidate()