2

这是我在 stackoverflow 上的第一篇文章,我是 Android 新手。我已经在论坛上搜索了一个类似的问题,发现了这个问题:SAX 解析器进度监控。但不幸的是,它对我没有帮助。我的应用程序必须在日历中注册事件。我实现的第一件事是推进 xml 文件的下载。您可以在附加的代码中看到这一点。之后,我希望progressDialog 重置并开始跟踪解析的进度。如果这可以通过新的 setMessage() 和百分比值来完成,那就太好了。解析后的数据用于在日历中注册事件,同样使用相同的 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 "";
}

}

我希望我的第一篇文章的风格是好的,如果不是请告诉我。先感谢您

4

1 回答 1

0

我假设 XML非常大,并且解析至少需要30 秒。否则,帮自己一个忙,只显示一个不确定的指标;)

此外,为了简化您的代码,您可能希望使用URL.openStream()而不是 full features HttpClient,并切换到 simple GET(因为您不发送任何参数,我想知道为什么您的服务器需要 a POST)。

假设文件非常大(当然对于手机而言),必须考虑内存使用情况,并且您将从 DOM 切换到SAX 接口来处理 XML。SAX 在扫描流时为您提供了一个基于事件的接口,因此您不必在开始处理之前将整个文件加载到内存中。请记住,这是一个大文件,我们不想耗尽内存。

使用 SAX,我们可以在文件下载时解析文件,因此我们可以在计算总时间和剩余时间时关闭网络延迟。此时,进度可以近似为current item / total。您可以更新内部计数器以跟踪当前项目,但现在的问题是如何计算总数。你可以从以下方面思考

  1. 字节(例如processed 12932/2791290 Bytes
  2. 业务项目(例如processed 80/291 Items

在这两种情况下,您都需要服务器的一些支持。它应该提供Content-LengthHTTP 标头或序言(<manifest>在此代码段中调用):

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

AsyncTask部分很简单:你可以publishProgress()在你的内部使用doInBackground(),然后它会onProgressUpdate()在 UI 线程上调用。在此方法中,您将更新对话框的进度

最后几点说明:当屏幕旋转时(假定默认配置),您的活动被销毁,然后重新创建。请注意,显示的对话框Activity.showDialog由系统自动重新创建,但旧的AsyncTask继续运行,并且它可能保留对旧的(现在可能已销毁但不是垃圾收集)Activity 和旧对话框的引用。你必须自己解决这个问题,有太多的选择(包括 Loader 框架)。

我希望你现在明白这个任务并不像听起来那么简单,所以我的建议是仔细检查业务需求并提出最简单、更健壮的解决方案——毕竟,下载 XML 并显示进度对话框不是您的应用程序的主要任务;)

于 2012-10-24T14:03:21.187 回答