我是新服务(并下载了这个问题)...我有这个下载XML Feed并下载它的下载服务,但需要一段时间。
我从14个不同的URL下载,此服务从URL下载,解析xml,然后将消息发送回活动,告知服务重新开始使用下一个URL。
我确定有更好的方法来实现这一目标,并且正在寻找一些建议。以下是下载服务中的代码,如果您需要其他代码(例如主要活动中的handlemessage),请告诉我,我会把它放完。
因为我被告知我需要一个特定的问题:是否有更有效的方法从多个URL下载,而不是从此下载服务接收响应并在循环中重新启动它直到所有URL都被下载?
package prs.psesto.rotorss;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
public class DownloadService extends Service {
// XML node keys
private final String KEY_ITEM = "item"; // parent node
private final String KEY_GUID = "guid";
private final String KEY_LINK = "link";
private final String KEY_TITLE = "title";
private final String KEY_DESCRIPTION = "description";
private final String KEY_UPDATED = "a10:updated";
public static final String nameSpace = null;
private static String[] sportArray = { "nfl", "mlb", "nba", "nhl", "bpl",
"cfb", "gol", "nas" };
private final int PLAYER_NEWS = 0;
private final int ARTICLES = 1;
private final String THREAD_PLAYER_NEWS = "THREAD_PLAYER_NEWS";
private final String THREAD_ARTICLES = "THREAD_ARTICLES";
public static enum DownloadType {
PLAYER_NEWS, ARTICLES
};
/**
* Looper associated with the HandlerThread.
*/
private volatile Looper mServiceLooper;
/**
* Processes Messages sent to it from onStartCommnand() that
*/
private volatile ServiceHandler mServiceHandler;
/**
* Hook method called when DownloadService is first launched by the Android
* ActivityManager.
*/
public void onCreate() {
super.onCreate();
Log.d("DownloadService", "onCreate");
// Create and start a background HandlerThread since by
// default a Service runs in the UI Thread, which we don't
// want to block.
HandlerThread thread = new HandlerThread("DownloadService");
thread.start();
// Get the HandlerThread's Looper and use it for our Handler.
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/**
* Hook method called each time a Started Service is sent an Intent via
* startService().
*/
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("DownloadService", "onStartCommand");
// Create a Message that will be sent to ServiceHandler to
// retrieve animagebased on the URI in the Intent.
Message message = mServiceHandler.makeDownloadMessage(intent, startId);
// Send the Message to ServiceHandler to retrieve an image
// based on contents of the Intent.
mServiceHandler.sendMessage(message);
// Don't restart the DownloadService automatically if its
// process is killed while it's running.
return Service.START_NOT_STICKY;
}
/**
* Helper method that returns sport if download succeeded.
*/
public static int getSportIndex(Message message) {
Log.d("DownloadService", "getSportIndex");
// Extract the data from Message, which is in the form
// of a Bundle that can be passed across processes.
Bundle data = message.getData();
// Extract the pathname from the Bundle.
int sport = data.getInt("SPORTCODE");
Log.d("DownloadService", "sport = " + String.valueOf(sport));
// Check to see if the download succeeded.
if (message.arg1 == 9)
return 9;
else
return sport;
}
/**
* Helper method that returns sport if download succeeded.
*/
public static int getTypeIndex(Message message) {
Log.d("DownloadService", "getTypeIndex");
// Extract the data from Message, which is in the form
// of a Bundle that can be passed across processes.
Bundle data = message.getData();
// Extract the pathname from the Bundle.
int type = data.getInt("TYPECODE");
Log.d("DownloadService", "type = " + String.valueOf(type));
// Check to see if the download succeeded.
if (message.arg1 == 9)
return 9;
else
return type;
}
/**
* Factory method to make the desired Intent.
*/
public static Intent makeIntent(Context context, int type, int sport,
Handler downloadHandler) {
Log.d("DownloadService", "makeIntent");
// Create the Intent that's associated to the DownloadService
// class.
Intent intent = new Intent(context, DownloadService.class);
// Pathname for the downloaded image.
intent.putExtra("TYPECODE", type);
intent.putExtra("SPORTCODE", sport);
// Create and pass a Messenger as an "extra" so the
// DownloadService can send back the pathname.
intent.putExtra("MESSENGER", new Messenger(downloadHandler));
return intent;
}
/**
* @class ServiceHandler
*
* @brief An inner class that inherits from Handler and uses its
* handleMessage() hook method to process Messages sent to it from
* onStartCommnand() that indicate which url to download.
*/
private final class ServiceHandler extends Handler {
/**
* Class constructor initializes the Looper.
*
* @param Looper
* The Looper that we borrow from HandlerThread.
*/
public ServiceHandler(Looper looper) {
super(looper);
log("public ServiceHandler(Looper looper)");
}
/**
* A factory method that creates a Message to return to the
* DownloadActivity with the downloaded sport and type.
*/
private Message makeReplyMessage(int type, int sport, int result) {
log("makeReplyMessage");
Message message = Message.obtain();
Bundle data = new Bundle();
// Pathname for the downloaded image.
data.putInt("TYPECODE", type);
data.putInt("SPORTCODE", sport);
message.arg1 = result;
message.setData(data);
return message;
}
/**
* A factory method that creates a Message that contains information on
* how to stop the Service.
*/
private Message makeDownloadMessage(Intent intent, int startId) {
log("makeDownloadMessage");
Message message = Message.obtain();
// Include Intent & startId in Message to indicate which URI
// to retrieve and which request is being stopped when
// download completes.
message.obj = intent;
message.arg1 = startId;
return message;
}
/**
* Retrieves the download response and sport/type and replies to the
* DownloadActivity via the Messenger sent with the Intent.
*/
private void downloadAndReply(Intent intent) {
log("downloadAndReply");
// Download the requested image.
int sport = intent.getExtras().getInt("SPORTCODE");
int type = intent.getExtras().getInt("TYPECODE");
int result = downloadAndParse(type, sport);
// Extract the Messenger.
Messenger messenger = (Messenger) intent.getExtras().get(
"MESSENGER");
// Send the pathname via the messenger.
sendResult(messenger, type, sport, result);
}
/**
* Send the result back to the DownloadActivity via the messenger.
*/
private void sendResult(Messenger messenger, int type, int sport,
int result) {
log("sendResult");
// Call factory method to create Message.
Message message = makeReplyMessage(type, sport, result);
try {
// Send pathname to back to the DownloadActivity.
messenger.send(message);
} catch (RemoteException e) {
Log.e(getClass().getName(), "Exception while sending.", e);
}
}
public int downloadAndParse(int typeIndex, int sportIndex) {
log("downloadAndParse");
long id = 0;
String link = null;
int linkType = ARTICLES;
String title = null;
String description = null;
String updated = null;
String sport = sportArray[sportIndex];
try {
InputStream stream = null;
try {
stream = downloadUrl(getUrl(getDlType(typeIndex), sport));
XmlPullParserFactory factory = XmlPullParserFactory
.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(stream, null);
boolean insideItem = false;
// Returns the type of current event: START_TAG,
// END_TAG,
// etc..
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equalsIgnoreCase(KEY_ITEM)) {
insideItem = true;
} else if (xpp.getName().equalsIgnoreCase(KEY_GUID)) {
if (insideItem) {
id = Long.valueOf(String.valueOf(
xpp.nextText()).replace(" ", ""));
}
} else if (xpp.getName().equalsIgnoreCase(KEY_LINK)) {
if (insideItem) {
link = xpp.nextText();
if (link.contains("player")) {
linkType = PLAYER_NEWS;
}
}
} else if (xpp.getName()
.equalsIgnoreCase(KEY_TITLE)) {
if (insideItem) {
title = xpp.nextText();
}
} else if (xpp.getName().equalsIgnoreCase(
KEY_DESCRIPTION)) {
if (insideItem) {
description = xpp.nextText();
}
} else if (xpp.getName().equalsIgnoreCase(
KEY_UPDATED)) {
if (insideItem) {
updated = xpp.nextText();
}
}
} else if (eventType == XmlPullParser.END_TAG
&& xpp.getName().equalsIgnoreCase("item")) {
insideItem = false;
}
eventType = xpp.next(); // / move to next element
RotoItem rItem = DatabaseManager.sInstance.newRotoItem(
id, sport, link, linkType, title, description,
updated);
DatabaseManager.sInstance.addRotoItem(rItem);
}
// Makes sure that the InputStream is closed after the
// class
// is
// finished using it.
} finally {
if (stream != null) {
stream.close();
}
}
} catch (IOException e) {
Log.e("DownloadXml - performDownload", "Connection Error");
Log.e("IOException", e.toString());
return 9;
} catch (XmlPullParserException e) {
Log.e("DownloadXml - performDownload", "Error in data set");
Log.e("XmlPullParserException", e.toString());
return 9;
}
Log.d("DownloadData", "sportIndex = " + String.valueOf(sportIndex));
return sportIndex;
}
public DownloadType getDlType(int typeIndex) {
if (typeIndex == PLAYER_NEWS) {
return DownloadType.PLAYER_NEWS;
} else {
return DownloadType.ARTICLES;
}
}
public String getUrl(DownloadType downloadType, String sport) {
if (downloadType == DownloadType.PLAYER_NEWS) {
return "http://www.rotoworld.com/rss/feed.aspx?sport=" + sport
+ "&ftype=news&count=12&format=rss";
} else {
return "http://www.rotoworld.com/rss/feed.aspx?sport=" + sport
+ "&ftype=article&count=12&format=rss";
}
}
// Given a string representation of a URL, sets up a connection and gets
// an input stream.
private InputStream downloadUrl(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
return conn.getInputStream();
}
public void handleMessage(Message message) {
log("handleMessage");
// Download the designated image and reply to the
// DownloadActivity via the Messenger sent with the
// Intent.
downloadAndReply((Intent) message.obj);
// Stop the Service using the startId, so it doesn't stop
// in the middle of handling another download request.
stopSelf(message.arg1);
}
}
/**
* Hook method called back to shutdown the Looper.
*/
public void onDestroy() {
log("onDestroy");
mServiceLooper.quit();
}
/**
* This hook method is a no-op since we're a Start Service.
*/
public IBinder onBind(Intent arg0) {
log("IBinder");
return null;
}
public void log(String message) {
Log.d("DownloadService", message);
}
}
答案 0 :(得分:0)
除了从此下载服务接收响应并重新启动直到所有网址都被下载之外,是否有更有效的方式从多个URL下载?
使用ThreadPoolExecutor
并并行运行几个线程。转储您的Messenger
- 和 - HandlerThread
内容,并onStartCommand()
将每个职位交给ThreadPoolExecutor
。使用打包的事件总线(例如,greenrobot的EventBus,LocalBroadcastManager
)让您的UI层了解已完成的工作。
ThreadPoolExecutor
逻辑将是相当标准的Java。唯一的Android-isms是onStartCommand()
作为工作的接收者并使用事件总线来传递结果。