Windows Phone 7 Series arendus: RSS-voogude lugemine
14.04.2010 | Gunnar
Esimene asi, mille ma Windows Phone 7 Series arendusvahenditega järgi proovisin, oli andmete lugemine veebist. Point väga lihtne – paljud mobiilsed rakendused hakkavad arvatavasti veebiserveritega suhtlema. See oli esimene koht, kus tekkisid mõned piirangud, kuid õnneks mitte ületamatud. Käesolev postitus näitab, kuidas lugeda sisse RSS-voog ja kuvada seda ekraanil.
RSS-i lugemiseks tuleb pöörduda serveri poole, kus RSS asub ja lugeda sealt sisse XML. Vanat head WebClient klassi me kasutada ei saa ja peame piirduma WebRequest, HttpWebRequest, WebResponse ja HttpWebResponse klassidega. Ja ka nende juures on üks väikene konks – HttpWebRequest klassil puudub GetResponse() meetod.
Need piirangud tähendavad seda, et alles jäävad ainult asünkroonsed meetodid andmete lugemiseks. Idee on küllaltki lihtne, kuniks asünkroonne meetod andmeid toob, ei jää hangu kasutusliides ära ning kasutaja saab vajadusel igal ajal programmi sulgeda või tegeleda muude asjadega oma telefonis.
NB! Tegemist on eksperimentaalse koodiga ja et .NET CE + Silverlight maailm on mulle uus, ei ole ma kuigi kindel, kas see kood on kindlasti parim lahendus. Võimalik, et saab ka kuidagi oluliselt efektiivsemalt sama asja ära teha.
Minu RSS-i lugeja
Minu WP7 RSS-i lugeja on hetkel väga algne, ei oma ilusat nägu ega ka ülivõimsat ettevõtteklassi kuuluvat koodilist arhitektuuri ja disaini. Täiesti mõttetu luuseri värk, eks ole. Aga... see töötab ja praegune toorik kasutab neid vahendeid, mida arendajatele mõeldud CTP välja pakub.
Et mu esmane ülesanne on panna asjad tööle ja alles siis kosmeetika kallale asuda, siis on ka minu RSS-i lugeja praegu äärmiselt lihtne oma välimuselt. Kes tahab suuremalt vaadata, klikkigu julgelt pildi peal, see läheb pisut suuremaks kah.
Rakenduse peavaate ülemises osas on loend kirjutistega ja alumises osas on valitud kirjatüki kirjeldus. Õnneks on regulaaravaldised .NET CE peal olemas ja seega pole ka kirjelduse puhastamine HTML-ist midagi piinarikast.
FeedItem klass
Nüüd asume koodi kallale. Esimene klass, mida meil vaja läheb, on FeedItem. See klass esindab meile RSS-ist loetud postitusi. Klass ise on lihtne.
{
public string Title { get; set; }
public string Description { get; set; }
public DateTime PublishDate { get; set; }
public List<string> Categories { get; set; }
public string Link { get; set; }
public FeedItem()
{
Categories = new List<string>();
}
}
Järgmiseks asume RSS-i lugemise kallale.
RssClient klass
Järgmiseks realiseerime klassi, mille abil me loeme sisse RSS-voo ja moodustame selle põhjal postituste loendi. Klass annab lugemise lõpetamisest teada ItemsReceived sündmuse kaudu. Milleks selline lahendus? Me loeme RSS-ist andmeid asünkroonselt ja seega on vaja kuidagi postitusi küsivat koodi teavitada sellest, et postitused on kohal.
Kuigi järgnev kood ei ole maailma nunnumate killast ja ajab liigarenenud ilumeelega inimesed jälle kord nutma (oi, kui paha inimene ma olen), saavad vintskemad elutuultes karastunud purikad selle mõttest siiski lihtsasti aru.
{
private readonly string _rssUrl;
public delegate void ItemsReceivedDelegate(RssClient client, IList<FeedItem> items);
public event ItemsReceivedDelegate ItemsReceived;
public RssClient(string rssUrl)
{
_rssUrl = rssUrl;
}
public void LoadItems()
{
var request = (HttpWebRequest)WebRequest.Create(_rssUrl);
var result = (IAsyncResult)request.BeginGetResponse(ResponseCallback, request);
}
void ResponseCallback(IAsyncResult result)
{
var request = (HttpWebRequest)result.AsyncState;
var response = request.EndGetResponse(result);
var stream = response.GetResponseStream();
var reader = XmlReader.Create(stream);
var items = new List<FeedItem>(50);
FeedItem item = null;
var pointerMoved = false;
while (!reader.EOF)
{
if (pointerMoved)
{
pointerMoved = false;
}
else
{
if (!reader.Read())
break;
}
var nodeName = reader.Name;
var nodeType = reader.NodeType;
if (nodeName == "item")
{
if (nodeType == XmlNodeType.Element)
item = new FeedItem();
else if (nodeType == XmlNodeType.EndElement)
if (item != null)
{
items.Add(item);
item = null;
}
continue;
}
if (nodeType != XmlNodeType.Element)
continue;
if (item == null)
continue;
reader.MoveToContent();
var nodeValue = reader.ReadElementContentAsString();
// we just moved internal pointer
pointerMoved = true;
if (nodeName == "title")
item.Title = nodeValue;
else if (nodeName == "description")
item.Description = Regex.Replace(nodeValue,@" <(.|\n)*?> ",string.Empty);
else if (nodeName == "feedburner:origLink")
item.Link = nodeValue;
else if (nodeName == "pubDate")
{
if (!string.IsNullOrEmpty(nodeValue))
item.PublishDate = DateTime.Parse(nodeValue);
}
else if (nodeName == "category")
item.Categories.Add(nodeValue);
}
if (ItemsReceived != null)
ItemsReceived(this, items);
}
}
Et RSS tuleb kenasti sisse ja saame kõik loetud, mis sealt meie jaoks oluline on, siis ongi käes too õilis hetk, et andmed ekraanile ka saaks paisatud.
RssClient klassi kasutamine
Midagi keerukat me tegelikult ei teegi. Loome uue RssClient instantsi, anname talle ette RSS-voo aadressi, haagime külge meetodi, mis käivitatakse kui RSS on loetud ja paneme RssClient-i RSS-voogu lugema.
{
InitializeComponent();
SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;
listBox1.Width = Width;
var rssClient = new RssClient("http://feedproxy.google.com/gunnarpeipman");
rssClient.ItemsReceived += new RssClient.ItemsReceivedDelegate(rssClient_ItemsReceived);
rssClient.LoadItems();
}
void rssClient_ItemsReceived(RssClient client, IList<feeditem> items)
{
Dispatcher.BeginInvoke(delegate()
{
listBox1.ItemsSource = items;
});
}
Kui RSS-voog on loetud ja postitused käes, siis anname postituste loendi ette tollele ülemisele loendile, mis on näha ka eespool toodud ekraanpaugu (või siis emulaatorpaugu peal).
Kannete kuvamine
Viimase asjana peame reageerima sellele, kui kasutaja postituste loendist midagi valis. Sel juhul küsime loendi käest valitud postituse ja kuvame selle sisu kirjelduse kasti. Koodi arvate vist unes ka ära.
{
var item = (FeedItem)listBox1.SelectedItem;
textBlock1.Text = item.Description;
}
Ja ongi esimene samm meie prototüübi juures valmis.
Kokkuvõte
RSS-voogude lugemine midagi keerukat endast ei kujuta. Kuigi out-of-box kujul pole paljusid mugavaid klasse, mida kasutada ja ka olemasolevad on ära kohitsetud, saime me siiski kõik vajaliku tehtud. Standardsed vahendid, mida kasutasime olid lihtsad ja olulist vaeva ei nõudnud. Ja nagu nägime, siis andmete ajamine kasutusliidese külge käis väga lihtsasti.
Järgmisena püüame kasutusliidese ilusamaks teha ja panna tööle kannete täismahus lugemise.

14.04.2010 kell 12:09
Kas see tähendab, et LINQtoSQL ei ole phone peal kasutatav? Kui on, siis hästi murevaba XDocument.Load(url) olemas rss voo sisselugemiseks.
14.04.2010 kell 12:35
Saab ka sellega, kuid dokument laaditakse minu teadmisi mööda täies mahus. Mul on plaanis järgmiste sammudena millalgi mälukasutust oluliselt veel vähendada.