如何更新与其他活动的活动的衔接?与其他

2023-09-12 22:28:14 作者:壹陣感情風

问题:活动A是一个的ListView 包含 ListAdapter ,并单击适配器导线的任何项目到活动B.活动B有一个按钮,从网上获取一个新的项目(或几个)(使用的AsyncTask ),并将其添加到通过一个活动时显示的列表pressed。从B中的操作没有被一个 ProgressDialog ,这样用户就可以回迁的的AsyncTask 的前B启动完成获取数据。

所以,我需要选自B更新的适配器的一种方式。

我有一个C类,在显示静态数据的的ListView 由A.当B处的按钮pssed $ P $,它增加了该值C.这类也已经从一个适配器作为静态字段,但我认为这泄漏从上下文的记忆,那是不好的。我的第一个解决这个的想法是删除从C每一次的静态适配器和 onResume()(如果适配器上的数据是从我都位于C不同)我加载从C数据再次插入适配器, notifyDatasetChanged()。那么,它的作品大部分时间,但如果用户返回到A从B B从网络获取之前的数据,那么适配器不更新,因为 onResume()来之前的数据被取出。

问:是否有选自B更新的适配器的更好的办法?

解决方案

不要保存静态引用到适配器。它的确会造成内存泄漏和表现不好。

看来我理解错了第一次。下面是一个更新的回答:

第一个解决方案

的prettiest解决方案是实现的内容提供者的数据存储和查询A和B的内容提供者更新使用contentProvider.insert在B中的数据() 和阅读使用contentProvider.query()返回例如SQLiteCursor的数据,如果它是由数据库或MatrixCursor支持,如果你只是将其保存在内存中的内容提供商。

的基本步骤(不CursorLoader):

在A的的onCreate您使用自己注册为一个contentobserver ContentResolver.registerContentObserver(URI,真实,这一点),其中URI是使用一些方案设置一个URI。 在A的的onCreate您使用查询ContentProvider的获取数据 ContentResolver.query(URI,投影,选择,selectionArgs两个,排序顺序)其中投影,选择,selectionArgs两个和排序顺序可有什么适合你的ContentProvider(可能为空)。开放的我们指的是你要查询和是你的选择的数据。 当数据在B调用加载 ContentResolver.insert()。在插入您的ContentProvider你调用 ContentResolver.notifyChange(URI URI,NULL,NULL),其中URI是URI你在步骤1中使用。 在一个工具的onChange(布尔selfChange),并重新查询内容提供商时,它被调用。

请注意,你不会需要调用registerContentObserver如果使用CursorLoaders了! 这将收到的装载机新的游标,因为它有自动重新查询,当您通知更改。

第二类解决方案 一个不太pretty的解决方案是实现一个处理数据的单独的对象。 是这样的:

实现类

 公共类DataHolder {
    私有静态DataHolder sDataHolder;

    私人字符串数据=; //数据再由串psented $ P $。
    公共DataHolder的getInstance(){
        如果(sDataHolder == NULL){
            sDataHolder =新DataHolder()
        }
        返回sDataHolder;
    }

    私人DataHolder(){} //隐藏构造

    公共无效使用setData(最终字符串数据){
        MDATA =数据;

        对于(的DataListener听众:mDataListeners){
            listener.onDataChanged(MDATA);
        }
    }

    公共无效registerListener(的DataListener监听器){
       mDataListeners.add(听众);
    }

    公共字符串unregisterListener(的DataListener监听器){
       mDataListeners.remove(听众);
    }

    公共字符串的getData(){
       返回MDATA;
    }

    公共静态接口的DataListener {
        公共无效onDataChanged(字符串数据);
    }
}
 

请一个工具的DataListener 在读取和更新 ONSTART数据()的DataListener,以确保它被设置如果换做是当B在世使用 DataHolder.getInstance()的getData()。 注册听众中一个的onCreate / ONSTART使用 DataHolder.getInstance()registerListener(本); 让听者更新数据 在A的的onDestroy注销监听器/的onStop使用 DataHolder.getInstance()。unregisterListener(本) 设置中的数据,并使用 DataHolder.getInstance()在B的信号,任何监听器。使用setData(数据)

