2011-04-11 70 views
1

我一直在解決這個問題,我已經準備好將我的頭髮拉出來。我在這裏和網絡上發現了一些答案,說這是由於嘗試在線程中(而不是在UI線程中)使用View來完成某些操作而導致的。但我已經嘗試過所有我見過的想法(處理程序/新線程),但仍然無法實現。我在C編程多年是一種愛好,現在我是Java/Android的新手。我正在使用Eclipse和Android 2.1平臺進行編程。我希望我的應用程序能夠儘可能多地使用Android手機,並且我認爲我使用的所有功能都與API 1兼容。我還看到有一些名爲AsyncTask的內容,但會導致問題有舊手機的人?Android:出現錯誤「只有創建視圖層次結構的原始線程才能觸及其視圖」

所以這裏是我的應用程序。當我點擊一個按鈕時,該應用程序將聯機到一個網站並下載一個xml/rss提要。然後它解析它,並使用我創建的自定義適配器將數據放入列表視圖中。下載和解析可能需要1秒到15秒的時間,所以我想添加一個進度對話框。添加後,這就是我開始在這篇文章的標題中獲得錯誤信息的地方。該應用程序成功下載(我網上的示例xml文件有8條記錄,因此它非常小),但是在顯示列表視圖之前我看到了錯誤。所以我想我需要知道視圖的哪個部分導致錯誤,然後如何解決它。

下面是代碼(我已刪除所有來自最後幾個小時我的測試代碼,以便它是乾淨的,會越來越混亂,所有的你......和我):

@SuppressWarnings("serial") 
public class ClubMessageList extends ListActivity implements Serializable 
{ 
private static final String TAG = "DGMS News"; 
private ArrayList<CMessage> m_messages = null; 
private MessageAdapter m_adapter; 
private ProgressDialog m_ProgressDialog = null; 
private Runnable downloadMessages; 
// Need handler for callbacks to the UI thread 
final Handler mHandler = new Handler(); 

@SuppressWarnings("unchecked") 
@Override 
public void onCreate(Bundle icicle) 
{ 
    Log.i(TAG, "Starting the ClubMessageList activity"); 
    super.onCreate(icicle); 

    setContentView(R.layout.list); 
    setTitle("DGMS News - Clubs"); 

    try 
    { 
     // check to see if we already have downloaded messages available in the bundle 
     m_messages = (ArrayList<CMessage>) ((icicle == null) ? null : icicle.getSerializable("savedMessages")); 

     // if there are no messages in the bundle, download them from the web and then display them 
     if (m_messages == null) 
     { 
      m_messages = new ArrayList<CMessage>(); 
      this.m_adapter = new MessageAdapter(this, R.layout.row_club, (ArrayList<CMessage>) m_messages); 
      setListAdapter(this.m_adapter); 

      downloadMessages = new Runnable(){ 
       public void run() { 
        getMessages(); 
       } 
      }; 
      Thread thread = new Thread(null, downloadMessages, "DownloadMessages"); 
      thread.start(); 
      m_ProgressDialog = ProgressDialog.show(ClubMessageList.this,  
        "Please wait...", "Retrieving 2010 Show data ...", true); 
     } 
     else // messages were already downloaded, so display them in the listview (don't download them again) 
     { 
      Log.i("DGMS News", "Starting activity again. Data exists so don't retrieve it again."); 
      m_adapter = new MessageAdapter(this, R.layout.row_club, (ArrayList<CMessage>) m_messages); 
      this.setListAdapter(m_adapter); 
     } 
    } 
    catch (Throwable t) 
    { 
     Log.e("DGMS News",t.getMessage(),t); 
    } 
} 

private Runnable returnRes = new Runnable() 
{ 
    public void run() 
    { 
     if(m_messages != null && m_messages.size() > 0) 
     { 
      m_adapter.notifyDataSetChanged(); 
      for(int i=0;i<m_messages.size();i++) 
       m_adapter.add(m_messages.get(i)); 
     } 
     m_ProgressDialog.dismiss(); 
     m_adapter.notifyDataSetChanged(); 
    } 
}; 

private void getMessages() 
{ 
    try 
    { 
     m_messages = new ArrayList<CMessage>(); 
     ClubFeedParser parser = ClubFeedParserFactory.getParser(); 
     m_messages = parser.parse(); 
     for(int i = 0; i < m_messages.size(); i++) 
      m_adapter.add(m_messages.get(i)); 
    } 
    catch (Exception e) 
    { 
     Log.e("DGMS News", e.getMessage()); 
    } 
    runOnUiThread(returnRes); 
} 

protected void onSaveInstanceState(Bundle outState) 
{ 
    super.onSaveInstanceState(outState); 
    outState.putSerializable("savedMessages", (Serializable) m_messages); 
} 

@Override 
protected void onListItemClick(ListView l, View v, int position, long id) 
{ 
    super.onListItemClick(l, v, position, id); 
    Intent intent = new Intent(ClubMessageList.this, ClubDetails.class); 
    // Add all info about the selected club to the intent 
    intent.putExtra("title", m_messages.get(position).getTitle()); 
    intent.putExtra("location", m_messages.get(position).getLocation()); 
    intent.putExtra("website", m_messages.get(position).getLink()); 
    intent.putExtra("email", m_messages.get(position).getEmail()); 
    intent.putExtra("city", m_messages.get(position).getCity()); 
    intent.putExtra("contact", m_messages.get(position).getContact()); 
    intent.putExtra("phone", m_messages.get(position).getPhone()); 
    intent.putExtra("description", m_messages.get(position).getDescription()); 

    startActivity(intent); 
} 

private class MessageAdapter extends ArrayAdapter<CMessage> implements Serializable 
{ 
    private ArrayList<CMessage> items; 

