【问题标题】:Android - result from AsyncTask not being returned to main ActivityAndroid - AsyncTask 的结果未返回到主 Activity
【发布时间】:2010-12-02 07:33:05
【问题描述】:

我正在尝试使用 AsyncTask 扩展类来处理连接到 URL、解析 JSON、在解析期间显示不确定的 ProgressDialog,并将结果作为 HashMap 中的键值对返回给主 Activity。然后 HashMap 的结果将被主 Activity 读取并放入表单字段中。然而,即使我在我的 AsyncTask 中填充了 HashMap(由 println 语句证明),调用主 Activity 中返回 HashMap 的方法会产生一个空结果。我不知道这是我做错了什么,还是我误解了 AsyncTask 的功能。

我正在讨论将我的扩展 AsyncTask 的类转换为 Activity。本质上,用户在此数据搜索/解析期间不应该做任何其他事情,并且应该等到 ProgressDialog 消失,然后才能再次与应用程序交互(或通过点击后退按钮)。此外,我的应用程序需要能够处理我的 AsyncTask 中捕获异常的某些情况(无法连接到 URL、错误的 JSON、无法找到要搜索的产品 ID),并且为这些异常定制了自定义错误对话框。如果这个类是一个 Activity,我可以很容易地做到这一点,因为我可以在调用 finish() 时返回不同的结果代码,具体取决于是否捕获到异常。

同样,我不确定 AsyncTask 是否是这里的最佳解决方案,因为在收集和解析信息时用户不会做任何其他事情。请告诉我新的 Activity 是否有意义,或者我只是在修改后台线程的实现。

MainActivity.java

mInitiateProductLookupButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                ProductLookup pl = new ProductLookup(id, MainActivity.this);
                pl.execute();

                // The below variable is always empty!
                HashMap<String, String> productInfo = pl.getProductInfo();
                applyProductInfoToFormFields(productInfo);
            }
        });

ProductLookup.java

public class ProductLookup extends AsyncTask<Object, Void, HashMap<String, String>> {
    private String mProductID;
    private Context mContext;
    HashMap<String, String> mProductInfo;
    ProgressDialog mDialog;

    public ProductLookup(String id, Context applicationContext) {
        mProductID = id;
        mContext = applicationContext;
        mProductInfo = new HashMap<String, String>();
    }

    @Override
    protected void onPreExecute() {
        mDialog = new ProgressDialog(mContext);
        mDialog.setMessage("Loading product info. Please wait...");
        mDialog.setIndeterminate(true);
        mDialog.setCancelable(false);
        mDialog.show();
    }

    @Override
    protected void onPostExecute(HashMap<String, String> result){
       super.onPostExecute(result);
       mDialog.dismiss();
       mProductInfo = result;
    }


    @Override
    protected HashMap<String, String> doInBackground(Object... params) {
        try {
            // Connect to URL, parse JSON, and add key-value pairs to mProductInfo...

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        finally {
            try {
                // Close input/output reader variables
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return mProductInfo;

    }

    public HashMap<String, String> getProductInfo(){
        return this.mProductInfo;
    }

}

【问题讨论】:

    标签: android thread-safety android-asynctask


    【解决方案1】:

    当您发出.execute() 时,它作为线程运行并且不等待结果。

    因此,无论您在此之后调用什么,它都是空的,因为尚未加载数据。

    您需要在 PostExecuted 上通过 setter MainActivity.this.setProductInfo(result) 将结果直接设置到您的 Activity 中

    【讨论】:

    • 当我尝试这样做时,我收到一个错误,无法编译:“在范围内无法访问 MainActivity 类型的封闭实例”
    • 在 MainActivity 中创建 AsyncTask 作为子私有类。
    • 具体是如何创建子私有类的?
    • 只需将代码放在活动中的方法级别(因为它是方法,而不是方法)
    • 很好,效果很好。只是好奇 - 如果 BookLookupInfo 现在是 MainActivity 的子类,那么调用“MainActivity.this.setProductInfo(result)”而不是“setProductInfo(result)”的原因是什么?
    【解决方案2】:

    你有一些想念的概念。 AsyncTask.execute() 之后的语句将在调用之后立即执行。当您的 doInBackground 在其他线程中执行时。在这里,当您使用 productInfo 地图时,doInBackground 没有完成,因此结果没有在那里填充

    简单的解决方案是使用 onPostExecute 方法中的结果。

    protected void onPostExecute(HashMap<String, String> result){
           mDialog.dismiss();
           mProductInfo = result;
     applyProductInfoToFormFields(productInfo);
    
        }
    

    【讨论】:

    • applyProductInfoToFormFields() 方法在 MainActivity 中,但是,它将该类的数据成员(代表表单字段)设置为具有新值(例如,从我的 JSON 解析的值)。我认为我无法从 ProductLookup 中调用该方法。另外,我认为如果我要修改/与我的 GUI 交互,我应该继续从我的 MainActivity 中执行此操作。 ProductInfo 怎么知道我的字段的数据成员是什么而不保存它们的新实例?
    • 我没有正确理解你。我认为你需要访问你的 GUI 控制表单 applyProductInfoToFormFields()。如果是这样,您最好的做法是全局声明您的所有 GUI 组件,以便您可以从任何地方访问它。
    • 我将如何从 ProductLookup 中引用 MainActivity 的数据成员?我需要对它们进行哪些更改才能使其全球化?
    • 如果您在 MainActivity.java 中声明 ProductLookup,则在每个类之外声明每个控件。如果您使用不同的 java 类。然后声明为静态。如果 MainActivity.java 中有静态按钮按钮。您可以参考使用 MainActivity.button
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    • 1970-01-01
    • 2016-05-04
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多