2012-11-12 149 views
4

我剛剛開始使用android,我正在開發一個應該下載html文件內容的簡單應用程序。我建議使用AsyncTask,但我遇到了一個問題。在下面的代碼(我跟着一個教程代碼),我得到tv cannot be resolvedonPostExecute方法。如何訪問下載的文件?謝謝:使用Android AsyncTask下載html文件

public class FlashResults extends Activity { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     TextView tv = new TextView(this); 
     setContentView(tv); 
     readWebpage(tv);     
    } 


    protected class DownloadPage extends AsyncTask<String, Void, String> { 
      protected String doInBackground(String... urls) { 

      String responseStr = null; 

      try { 
       for (String url : urls) { 
       DefaultHttpClient httpClient = new DefaultHttpClient(); 
       HttpGet get = new HttpGet(url); 
       HttpResponse httpResponse = httpClient.execute(get); 
       HttpEntity httpEntity = httpResponse.getEntity(); 
       responseStr = EntityUtils.toString(httpEntity); 
       } 
      } catch (UnsupportedEncodingException e) { 

      } catch (ClientProtocolException e) { 

      } catch (IOException e) { 

      } 
      return responseStr; 
     } 

     protected void onPostExecute(String result) {   
      tv.setText(result); 
     } 
    } 

    public void readWebpage(View v) { 
     DownloadPage task = new DownloadPage(); 
     task.execute(new String[] { "http://seznam.cz" }); 
     } 

}

+1

方面的問題。 tv是在onCreate中聲明的局部變量(因此只能從那裏訪問)。使其成爲實例字段 – njzk2

回答

1

如果你想有一個變量是方法的外部訪問,你需要聲明它的方法之外。這是一個稱爲範圍的基本編程概念。

更改您的代碼看起來像這樣:

public class FlashResults extends Activity { 
private TextView tv; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    tv = new TextView(this); 
    setContentView(tv); 
    readWebpage(tv);     
} 

,這將是提供給任何內部FlashResults

0

您必須製作電視才能使其從子類訪問。

public class FlashResults extends Activity { 

     TextView tv; 

     @Override 
     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      tv = new TextView(this); 
      setContentView(tv); 
      readWebpage(tv);     
     } 


     protected class DownloadPage extends AsyncTask<String, Void, String> { 
       protected String doInBackground(String... urls) { 

       String responseStr = null; 

       try { 
        for (String url : urls) { 
        DefaultHttpClient httpClient = new DefaultHttpClient(); 
        HttpGet get = new HttpGet(url); 
        HttpResponse httpResponse = httpClient.execute(get); 
        HttpEntity httpEntity = httpResponse.getEntity(); 
        responseStr = EntityUtils.toString(httpEntity); 
        } 
       } catch (UnsupportedEncodingException e) { 

       } catch (ClientProtocolException e) { 

       } catch (IOException e) { 

       } 
       return responseStr; 
      } 

      protected void onPostExecute(String result) {   
       tv.setText(result); 
      } 
     } 

     public void readWebpage(View v) { 
      DownloadPage task = new DownloadPage(); 
      task.execute(new String[] { "http://seznam.cz" }); 
      } 
} 
+0

這是否會導致垃圾回收問題?如果用戶不斷地改變設備的方向並且實例變量沒有被釋放會怎麼樣? –

1

嘗試使文本視圖類級變量。

private TextView tv; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    tv = new TextView(this); 
    setContentView(tv); 
    readWebpage(tv);     
} 

的另一個選項是宣佈你的AsyncTask匿名,宣告TextView的作爲最終在相同的方法體作爲任務的聲明。 乾杯

3

一種方法是按照其他答案的建議並使tv實例級別。或者你可以做一個TextView字段中輸入您AsyncTask內,並通過引用到構造函數:

... 
public void readWebpage(TextView v) { 
    DownloadPage task = new DownloadPage(v); 
    task.execute(new String[] { "http://seznam.cz" }); 
} 
... 
protected class DownloadPage extends AsyncTask<String, Void, String> { 
    protected String doInBackground(String... urls) { 
     ... 
    } 
    TextView tv = null; 

    public DownloadPage(TextView tv){ 
     this.tv = tv; 
    } 
    ... 
} 
+0

我也更喜歡這種方法。 –

+0

@DavidT。 : 我不。對於單個「TextView」它可能工作得很好,但是如果OP在將來的某個時間點擴展UI並需要訪問/操作多個UI元素會怎樣? – Squonk

+1

@ dave.c:代碼有缺陷 - 您已經在'doInBackground(...)'方法中嵌入了'responseStr','tv'和構造函數的聲明。 – Squonk

4

到目前爲止建議將工作的其他答案的全部。不過,我想補充一對夫婦的其他注意事項:

  1. 如果只訪問此的onCreate和DownloadPage胡亞蓉內TextView的tv,您可以通過直接提供給它的DownloadPage的構造限制tv訪問
  2. 對於像DownloadPage AsyncTask這樣有用的東西,我通常會將它從作爲任何活動的內部類中移除,而是將其放入一個名爲「Utils」的公共類中,以供其他許多活動根據需要使用。 (代碼中的模塊化)
  3. 如果您要使用內部類(完全合法),那麼爲您的目標做好privatestatic總是一個好習慣。

事情是這樣的:

public class FlashResults extends Activity { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     TextView tv = new TextView(this); 
     setContentView(tv); 
     readWebpage(tv); 
    } 

    public void readWebpage(View v) { 
     DownloadPage task = new DownloadPage(tv); 
     task.execute(new String[] { "http://seznam.cz" }); 
    } 

    private static class DownloadPage extends AsyncTask<String, Void, String> { 

     private TextView textView; 
     public DownloadPage(TextView tv){ 
      textView = tv; 
     } 

     protected String doInBackground(String... urls) { 

     String responseStr = null; 

      try { 
       for (String url : urls) { 
       DefaultHttpClient httpClient = new DefaultHttpClient(); 
       HttpGet get = new HttpGet(url); 
       HttpResponse httpResponse = httpClient.execute(get); 
       HttpEntity httpEntity = httpResponse.getEntity(); 
       responseStr = EntityUtils.toString(httpEntity); 
       } 
      } catch (UnsupportedEncodingException e) { 

      } catch (ClientProtocolException e) { 

      } catch (IOException e) { 

      } 
      return responseStr; 
     } 

     protected void onPostExecute(String result) {   
      if (textView != null) { 
       textView.setText(result); 
      } 
     } 
    } 
} 

}

+1

爲什麼要使'AsyncTask'靜態'? – Squonk

+0

@Squonk有趣。再看看,也許它不需要是靜態的。不明確需要引用外部類的內部類應保持靜態。但我在這裏看到'tv'實例會保留活動引用的副本(僅僅是初始化'tv')。這更多的是一個良好的編碼實踐理論的建議,但可能不完全適用於這種特定的情況。你是對的 –

+1

是不是一個壞主意,通過一個小部件的參考 - 如果用戶旋轉手機,而該文件正在下載...它會崩潰。 –