    public MessageAdapter(Context context, int textViewResourceId, ArrayList<CMessage> items) 
    { 
     super(context, textViewResourceId, items); 
     this.items = items; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) 
    { 
     View v = convertView; 
     if (v == null) 
     { 
      LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      v = vi.inflate(R.layout.row_club, null); 

      CMessage m = items.get(position); 
      if (m != null) 
      { 
       TextView ltt = (TextView) v.findViewById(R.id.ltoptext); 
       TextView rtt = (TextView) v.findViewById(R.id.rtoptext); 
       TextView lbt = (TextView) v.findViewById(R.id.lbottext); 

       if (ltt != null) 
        ltt.setText(m.getTitle()); 

       if (rtt != null) 
        rtt.setText(m.getLocation()); 

       if (lbt != null) 
        lbt.setText(m.getCity() + ", CO"); 

       //if (rbt != null) 
        ; // not used in this list row 
      } 
     } 
     return v; 
    } 
} 
} 

由於我說,所有這些代碼工作良好,直到我添加了前幾天在另一個網站上找到的進度對話框。

我很感激任何和所有的幫助,雖然我已經去過Android Developers網站查看線程,處理程序等,它讓我越來越困惑。實際的代碼更改會很棒。 :-)今天看到這麼多網站後,我的頭很痛。

謝謝!

鮑勃

回答

2
   runOnUiThread(new Runnable() { 
      public void run() { 
        m_adapter.notifyDataSetChanged(); 

        m_adapter.add(m_messages.get(i)); 

       m_ProgressDialog.dismiss(); 
       m_adapter.notifyDataSetChanged(); 


      } 
     }); 

所有你的UI代碼必須在runOnUiThread中去。你得到的錯誤是你試圖從活動UI線程以外的其他線程更新UI。

此代碼中的線程導致此問題。

   private Runnable returnRes = new Runnable() 
      { 
       public void run() 
       { 
       if(m_messages != null && m_messages.size() > 0) 
      { 
       m_adapter.notifyDataSetChanged(); 
       for(int i=0;i<m_messages.size();i++) 
       m_adapter.add(m_messages.get(i)); 
       } 
      m_ProgressDialog.dismiss(); 
      m_adapter.notifyDataSetChanged(); 
     } 
      }; 
+0

@ user593424:謝謝!這解決了它。而且我實際上在我的代碼中加載了兩次列表,所以我也修復了這個問題。非常感謝! – Bobert 2011-04-15 04:34:42

0

使用AsyncTask。幾乎沒有手機在這一點上使用Android 1.0/1.1(唯一的手機甚至與Android < 1.5一起提供的是HTC G1,並且大多數是在一段時間之前升級了OTA)。如果您確實需要支持這些設備,則可以使用相同的UserTask。有關更多信息,請參閱this article。並看到關於確保您從主線程更新UI的十幾個SO問題。

+0

Hi Yoni!謝謝您的回答。我會盡快嘗試你的建議。如果我能使它工作,我會用它替換現有的代碼。 :-) – Bobert 2011-04-15 04:36:51

相關問題