2012-10-24 46 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并显示进度对话框不是您应用程序的主要任务;)