0

Android アプリで XML(RSS) ファイルを解析する方法に関するチュートリアルに従いました。以下は動作している私のコードですが、かなり時間がかかります。私は何か間違ったことをしているのですか、それとも遅くなるような方法でやっていますか? 30 ~ 35 の記事をロードするのに 7 ~ 10 秒かかります...一見長すぎますし、ユーザーがセクションを切り替えるたびに待つには長すぎます (別のフィードが読み込まれます)。

1時間ごとに新しいデータのみをプルするように設定しています...など...しかし、最初の時間は通常10秒かかります。それまでに、ユーザーはアプリがクラッシュしたと思います...など.

  • 私はAsyncTaskでこれをやっています
  • この時点では画像をダウンロードしていません
  • これはコードの遅い部分です (インターネットや表示などではありません)。

TLDR:
このコードは遅すぎる - なぜ?:

package com.mysite.utilities;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

public class RSSHandler extends DefaultHandler
{

    // creats a news item class to hold data within loop
    public class NewsItem
    {
        public String title;
        public String subhead;
        public String link;
        public String byline;
        public String description;
        public String storytext;
        public String cmsstoryid;
        public String pubDate;
        public String keyword;
        public String category;
        public String subcategory;
        public String slotreference;
        public String lastModTime;
        public ArrayList<PhotoItem> photos = new ArrayList<PhotoItem>();

        @Override
        public String toString()
        {
            return title;
        }
    }

    //creates a photo item class to hold image data within loop
    public class PhotoItem
    {
        public String photoid; //tribs id
        public String caption;
        public String height;
        public String width;
        public String photo; //full path to photo
        public String thumbnail; //full path to thumbnail
        public int articleid;
        public String photolastmodified;

        @Override
        public String toString()
        {
            return photo;
        }
    }

    //creates instances of classes to be used in loop
    private StringBuffer buf; //to hold element characters with loop
    private ArrayList<NewsItem> feedItems;
    private NewsItem item;
    private PhotoItem photoitem;

    //initialize variables of whether or not it's within an item (or photo item)
    private boolean inItem = false;
    private boolean inPhotoItem = false;

    //
    public ArrayList<NewsItem> getParsedItems() {
        return feedItems;
    }

    //Called at the head of each new element
    @Override
    public void startElement(String uri, String name, String qName, Attributes atts)
    {
        //creates an array of news items
        if ("channel".equals(name))
        {
            feedItems = new ArrayList<NewsItem>();
        }
        //creates a news item and toggles "in news item" to on
        else if ("item".equals(name))
        {
            item = new NewsItem();
            inItem = true;
        }
        //creates a photo item and toggles "in photo item" to on
        else if ("image".equals(name))
        {
            photoitem = new PhotoItem();
            inPhotoItem = true;
        }
        //starts a new string buffer if matches an elemnt we want from news item
        else if (
            ("title".equals(name) ||
            "subhead".equals(name) ||
            "link".equals(name) ||
            "byline".equals(name) ||
            "description".equals(name) ||
            "storytext".equals(name) ||
            "keyword".equals(name) ||
            "cmsstoryid".equals(name) ||
            "pubDate".equals(name) ||
            "category".equals(name) ||
            "subcategory".equals(name) ||
            "lastModTime".equals(name) ||
            "slotreference".equals(name)
            )
            && inItem)
        {
            buf = new StringBuffer();
        }
        //starts an a new string buffer if it matches an element we want from image item
        else if(
            ("caption".equals(name) ||
            "photoid".equals(name) ||
            "height".equals(name) ||
            "width".equals(name) ||
            "photo".equals(name) ||
            "photolastmodified".equals(name) ||
            "thumbnail".equals(name)
            )
            && inPhotoItem)
        {
            buf = new StringBuffer();
        }
    }

    //Called at the tail of each element end
    @Override
    public void endElement(String uri, String name, String qName)
    {       
        if ("item".equals(name))
        {
            feedItems.add(item);
            inItem = false;
        }
        else if ("image".equals(name))
        {
            try {
                item.photos.add(photoitem);
            } catch (Exception e) {
                System.out.println(e);
            }
            inPhotoItem = false;
        }
        else if (inItem)
        {
            if (inPhotoItem)
            {
                if ("caption".equals(name)) { photoitem.caption = buf.toString(); }
                else if ("photoid".equals(name)) { photoitem.photoid = buf.toString(); }
                else if ("height".equals(name)) { photoitem.height = buf.toString(); }
                else if ("width".equals(name)) { photoitem.width = buf.toString(); }
                else if ("photo".equals(name)) { photoitem.photo = buf.toString(); }
                else if ("photolastmodified".equals(name)) { photoitem.photolastmodified = buf.toString(); }
                else if ("thumbnail".equals(name)) { photoitem.thumbnail = buf.toString(); }
            }
            else if ("title".equals(name)) { item.title = buf.toString(); }
            else if ("subhead".equals(name)) { item.subhead = buf.toString(); }
            else if ("link".equals(name)) { item.link = buf.toString(); }
            else if ("byline".equals(name)) { item.byline = buf.toString(); }
            else if ("description".equals(name)) { item.description = buf.toString(); }
            else if ("storytext".equals(name)) { item.storytext = buf.toString(); }
            else if ("keyword".equals(name)) { item.keyword = buf.toString(); }
            else if ("cmsstoryid".equals(name)) { item.cmsstoryid = buf.toString(); }
            else if ("pubDate".equals(name)) { item.pubDate = buf.toString(); }
            else if ("category".equals(name)) { item.category = buf.toString(); }
            else if ("subcategory".equals(name)) { item.subcategory = buf.toString(); }
            else if ("lastModTime".equals(name)) { item.lastModTime = buf.toString(); }
            else if ("slotreference".equals(name)) { item.slotreference = buf.toString(); }

        }
        else
        {
            buf = null;
        }

    }

    //Called with character data inside elements
    @Override
    public void characters(char ch[], int start, int length)
    {
        //Don't bother if buffer isn't initialized
        if(buf != null)
        {
            for (int i=start; i<start+length; i++)
            {
                buf.append(ch[i]);
            }
        }
    }
}

これまでの私の更新されたコード(まだ速度は向上していません):

package com.sltrib.utilities;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

import android.util.Log;

public class RSSHandler extends DefaultHandler
{

    // creats a news item class to hold data within loop
    public class NewsItem
    {
        public String title;
        public String subhead;
        public String link;
        public String byline;
        public String description;
        public String storytext;
        public String cmsstoryid;
        public String pubDate;
        public String keyword;
        public String category;
        public String subcategory;
        public String slotreference;
        public String lastModTime;
        public ArrayList<PhotoItem> photos = new ArrayList<PhotoItem>();

        @Override
        public String toString()
        {
            return title;
        }
    }

    //creates a photo item class to hold image data within loop
    public class PhotoItem
    {
        public String photoid; //tribs id
        public String caption;
        public String height;
        public String width;
        public String photo; //full path to photo
        public String thumbnail; //full path to thumbnail
        public int articleid;
        public String photolastmodified;

        @Override
        public String toString()
        {
            return photo;
        }
    }

    //creates instances of classes to be used in loop
    private StringBuilder buf; //to hold element characters with loop
    private ArrayList<NewsItem> feedItems;
    private NewsItem item;
    private PhotoItem photoitem;

    //initialize variables of whether or not it's within an item (or photo item)
    private boolean inItem = false;

    private int currentTagId = 0;

    //
    public ArrayList<NewsItem> getParsedItems() {
        return feedItems;
    }


    @Override
    public void startDocument()
    {
        feedItems = new ArrayList<NewsItem>(); //creates an array to hold feed items
    }


    //Called at the head of each new element
    @Override
    public void startElement(String uri, String name, String qName, Attributes atts)
    {
        //gets the id of the current tag
        currentTagId = 0;
        String tmpId = atts.getValue("id");
        if(tmpId != null)
        {
            currentTagId = Integer.parseInt(tmpId);
        }

        //creates a news item
        if (currentTagId == 99) // <item>
        {
            item = new NewsItem();
            inItem = true;
        }

        //creates a photo item
        else if (currentTagId == 21) { // <image>
            photoitem = new PhotoItem();
        }

        //creates a string builder if it's a tag within an article or a photo
        else if (inItem && currentTagId > 0 && currentTagId < 29)
        {
            buf = new StringBuilder();
        }
    }


    //Called at the tail of each element end
    @Override
    public void endElement(String uri, String name, String qName)
    {

        // it's not getting the tag id - how?

        Log.d("XML", "endElement:" + Integer.toString(currentTagId));

        if (currentTagId == 99)  // </item>
        {
            Log.d("XML", "Should be adding item: " + item.title);
            feedItems.add(item);
            inItem=false;
        }

        else if (currentTagId == 21) // </image>
        {
            try {
                item.photos.add(photoitem);
            } catch (Exception e) {
                System.out.println(e);
            }
        }
        else
        {
            switch(currentTagId)
            {
                case 1: item.title = buf.toString(); break;
                case 2: item.subhead = buf.toString(); break;
                case 3: item.link = buf.toString(); break;
                case 4: item.byline = buf.toString(); break;
                case 5: item.description = buf.toString(); break;
                case 6: item.storytext = buf.toString(); break;
                case 11: item.cmsstoryid = buf.toString(); break;
                case 14: item.pubDate = buf.toString(); break;
                case 15: item.lastModTime = buf.toString(); break;
                case 16: item.keyword = buf.toString(); break;
                case 17: item.category = buf.toString(); break;
                case 18: item.subcategory = buf.toString(); break;
                case 19: item.slotreference = buf.toString(); break;
                case 22: photoitem.caption = buf.toString(); break;
                case 23: photoitem.photoid = buf.toString(); break;
                case 24: photoitem.photolastmodified = buf.toString(); break;
                case 25: photoitem.height = buf.toString(); break;
                case 26: photoitem.width = buf.toString(); break;
                case 27: photoitem.photo = buf.toString(); break;
                case 28: photoitem.thumbnail = buf.toString(); break;
                default: if(!inItem) buf = null;
            }
        }
    }

    //Called with character data inside elements
    @Override
    public void characters(char ch[], int start, int length)
    {
        if(buf != null)
        {
            String chars = new String(ch, start, length); // get all text value inside the element tag
            chars = chars.trim(); // remove all white-space characters
            buf.append(chars);
        }
    }
}
4

1 に答える 1

2

おそらくあなたはすでにこれを行っていますが、これは別のスレッドで行う必要があることを繰り返したいと思います. 進行状況インジケーター (スピナー) を表示し、GUI の応答性を維持すると、ユーザーはアプリがクラッシュしたとは思いません。

バックグラウンド スレッドでこれを行っていない場合、システムがユーザー インターフェースの動作を維持しようと戦っているため、人為的に処理が遅くなる可能性があります。

なぜこれが遅いのかというと、大量の分岐があります。if ステートメントが多く、else (etc) が多いほど、分岐予測子がその仕事をするのが難しくなります。

また、ここで画像をダウンロードしているかどうかはわかりませんが、ダウンロードしている場合は、テキスト データが取得されてユーザーに表示された後に非同期で実行する必要があります (ユーザー インターフェイスの応答性を高めるため)。

于 2012-07-25T15:44:59.177 に答える