【问题标题】:How to get a string back from AsyncTask?如何从 AsyncTask 中取回字符串?
【发布时间】:2012-06-10 20:27:20
【问题描述】:

我有以下课程:

public class getURLData extends AsyncTask<String, Integer, String>{

@Override
protected String doInBackground(String... params) {
    String line;
    try {  
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(params[0]);

        HttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        line = EntityUtils.toString(httpEntity);

    } catch (UnsupportedEncodingException e) {
        line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
    } catch (MalformedURLException e) {
        line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
    } catch (IOException e) {
        line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
    }
    return line;
}

@Override
protected void onPostExecute(String result) {
    super.onPostExecute(result);
}

}

我想这样称呼它:

String output = null;
output = new getURLData().execute("http://www.domain.com/call.php?locationSearched=" + locationSearched);

但输出变量没有获取数据,而是出现错误:

Type mismatch: cannot convert from AsyncTask<String,Integer,String> to String

【问题讨论】:

  • 你从哪里得到你必须做的super.onPostExecute(result);?我没有放那条线,但仍然有效!

标签: android string android-asynctask


【解决方案1】:

方法execute返回AynscTask本身,需要调用get

output =
    new getURLData()
        .execute("http://www.example.com/call.php?locationSearched=" + locationSearched)
        .get();

这将启动一个新线程(通过execute),同时阻塞当前线程(通过get),直到新线程的工作完成并返回结果。

如果你这样做,你只是把你的 async 任务变成了 sync 一个。

但是,使用get 的问题在于,因为它会阻塞,所以需要在工作线程上调用它。但是,AsyncTask.execute() 需要在主线程上调用。因此,尽管此代码可以工作,但您可能会得到一些不希望的结果。我还怀疑 get() 没有被 Google 测试,他们可能在某个地方引入了错误。

参考:AsyncTask.get

【讨论】:

  • 天哪,我越深入,这就越复杂......我要做的就是当用户单击一个按钮时,它会直接加载屏幕,然后显示来自 http 的内容完成的。这是怎么做到的?
  • @Paul:无论你在执行后需要做什么,都可以在onPostExecute 上完成。 简单吗……
  • 我希望是这样,但是如果我移至 onPostExecute 方法,我将不再有 params 变量,并且返回字符串时会出现越来越多的问题。感谢您的帮助,但这花了我几个小时,我真的认为这是一个失败的事业。
  • @Paul:您可以向getURLData 添加一个构造函数,该构造函数接受参数并将它们存储为类成员,然后它们可以在您的onPostExecute 方法中使用。
  • 感谢您的帮助和耐心等待。我设法让它工作!不错的一个:)
【解决方案2】:

我宁愿创建回调而不是阻塞 UI 线程。 在您的类中创建数据到达时将调用的方法。例如:

private void setData(String data){
    mTextView.setText(data);
}

然后在AsyncTask中实现onPostExecute:

@Override
protected void onPostExecute(String result) {
    setData(result);
}

然后在代码的某个地方执行任务:

new getURLData().execute(...

当任务完成时调用setData并填充mTextView。

AsyncTask.get() 会阻塞你的 UI,所以没有理由使用 AsyncTask。

【讨论】:

  • 很好,但是如果该方法在另一个活动中(生成 .execute 的那个),我如何从 AsyncTask 调用 setData
  • 你没有。只需在onPostExecute() 中做你需要的事
  • @FranciscoCorralesMorales 最好定义接口来使用它这样的答案:stackoverflow.com/a/12575319/4616096
【解决方案3】:

如果用户点击按钮,则必须等待内容,同时他们在做什么?

为什么不这样做:

  1. 用户点击按钮。
  2. 检查连接性。如果用户没有连接到互联网,请告诉他们。
  3. 您通过发送 Intent 来启动 IntentService 以发送 HTTP 请求。
  4. 请求完成后,您会发布通知。
  5. 用户点击通知,返回到可以进行下一步操作的Activity。

这允许用户在处理请求时离开并做任何事情。

IntentService 在后台以自己的线程运行。当它接收到一个 Intent 时,它运行 onHandleIntent()。当该方法完成时,Service 被缓存:它不是活动的,但它可以在下一个 Intent 到达时快速重新启动。

【讨论】:

    【解决方案4】:
    1. 像这样在构造函数中获取上下文:

      public GetDataTask(Context context) {}

    2. 使用方法创建接口:

      void onDataRetrieved(String data);

    3. 在创建任务对象的类中实现接口(例如MainActivity

    4. 将上下文投射到接口并调用 onDataRetrieved 方法

    【讨论】:

    • 这可能会导致内存泄漏。如果长时间运行的操作可以访问 Activity 的上下文,则 asynctask 将阻止在配置更改或用户出于某种原因从 Activity 回退的情况下对 Activity 进行垃圾收集。
    • 在向AsyncTask 发送Activity 时必须使用WeakReference&lt;Activity&gt; actWeak = new WeakReference&lt;&gt;(activity) 以避免内存泄漏,并在doInBackground 方法中使用Activity act = actWeak.get() 将其取回。
    【解决方案5】:

    在下面的代码中,我从 AsyncTask 返回一个字符串(directorName)。

    public class GetDirector {
        String id;
        private String baseURL = "http://www.omdbapi.com/?i=";
        private String finalURL = "";
        String theDirector;
    
        public GetDirector(String imdbID) throws ExecutionException, InterruptedException {
            id= imdbID;
            finalURL = baseURL + id + "&plot=full&r=json";
            System.out.println("GetDirector. finalURL= " + finalURL);
            theDirector = new GetDirectorInfo().execute().get();
        }
    
        public String getDirector (){
            return theDirector;
        }
    
        private class GetDirectorInfo extends AsyncTask<Void, Void,String> {
            @Override
            protected String doInBackground(Void... params) {
                String directorName = null;
    
                ServiceHandler sh = new ServiceHandler();
    
                // Making a request to url and getting response
                String jsonStr = sh.makeServiceCall(finalURL, ServiceHandler.GET);
                System.out.println("Act_DetailsPage. jsonStr= " + jsonStr);
    
                if (jsonStr != null) {
                    try {
                        JSONObject everything = new JSONObject(jsonStr);
    
                        directorName = everything.getString(JSON_Tags.TAG_DIRECTOR);
                        System.out.println("directorName= "+ directorName);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                } else {
                    System.out.println("Inside GetDirector. Couldn't get any data from the url");
                }
                return directorName;
            }
        }
    }
    

    【讨论】:

    • 通过使用 get 您将实现同步,从而违背了 AsyncTask 异步执行的全部目的。
    【解决方案6】:

    向任务的构造函数添加一个上下文参数,该参数将引用存储结果数据的对象。

    class PopulateArray extends AsyncTask<Integer, Integer, ArrayList<String>>
    {
        Context _context; // context may be what ever activity or object you want to store result in
        PopulateArray(Context context)
        {
            _context = context;
        }
        @Override
        protected ArrayList<String> doInBackground(Integer... integers)
        {
            ArrayList<String> data = new ArrayList<String>();
            //manipulate
            return data;
        }
    
        @Override
        protected void onPostExecute(ArrayList<String> strings)
        {
            _context.setData(strings);
        }
    }
    

    【讨论】:

      【解决方案7】:

      这 ONE LINER 为我工作:

      String result = MyasyncTask.execute(type, usrPhoneA, usrPWDA).get();
      

      【讨论】:

      • 当它返回一个 AsycTask 变量时如何工作?
      • PHP处理登录函数后,在变量“result”中返回操作结果。我读到这使它不是异步任务,但在我的情况下没关系。
      • 我得到了一个 asynctask 变量,用处不大
      【解决方案8】:

      将数据从 AsyncTask 发送到 UI 的唯一方法是 OttoEvent 总线。注册一个方法,该方法将在 UI 中的 @Subscribe 注释下处理结果,并在 AsyncTaskonPostExecute 方法中将结果处理到 postmessage 中。

      【讨论】:

        猜你喜欢
        • 2015-04-30
        • 1970-01-01
        • 1970-01-01
        • 2012-12-12
        • 1970-01-01
        • 1970-01-01
        • 2014-03-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多