【问题标题】:Android Class with sub-class AsyncTask wait for the postExecute before returning the value具有子类 AsyncTask 的 Android 类在返回值之前等待 postExecute
【发布时间】:2013-12-09 12:03:39
【问题描述】:

目前我正在为我的项目做一些事情,其中​​我创建了一个单独的类,它将只处理 Asynctask 并获取我传递的 web 服务的值,并且该类应该将 JSON 响应作为字符串返回。现在我已经使用taskName.execute().get(); 实现了它,它会等待任务完成,但问题是它也在等待任务完成,然后再显示屏幕布局。使我的 progressDialog 无用并导致切换屏幕延迟。这是我现在的代码:

对于带有 AsyncTask 的类:

public class UtilGetResponse {

    Context context;
    Map hash_values = new HashMap();
    int DialogType;
    String response;
    /*  
        PLAN FOR DialogTypes:
    * 0 - Standard Please wait dialog
    * 1 - Progress dialog
    * 2 - Camera upload dialog
    * */


    InputStream is = null;
    StringBuilder string_builder = null;


    public UtilGetResponse(Map values, Context baseContext, int type){
        /*initialize class and pass the hash values for parameters*/
        context = baseContext;
        hash_values.putAll(values);
        DialogType = type;
    }

    public String startTask(){
        //TODO CASE WHEN BASED ON THE DIALOG TYPE SPECIFIED
        Utilities util = new Utilities();

        if(util.isOnline(context)){
            try {
                new UploaderTaskStandard().execute().get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return response; //THE RESPONSE ONLY SHOW ONCE THE WHOLE TASK IS COMPLETED
    }


    public class UploaderTaskStandard extends AsyncTask<Map, Void, Void> {
        ProgressDialog simpleDialog;

        @Override
        protected void onPreExecute() {
            /*Do something before the async task starts*/
            simpleDialog = new ProgressDialog(context);
            simpleDialog.setMessage("Please wait");
            simpleDialog.show();
        }

        @Override
        protected Void doInBackground(Map... maps) {
            uploadData();
            return null;
        }

        protected void onPostExecute(Void v) {
            /*Do something after the task is complete*/
            simpleDialog.dismiss();
        }
    }

    private void uploadData() {
        response = "null";
        String url = hash_values.get("url").toString().replace(" ", "%20"); //get the URL replacing the space with %20

        //If the user is trying to upload a file use this part
        try {
            HttpClient client = new DefaultHttpClient();
            HttpPost post = new HttpPost(url);
            MultipartEntity mpEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);

                /*This will convert the hashMap sent into individual part per key per value*/
            Set set = hash_values.entrySet();
            Iterator iterator = set.iterator();

                /*do a loop passing all the data on a string*/
            while(iterator.hasNext()) {
                Map.Entry mapEntry = (Map.Entry)iterator.next();
                String keyword = String.valueOf(mapEntry.getKey());
                String value = String.valueOf(mapEntry.getValue());

                    /*this will check if the passed data is a URL, file or a simple value*/
                if(!keyword.equals("url")){
                    if(value.matches("(.*)/(.*)")){
                        File file = new File(value);
                        Log.v("Does this exists?",String.valueOf(file.exists()));
                        if(file.exists()){
                            FileBody upload_file;
                            upload_file = new FileBody(file);
                                /*not url but file*/
                            mpEntity.addPart(keyword, upload_file);
                        }else{
                                /*not url and not file*/
                            mpEntity.addPart(keyword, new StringBody(value));
                        }
                    }else{
                            /*not URL and not file*/
                        mpEntity.addPart(keyword, new StringBody(value));
                    }
                }
            }

            post.setEntity(mpEntity);
            HttpResponse response = client.execute(post);
            HttpEntity resEntity = response.getEntity();

            is = resEntity.getContent();
        } catch (Exception e) {
            e.printStackTrace();
            response = "null";
        }

        /*convert JSON to string*/
        try{
            BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8);
            string_builder = new StringBuilder();
            String line = "0";

            while ((line = reader.readLine()) != null) {
                string_builder.append(line + "\n");
            }
            is.close();
            response = string_builder.toString();
        }catch(Exception e){
            e.printStackTrace();
        }

    }

}

并称之为:

Map hash_values = new HashMap();

        try{
            HashMap params = new HashMap<String,String>();
            params.put("param1", "YOUR_PARAM");
            params.put("url", "YOUR_WEBSERVICE_URL");

            //pass parameters
            hash_values.putAll(params);
            //start async task

            UtilGetResponse util = new UtilGetResponse(hash_values, getActivity(), 0);
            String result = util.startTask();

            Log.v("The result string",result);

        }catch (Exception e){
            e.printStackTrace();
            e.getCause();
            Toast.makeText(getActivity(), "Oops problem", Toast.LENGTH_SHORT).show();
        }

有没有一种方法可以让我正确地执行此操作,而无需真正等待整个任务完成后再移动到下一个屏幕?我正在考虑使用 Handler,但我对如何使用它并不是很熟悉。

【问题讨论】:

    标签: java android android-asynctask


    【解决方案1】:

    你的问题是使用这个

    new UploaderTaskStandard().execute().get();
    

    虽然你使用了 AsynTask,但仍然让系统等待结果,这与你的要求不符,你需要的是一种交付机制,一旦结果准备好就会通知你。您可以采取两种方法中的任何一种。

    change to this, and implement one of below mechanism.
    new UploaderTaskStandard().execute();
    
    1. 实现处理程序,并在结果可用后发回结果。
    2. 实现观察者设计模式,您可以使用onResultReady 等方法创建一个接口,并将实现上述接口的类的对象传递给您的方法startTask,并在可用时从AsyncTask onPostExecute 发回结果通过接口机制。

    通过接口将非常容易,这样您的代码将独立于您的网络逻辑,示例代码如下

    // Observer listener interface design
    interface ResultListener{
        // You can overload this method with data type you want to return
        public void onResultReceived();
    
        // Use them in a proper way for sending error message back to your program
        public void onTaskCancelled();
        public void onError();
    
    }
     // This will be your new method signature
     public String startTask(ResultListener listener){
         // Call it liske this, passing listener reference
         new UploaderTaskStandard().execute(listener);
     }
    
     // This is your AsyncTask model
     public class UploaderTaskStandard extends AsyncTask<ResultListener, Void, Void> {
    
         ResultListener listener;
    
            @Override
            protected Void doInBackground(ResultListener... maps) {
                this.listener = maps[0];
                uploadData();
                return null;
            }
    
            protected void onPostExecute(Void v) {
                /*Do something after the task is complete*/
                simpleDialog.dismiss();
                // Notify back to calling program
                listener.onResultReceived();
            }
    
     }
    

    【讨论】:

    • 我有这个想法,但我真的不知道我应该如何实现它。我对第二个选项更感兴趣。非常感谢您提供有关如何实现它的链接。 :)
    • 刚刚发布了一个为您工作的示例,如果您有任何疑问,请查看并告诉我。
    猜你喜欢
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 2021-06-20
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    相关资源
    最近更新 更多