2012-10-24 43 views
2

這是我在stackoverflow上的第一篇文章,我是Android新手。我已經搜索了類似的問題論壇,並發現這一個:SAX parser progress monitoring。 但不幸的是它並沒有幫助我。 我的應用程序必須在日曆中註冊事件。 我取得的第一件事就是進行xml文件的下載。你可以在附加的代碼中看到它。 之後,我希望progressDialog重置並開始跟蹤解析的進度。如果可以用新的setMessage()和一個百分比值來完成,那將會很棒。 解析完數據後用於在日曆中註冊事件,再次使用相同的progressDialog。解析xml時使用progressDialog

但起初我想知道如何跟蹤解析的進度。如果有一些想法會很好。 謝謝

public class AddCoursesToCalendar extends Activity { 

public static final int progress_bar_type = 0; 
ArrayList<String> selectedCourses; 
public ProgressDialog progressDialog; 

@Override 
public void onCreate(Bundle bundle) { 
    super.onCreate(bundle); 
    setContentView(R.layout.activity_add_courses_to_calendar); 
    if (bundle != null) { 
     selectedCourses = bundle.getStringArrayList("selectedCourses"); 
    } 
    new GetDataTask().execute(); 
} 

private Boolean isOnline() { 
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
    NetworkInfo ni = cm.getActiveNetworkInfo(); 
    if (ni != null && ni.isConnected()) 
     return true; 

    return false; 
} 

@Override 
protected Dialog onCreateDialog(int id) { 
    switch (id) { 
    case progress_bar_type: 
     progressDialog = new ProgressDialog(this); 
     progressDialog.setMessage("Downloading file. Please wait..."); 
     progressDialog.setIndeterminate(false); 
     progressDialog.setMax(100); 
     progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
     progressDialog.setCancelable(true); 
     progressDialog.show(); 
     return progressDialog; 
    default: 
     return null; 
    } 
} 

public class GetDataTask extends AsyncTask<String, String, Integer> { 

    private static final String URL = "http://10.0.2.2/WIN2.xml"; 
    private static final String KEY_ITEM = "Item"; 
    private static final String KEY_DAUER = "Duration"; 
    private static final String KEY_ENDE = "End"; 
    private static final String KEY_SEMESTER_DOZENT = "Location"; 
    private static final String KEY_RAUMMITSTOCKWERK = "Organizer"; 
    private static final String KEY_START = "Start"; 
    private static final String KEY_VERANSTALTUNGSNAME = "Subject"; 

    @Override 
    protected void onPreExecute() { 
     super.onPreExecute(); 
     onCreateDialog(progress_bar_type); 
    } 


    @Override 
    protected Integer doInBackground(String... params) { 

     if (isOnline()) { 
      XMLParser parser = new XMLParser(); 
      String xml = parser.getXmlFromUrl(URL, this); 
      long id = 0; 

      Document doc = parser.getDomElement(xml, this); 

      NodeList nl = doc.getElementsByTagName(KEY_ITEM); 

      for (int i = 0; i < nl.getLength(); i++){ 
       Element e = (Element) nl.item(i); 

       for (String s : selectedCourses) { 
        if (parser.getValue(e, KEY_VERANSTALTUNGSNAME) 
          .contains(s)) { 

         String dozent = null; 
         int spaceIndex = parser.getValue(e, 
           KEY_SEMESTER_DOZENT).indexOf(" "); 
         int lastIndex = parser.getValue(e, 
           KEY_SEMESTER_DOZENT).length(); 
         if (spaceIndex != -1) { 
          dozent = parser 
            .getValue(e, KEY_SEMESTER_DOZENT) 
            .substring(spaceIndex, lastIndex); 
         } 

         addEvent(
           parser.getValue(e, KEY_VERANSTALTUNGSNAME), 
           parser.getValue(e, KEY_START), 
           parser.getValue(e, KEY_ENDE), 
           parser.getValue(e, KEY_DAUER), 
           dozent, 
           parser.getValue(e, KEY_RAUMMITSTOCKWERK), 
           id); 

        } id++; 
       } 
      } 
     } else { 
      Toast.makeText(AddCoursesToCalendar.this, "No Connection..", 
        Toast.LENGTH_LONG).show(); 
     } 
     return 1; 
    } 

     public void doProgress(String value){ 
      publishProgress(value); 
     } 


    @Override 
    protected void onPostExecute(Integer result) { 
     progressDialog.dismiss(); 
     super.onPostExecute(result); 
    } 

    protected void onProgressUpdate(String... progress) { 
     progressDialog.setProgress(Integer.parseInt(progress[0])); 
    } 

    protected void addEvent(String title, String start, String end, 
      String duration, String organizer, String location, long id) { 

     SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); 
     long startInMillis = 0, endInMillis = 0; 
     Date startDate, endDate; 
     try { 
      startDate = format.parse(start); 
      endDate = format.parse(end); 
      startInMillis = startDate.getTime(); 
      endInMillis = endDate.getTime(); 
     } catch (ParseException e1) { 
      e1.printStackTrace(); 
     } 

     TimeZone timeZone = TimeZone.getDefault(); 
     ContentResolver cr = getContentResolver(); 
     ContentValues values = new ContentValues(); 
     values.put(CalendarContract.Events.EVENT_TIMEZONE, timeZone.getID()); 
     values.put(CalendarContract.Events.DTSTART, startInMillis); 
     values.put(CalendarContract.Events.DTEND, endInMillis); 
     values.put(CalendarContract.Events.TITLE, title); 
     values.put(CalendarContract.Events.EVENT_LOCATION, "Location: " + location); 
     values.put(CalendarContract.Events.CALENDAR_ID, 1); 
     Uri uri = cr.insert(CalendarContract.Events.CONTENT_URI, values); 
     ContentUris.withAppendedId(uri, id); 
    } 

} 

}

