2012-12-03 78 views
0

我几乎完成了我的项目,只有一件事情还有待改进。Android Asynctask:等待整个计算而不会阻塞UI线程

我的应用程序是一个音乐测验,它可以检索关于作者,歌曲标题,previewUrl ecc的所有信息。从iTunes Store使用适用的搜索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(); 
     } 
    } 
} 

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

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

你能为我提出一个解决这个问题的方法吗?

谢谢!

+4

不要使用get;)只是显示用户一些微调,让他知道他会发生。在收到所有需要的数据后填入你的列表,隐藏微调并开始播放音乐:) – fgeorgiew

+0

如果你不想阻塞线程UI,你不能调用GET。 get() 如果需要等待计算完成,然后检索其结果。 – dougcunha

+1

我注意到在catch(IllegalArgumentException errore){}'你会尝试创建一个AlertDialog。理解这会使您的应用程序崩溃,并尝试从另一个线程访问UI ......您无法/不应该在'doInBackground()'中访问UI。 – Sam

回答

3

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

开始像(播放视频),这是在

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

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

好吧,我尝试过,但问题是,播放流的方法是在另一个活动类中,它必须访问UI的所有元素...我怎么能遵循你的建议? –

0

的get()调用阻止依赖AsycTask任何任务。从文档:

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

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

如果你不想在你的类之外暴露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()实现是您需要开始播放的地方。

0

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

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