简体   繁体   English

Android Asynctask:等待整个计算而不会阻塞UI线程

[英]Android Asynctask: wait for entire computation without blocking UI thread

I have almost finished my project, only one thing remain to improve. 我的项目几乎完成了,剩下的只有一件事需要改进。

My app is a music quiz, that retrieves all the informations about author, song title, previewUrl ecc. 我的应用程序是一个音乐测验,它检索有关作者,歌曲标题,previewUrl ecc的所有信息。 from the Itunes Store using the apposite Search API. 使用相应的Search API从Itunes商店中获取。

When a user choose a genre to play with, I must say to the user to wait for 4-5 seconds because of the computation that fills the List containing all the informations. 当用户选择要播放的流派时,我必须告诉用户等待4到5秒钟,因为计算将填充包含所有信息的列表。

I call the Asynctask that retrieve these informations like this: 我调用Asynctask来检索这些信息,如下所示:

JsonCanzoni recuperoCanzoni = new JsonCanzoni(arrayGenere,Canzone.this);

    try {
        recuperoCanzoni.execute().get();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

The class (extends Asynctask) that do these operation is the following: 执行这些操作的类(扩展了Asynctask)如下:

class JsonCanzoni extends AsyncTask<Void, Void, Void>
{
    List<String> canzoni = new ArrayList<String>(5);
    ProgressDialog pDialog;
    int[] arrayGenere;
    Context context;

    public JsonCanzoni(int[] arrayGenere,Context context) 
    {
        this.arrayGenere = arrayGenere;
        this.context = context;
    }



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

        pDialog.dismiss();
    }



    @Override
    protected void onPreExecute() 
    {
        super.onPreExecute();

        pDialog = new ProgressDialog(context);
        pDialog.setMessage("Preparazione round...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(false);
        pDialog.show();
    }



    protected Void doInBackground(Void... params) 
    {
        try
        {       
            int randomLookupId = 0;
            JSONObject obj;                         
            JSONArray jsonArray;    

            for(int i = 0; i < 10; i++)
            {
                canzoni = new ArrayList<String>();

                Log.d("GENERE", arrayGenere.toString());

                obj = getJSONObject(scegliClassifica(arrayGenere));
                jsonArray = obj.getJSONArray("resultIds");

                Log.d("dimensione JsonArray", String.valueOf(jsonArray.length()));
                try
                {
                    randomLookupId = new Random().nextInt(jsonArray.length()-1);
                }
                catch(IllegalArgumentException errore)
                {
                    new AlertDialog.Builder(context)
                    .setTitle("Connessione non attiva!")
                    .setMessage("Connessione di rete debole, uscita dal programma!");
                }
                Log.d("randomLookupID", String.valueOf(randomLookupId));

                JSONObject finalObj = getJSONObject("http://itunes.apple.com/lookup?id="+jsonArray.getString(randomLookupId)); 
                Log.d("URL","http://itunes.apple.com/lookup?id="+jsonArray.getString(randomLookupId));

                while(finalObj.getJSONArray("results").length() == 0)
                {
                    Log.d("Array VUOTO!!","Non è possibile!!!!");
                    randomLookupId = new Random().nextInt(jsonArray.length()-1);
                    Log.d("randomID rigenerato", String.valueOf(randomLookupId));

                    finalObj = getJSONObject("http://itunes.apple.com/lookup?id="+jsonArray.getString(randomLookupId));
                    Log.d("URL Rigenerato","http://itunes.apple.com/lookup?id="+jsonArray.getString(randomLookupId));
                }

                JSONArray finalJsonArray = finalObj.getJSONArray("results");

                JSONObject returnObj = finalJsonArray.getJSONObject(0);
                Log.d("returnObj.length",String.valueOf(returnObj.length()));

                canzoni.add(returnObj.getString("previewUrl"));
                canzoni.add(returnObj.getString("artistName"));
                canzoni.add(returnObj.getString("trackName"));
                canzoni.add(returnObj.getString("artistViewUrl"));
                canzoni.add(returnObj.getString("artworkUrl100"));
//              GTTapp app=(GTTapp) ((Activity)context).getApplication();
//              app.dieciCanzoni;
                Canzone.dieciCanzoni.add(i, new ArrayList<String>(canzoni));
            }
        }   
        catch (JSONException ignored)
        {
            ignored.getCause();
        }
        catch (MalformedURLException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }

    private String scegliClassifica(int[] arrayGenere)
    {
        int randomArrayPosition = new Random().nextInt(arrayGenere.length);
        return "http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/charts?cc=us&g="+arrayGenere[randomArrayPosition]+"&name=Songs&limit=200";
    }

    JSONObject getJSONObject(String url) throws IOException, MalformedURLException, JSONException
    {

        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();

        InputStream in = conn.getInputStream();

        try
        {
            StringBuilder sb = new StringBuilder();
            BufferedReader r = new BufferedReader(new InputStreamReader(new DoneHandlerInputStream(in)));
            for (String line = r.readLine(); line != null; line = r.readLine())
            {
                sb.append(line);
            }
            return new JSONObject(sb.toString());
        }
        finally
        {
            in.close();
        }
    }
}

THE PROBLEM: Using the .get() method make the app waiting for the entire computation of the AsyncTask, but it block the UI thread too!! 问题:使用.get()方法使应用程序等待AsyncTask的整个计算,但是它也会阻塞UI线程! So the user will remain with a black screen for 5 secs or more, and that's not a good thing! 因此,用户将在黑屏上停留5秒钟或更长时间,这不是一件好事!

If I don't use the .get() method, I receive an IndexOutOfBounds Exception, because I begin to play the music stream but the list is has not been filled yet. 如果我不使用.get()方法,则会收到IndexOutOfBounds异常,因为我开始播放音乐流,但列表尚未填写。

Can you suggest me a workarund for this situation? 您能建议我解决这种情况吗?

Thank you! 谢谢!

remove .get() it will block the UI till completion of the task. 删除.get()它将阻塞用户界面,直到任务完成。

Start any task like (playing video) which is dependent on AsycTask in 启动任何依赖于AsycTask任务(如播放视频)

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

    pDialog.dismiss();
      //You can start music stream here
}

The get() call is blocking. get()调用被阻止。 From the docs: 从文档:

Waits if necessary for the computation to complete, and then retrieves its result. 必要时等待计算完成,然后检索其结果。

What you should do is wait asynchronously the computation to finish before you start to play the music. 您应该做的是在开始播放音乐之前异步等待计算完成。

If you do not want to expose the asynctask outside your class, you can set a callback into your JSonCanzoni class to be called into the onPostExecute method of the asynctask. 如果不想在类外公开asynctask,则可以在JSonCanzoni类中设置一个回调,以在asynctask的onPostExecute方法中调用。

Something like 就像是

public interface CanzoniDownloadedInterface {
   public void onCanzoniDownloaded();
}


public JsonCanzoni(int[] arrayGenere, CanzoniDownloadedInterface callback, Context context){
    this.arrayGenere = arrayGenere;
    this.context = context;
    this.callback = callback;
}

and in your onPostExecute(): 并在您的onPostExecute()中:

@Override
protected void onPostExecute(Void result)
{
    super.onPostExecute(result);
    this.callback.onCanzoniDownloaded();
    pDialog.dismiss();
}

If you let your activity implement the interface, you can pass it to your class. 如果让您的活动实现该接口,则可以将其传递给您的班级。

The onCanzoniDownloaded() implementation is where you need to start playing. 您需要开始播放onCanzoniDownloaded()实现。

Finally I solved my problem, some advices were good and helped me a lot! 终于我解决了我的问题,一些建议很好,对我有很大帮助!

I simply moved the startActivity instruction to onPostExecute of JsonCanzoni AsyncTask, and changed some code to adapt to the new version and it's all right! 我只是将startActivity指令移至JsonCanzoni AsyncTask的onPostExecute,并更改了一些代码以适应新版本,没关系! ;) ;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM