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

时间:2012-12-03 18:59:31

标签: android android-asynctask media-player

我差不多完成了我的项目,只有一件事需要改进。

我的应用是一个音乐测验,可以检索有关作者,歌曲标题,previewUrl ecc的所有信息。来自Itunes商店使用适当的搜索API。

当用户选择要播放的类型时,我必须告诉用户等待4-5秒,因为计算会填充包含所有信息的列表。

我调用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();
    }

执行这些操作的类(扩展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();
        }
    }
}

问题:使用.get()方法使应用程序等待AsyncTask的整个计算,但它也阻止了UI线程!因此,用户将保持黑屏5秒或更长时间,这不是一件好事!

如果我不使用.get()方法,我会收到一个IndexOutOfBounds异常,因为我开始播放音乐流但列表尚未填充。

你可以建议我为这种情况做一个工作吗?

谢谢!

3 个答案:

答案 0 :(得分:3)

删除.get()它会阻止用户界面,直到完成任务。

启动任务,例如(播放视频),这取决于

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

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

答案 1 :(得分:0)

get()调用正在阻塞。来自文档:

  

如果需要等待计算完成,然后检索其结果。

你应该做的是在开始播放音乐之前等待计算完成。

如果您不想在类外面公开asynctask,可以在JSonCanzoni类中设置一个回调函数,以便调用asynctask的onPostExecute方法。

这样的东西
public interface CanzoniDownloadedInterface {
   public void onCanzoniDownloaded();
}


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

并在你的onPostExecute()中:

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

如果您让活动实现界面,您可以将其传递给您的班级。

onCanzoniDownloaded()实现是你需要开始播放的地方。

答案 2 :(得分:0)

最后我解决了我的问题,一些建议很好并且帮助了我很多!

我只是将startActivity指令移动到JsonCanzoni AsyncTask的onPostExecute,并更改了一些代码以适应新版本,它没问题! ;)