我是Windows Phone 7开发的新手,如果愿意,我在查找如何在“后台”中下载某些数据时会遇到一些麻烦。我知道这是可能的,因为像ESPN等应用程序显示“正在加载... ..”。在下载他们的数据时,UI仍然完全响应。我想要做的是下载一些Twitter数据。
这就是我现在所拥有的,但它阻止了atm:
// Constructor:
// load the twitter data
WebClient twitter = new WebClient();
twitter.DownloadStringCompleted += new DownloadStringCompletedEventHandler(twitter_DownloadStringCompleted);
twitter.DownloadStringAsync(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=badreligion"));
// Callback function:
void twitter_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
return;
}
XElement xmlTweets = XElement.Parse(e.Result);
TwitterListBox.ItemsSource = from tweet in xmlTweets.Descendants("status")
select new TwitterItem
{
ImageSource = tweet.Element("user").Element("profile_image_url").Value,
Message = tweet.Element("text").Value,
UserName = tweet.Element("user").Element("screen_name").Value
};
}
编辑:尝试多线程:
// in constructor
Dispatcher.BeginInvoke(new ThreadStart(StartTwitterUpdate));
// other functions
private void StartTwitterUpdate()
{
// load the twitter data
WebClient twitter = new WebClient();
twitter.DownloadStringCompleted += new DownloadStringCompletedEventHandler(twitter_DownloadStringCompleted);
twitter.DownloadStringAsync(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=badreligion"));
}
void twitter_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
return;
}
XElement xmlTweets = XElement.Parse(e.Result);
TwitterListBox.ItemsSource = from tweet in xmlTweets.Descendants("status")
select new TwitterItem
{
ImageSource = tweet.Element("user").Element("profile_image_url").Value,
Message = tweet.Element("text").Value,
UserName = tweet.Element("user").Element("screen_name").Value
};
}
编辑2 :按照Rico Suter的建议使用HttpWebRequest
,并在this博文的帮助下,我认为我已经完成了:
// constructor
StartTwitterUpdate();
private void StartTwitterUpdate()
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=badreligion"));
request.BeginGetResponse(new AsyncCallback(twitter_DownloadStringCompleted), request);
}
void twitter_DownloadStringCompleted(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
using (StreamReader streamReader1 =
new StreamReader(response.GetResponseStream()))
{
string resultString = streamReader1.ReadToEnd();
XElement xmlTweets = XElement.Parse(resultString);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
TwitterListBox.ItemsSource = from tweet in xmlTweets.Descendants("status")
select new TwitterItem
{
ImageSource = tweet.Element("user").Element("profile_image_url").Value,
Message = tweet.Element("text").Value,
UserName = "@" + tweet.Element("user").Element("screen_name").Value
};
});
}
}
答案 0 :(得分:5)
我认为WebClient
方法部分阻塞。包括DNS查找的第一部分是阻止,但下载本身不是。
请参阅C# async methods still hang UI
我个人认为这是.net API中的一个错误(或者更糟糕的是:被设计破坏)
作为一种解决方法,您可以在单独的线程中开始下载。我建议使用任务API。
Task.Factory.StartNew(
()=>
{
twitter.DownloadStringAsync(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=badreligion"));
}
);
不是最佳的,因为它在执行DNS查找时占用一个线程,但在实践中应该是可接受的。
我认为你的代码的另一个问题是回调不会发生在主线程上,而是发生在线程池线程上。您需要使用将事件发布到主线程的SynchronizationContext
。
答案 1 :(得分:1)
您有两种选择:HttpWebRequest
和WebClient
。这两个类都在后台下载。唯一区别:使用WebClient
方法twitter_DownloadStringCompleted
将在UI线程中调用,因此解析数据将阻止UI。
如果您使用HttpWebRequest,该方法将在另一个线程中调用,但要设置数据绑定的数据或直接设置为控件,您必须使用以下内容:
void twitter_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
// do your parsing with e.Result...
Deployment.Current.Dispatcher.BeginInvoke(() => {
// set your data (2) to UI
});
}
将在UI线程中调用(2)中的代码。将进度条设置为StartTwitterUpdate
中可见,并在(2)中将进度条设置为不可见。
查看此类以简化http调用(POST,FILES,GZIP等):