另外请注意,你可以让第二个解决方案完全线程安全的,通过改变无效registerListener()同步串registerListenerAndGetValue()如果你也使的setValue同步。

基于一种误解旧的答案

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

公主连接台服2周年更新活动内容一览

如果你想将数据发送到一个活性的,你应该做到以下几点:

始终以 startActivityForResult B(意向意图,诠释请求code) 在使用B中,当完成设置结果的setResult(INT结果code) 处理结果,当你回来到A通过实施 onActivityResult(INT申请code,INT结果code,意图数据)

作为此外,您可以添加,所以你只能这样做只有当 savedInstanceState == NULL 在如的onCreate()。

Problem: Activity A is a ListView that contains a ListAdapter, and clicking in any item of the adapter leads to activity B. Activity B has a button that fetches a new item (or several) from the web (using an AsyncTask) and adds it to the list displayed by activity A when pressed. That operation from B is not blocked by a ProgressDialog, so the user can move back to A before the AsyncTask that B started finishes fetching the data.

So I need a way of updating the adapter of A from B.

I have a class C with static data displayed in the ListView by A. When the button at B is pressed, it adds that value to C. That class also has the adapter from A as a static field, but I think that this leaks the memory from the Context, and that is bad. My first idea of fixing this was removing the static adapter from C and every time A onResume() (and if the data on the adapter is different from what I have at C), I load the data from C again into the adapter and notifyDatasetChanged(). Well, it works most of the time, but if the user goes back to A from B before B fetches the data from the web, then the adapter does not update, since the onResume() came before the data is fetched.

Question: Is there a better way of updating the adapter of A from B?

解决方案

Don't save static references to the adapter. It will indeed leak memory and behave badly.

It appears I misunderstood the first time. Here is an updated answer:

First solution

The prettiest solution is to implement a content provider for the data storage and query that content provider in both A and B. Update the data in B using contentProvider.insert() and read the data using contentProvider.query() returning for example a SQLiteCursor if it is backed by database or a MatrixCursor if you just save it in memory in the content provider.

The basic steps (without CursorLoader):

In onCreate of A you register yourself as a contentobserver using ContentResolver.registerContentObserver(uri, true, this) where uri is an URI using some scheme you set. In onCreate of A you get the data by querying the contentprovider using ContentResolver.query(uri, projection, selection, selectionArgs, sortOrder) where projection, selection, selectionArgs and sortOrder can be what fits your contentprovider (maybe null). Uri refers to the data you want to query and is your choice. When data is loaded in B you call ContentResolver.insert(). In insert of your contentprovider you call ContentResolver.notifyChange (Uri uri, null, null) where uri is the URI you used in step 1. Implement onChange(boolean selfChange) in A and requery the content provider when it is called.

Note that you will not need to call registerContentObserver at all if you use CursorLoaders! It will receive the new cursor in the loader since it has automatic requery when you notify change.

Second solution A less pretty solution is to implement a singleton object that handles the data. Something like:

Implement the class

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);
    }
}

Make A implement DataListener Read and update the data in onStart() of DataListener to make sure that it is set if the change was done when B was alive using DataHolder.getInstance().getData(). Register listener in A's onCreate/onStart using DataHolder.getInstance().registerListener(this); Let the listener update the data. Unregister listener in A's onDestroy/onStop using DataHolder.getInstance().unregisterListener(this) Set the data and signal any listener in B using DataHolder.getInstance().setData(data)

Also note that you can make the second solution fully thread safe by changing void registerListener() to synchronized String registerListenerAndGetValue() if you also make setValue synchronized.

Old answer based on a misunderstanding

My old answer for general result handling did not quite answer the question, but it was:

If you want to send data back to an activity A you should do the following:

Always start B with startActivityForResult (Intent intent, int requestCode) Set the result when done in B using setResult (int resultCode) Handle the result when you come back to A by implementing onActivityResult (int requestCode, int resultCode, Intent data)

As an addition you could add so you only fetch data in A the first time by doing it only if savedInstanceState == null in for example onCreate().