而且這裏的類負責下載和解析:

public class XMLParser { 

public String getXmlFromUrl(String url, AddCoursesToCalendar.GetDataTask task) { 
    String xml = null; 

    try { 
     int count; 
     DefaultHttpClient httpClient = new DefaultHttpClient(); 
     HttpPost httpPost = new HttpPost(url); 
     HttpResponse httpResponse = httpClient.execute(httpPost); 

     HttpEntity httpEntity = httpResponse.getEntity(); 
     long lenghtOfFile = httpEntity.getContentLength(); 

     byte data[] = new byte[1024]; 
     long total = 0; 
     while ((count = httpEntity.getContent().read(data)) != -1) { 
      total += count; 
      task.doProgress(""+(int)((total*100)/lenghtOfFile)); 
     } 

     xml = EntityUtils.toString(httpEntity, "UTF-8"); 

    } catch (UnsupportedEncodingException e) { 
     e.printStackTrace(); 
    } catch (ClientProtocolException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return xml; 
} 

public Document getDomElement(String xml, AddCoursesToCalendar.GetDataTask task) { 
    Document doc = null; 
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
    try { 

     DocumentBuilder db = dbf.newDocumentBuilder(); 
     InputSource is = new InputSource(); 
     StringReader reader = new StringReader(xml); 
     is.setCharacterStream(reader); 
     doc = db.parse(is); 

    } catch (ParserConfigurationException e) { 
     Log.e("Error: ", e.getMessage()); 
     return null; 
    } catch (SAXException e) { 
     Log.e("Error: ", e.getMessage()); 
     return null; 
    } catch (IOException e) { 
     Log.e("Error: ", e.getMessage()); 
     return null; 
    } 
    return doc; 
} 

public String getValue(Element item, String str) { 
    NodeList n = item.getElementsByTagName(str); 
    return this.getElementValue(n.item(0)); 
} 

public final String getElementValue(Node elem) { 
    Node child; 
    if (elem != null) { 
     if (elem.hasChildNodes()) { 
      for (child = elem.getFirstChild(); child != null; child = child 
        .getNextSibling()) { 
       if (child.getNodeType() == Node.TEXT_NODE) { 
        return child.getNodeValue(); 
       } 
      } 
     } 
    } 
    return ""; 
} 

}

我希望我的第一篇文章的風格是好的,如果不要請告訴我。謝謝你在前進

+1

您可以使用asynctask來獲得所需的結果。 – Raghunandan

+0

就「問」風格而言..它不壞,但會更好,如果你能想出一個普遍的問題,比如「如何跟蹤解析XML文件並顯示進度?」之類的東西那個...... :) – Farhan

+0

@ Raghunandan:感謝您的發帖,我已經使用了asynctask。我想知道如何檢查onPreExecute()中的解析 – Markus

回答

0

我假設XML是非常大和解析需要至少 30秒。否則,請你幫個忙,並只顯示一個不確定的指標;)

此外,爲了簡化代碼,您可能需要使用URL.openStream(),而不是一個全功能的HttpClient,並切換到一個簡單的GET(因爲你不知道發送任何參數我想知道爲什麼你的服務器需要一個POST)。

假設文件是​​非常大的文件(當然是電話),必須考慮內存使用情況,並且您將從DOM切換到the SAX interface以處理XML。 SAX在掃描流時爲您提供基於事件的界面,因此您無需在開始處理之前將整個文件加載到內存中。記住,這是一個很大的文件,我們不想耗盡內存。

使用SAX,我們可以在文件下載的時候解析文件,因此我們可以在計算總計和剩餘時間時關閉網絡延遲。此時,進度可近似爲當前料品/總計。您可以更新內部計數器以跟蹤當前項目,但現在的問題是如何計算總計。您可以認爲

  1. 字節爲單位(如processed 12932/2791290 Bytes
  2. 業務項目(例如processed 80/291 Items

在您需要從服務器的一些支持這兩種情況。它應該提供一個Content-Length HTTP報頭或(在這個片段中稱爲<manifest>)序言:

<root> 
    <manifest> 
    <total>291</total> 
    </manifest> 
    ... 
    <item id="foobar1"> 
    <foo>Foo</foo> 
    <bar>Bar</bar> 
    </item> 
    ... 
</root> 

AsyncTask部分是很容易的:你可以用publishProgress()doInBackground()裏面,反過來它會調用onProgressUpdate()的UI線。在這個方法裏面,你會對話框的update the progress

只是幾個最後的筆記:當屏幕旋轉(假定爲默認配置)時,您的活動被破壞,然後重新創建。請注意,系統會自動重新創建通過Activity.showDialog顯示的對話框,但舊的AsyncTask會繼續運行,並且可能會保留對舊的(現在可能已銷燬但未收集垃圾)活動和舊對話框的引用。你必須自己完成這個工作,有too many alternatives(包括Loader框架)。

我希望您現在明白,任務並不像聽起來那麼簡單,所以我的建議是仔細檢查業務需求並提出最簡單,更強大的解決方案 - 畢竟,下載XML並顯示進度對話框不是您應用程序的主要任務;)