#android #multithreading #android-asynctask #httpclient
#Android #многопоточность #android-asynctask #httpclient httpclient
Вопрос:
Я ищу наилучший способ одновременного выполнения нескольких HTTP-подключений. Мое приложение извлекает RSS-каналы из 25 различных источников, и на данный момент я делаю только одно HTTP-соединение одновременно, что, очевидно, занимает немного времени для просмотра всех URL-адресов. Я использую AsyncTask для задания, и каждый раз, когда RSS-документ загружается и анализируется, я обновляю свою базу данных SQLite, добавляя в нее каналы.
private class FeedFetcherTask extends AsyncTask<String, Void, Integer> {
private Context context;
private String[] pcFeedUrls;
private String[] xboxFeedUrls;
private String[] playstationFeedUrls;
private String[] nintendoFeedUrls;
private String[] mobileFeedUrls;
private ArrayList<NewsFeed> newFeeds;
public FeedFetcherTask(Context c) {
context = c;
pcFeedUrls = c.getResources().getStringArray(R.array.pc_feeds);
xboxFeedUrls = c.getResources().getStringArray(R.array.xbox_feeds);
playstationFeedUrls = c.getResources().getStringArray(R.array.playstation_feeds);
nintendoFeedUrls = c.getResources().getStringArray(R.array.nintendo_feeds);
mobileFeedUrls = c.getResources().getStringArray(R.array.mobile_feeds);
newFeeds = new ArrayList<NewsFeed>();
}
@Override
protected Integer doInBackground(String... params) {
long time = System.currentTimeMillis();
//getActivity().setProgressBarIndeterminateVisibility(true);
getNewsForPc();
getNewsForXbox();
getNewsForPlaystation();
getNewsForNintendo();
getNewsForMobile();
newRowsInserted = storeNewsInDatabase();
long finish = System.currentTimeMillis() - time;
Log.i("time elapsed", finish / 1000.0 "");
return null;
}
@Override
protected void onPostExecute(Integer count) {
super.onPostExecute(count);
if (getActivity() != null) {
getActivity().setProgressBarIndeterminateVisibility(false);
if (newRowsInserted == 0) {
Toast.makeText(getActivity().getApplicationContext(), getResources().getString(R.string.no_new_tweets), Toast.LENGTH_SHORT).show();
} else {
newFeedsButton.setVisibility(Button.VISIBLE);
buttonVisible = Button.VISIBLE;
newFeedsButton.setText(getResources().getQuantityString(R.plurals.new_feeds_plurals, newRowsInserted, newRowsInserted));
//TODO Create animation
}
}
else{
buttonVisible = Button.VISIBLE;
}
}
@Override
protected void onCancelled() {
super.onCancelled();
}
private void retainListViewPosition() {
int index = listView.getFirstVisiblePosition() newFeeds.size();
View v = listView.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
listView.setSelectionFromTop(index, top);
}
private void getNewsForPc() {
int platform = NewsFeed.PLATFORM_PC;
for (String url : pcFeedUrls) {
parseRssFeed(url, platform);
}
}
private void getNewsForXbox() {
int platform = NewsFeed.PLATFORM_XBOX;
for (String url : xboxFeedUrls) {
parseRssFeed(url, platform);
}
}
private void getNewsForPlaystation() {
int platform = NewsFeed.PLATFORM_PLAYSTATION;
for (String url : playstationFeedUrls) {
parseRssFeed(url, platform);
}
}
private void getNewsForNintendo() {
int platform = NewsFeed.PLATFORM_NINTENDO;
for (String url : nintendoFeedUrls) {
parseRssFeed(url, platform);
}
}
private void getNewsForMobile() {
int platform = NewsFeed.PLATFORM_MOBILE;
for (String url : mobileFeedUrls) {
parseRssFeed(url, platform);
}
}
private void parseRssFeed(String urlIn, int platformIn) {
//TODO Too many GC, also need to close streams
try {
HttpClient apacheClient = new DefaultHttpClient();
HttpResponse response = apacheClient.execute(new HttpGet(urlIn));
BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
InputSource is = new InputSource(br);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(is);
NodeList nodeList = document.getElementsByTagName("item");
String provider = document.getElementsByTagName("title").item(0).getTextContent();
int platform = platformIn;
Node node;
NewsFeed feed = null;
String title;
String link;
String description;
NodeList guidNodeList;
String guid;
String pubDate;
NodeList creatorNodeList;
String creator;
Element element;
for (int i = 0; i < nodeList.getLength(); i ) {
node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
element = (Element) node;
feed = new NewsFeed();
title = element.getElementsByTagName("title").item(0).getTextContent();
feed.setTitle(title);
link = element.getElementsByTagName("link").item(0).getTextContent();
feed.setLink(link);
description = element.getElementsByTagName("description").item(0).getTextContent();
feed.setDescription(description);
guidNodeList = element.getElementsByTagName("guid");
if (guidNodeList == null | guidNodeList.getLength() < 1) {
feed.setGuid(link);
} else {
guid = guidNodeList.item(0).getTextContent();
feed.setGuid(guid);
}
pubDate = element.getElementsByTagName("pubDate").item(0).getTextContent();
feed.setDate(pubDate);
creatorNodeList = element.getElementsByTagName("dc:creator");
if (creatorNodeList == null | creatorNodeList.getLength() < 1) {
feed.setCreator(provider);
} else {
creator = creatorNodeList.item(0).getTextContent();
feed.setCreator(creator);
}
feed.setProvider(provider);
feed.setPlatform(platform);
newFeeds.add(feed);
}
}
} catch (ConnectException ce) {
Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.connection_exception_error), Toast.LENGTH_SHORT).show();
} catch (UnknownHostException uhe) {
uhe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private int storeNewsInDatabase() {
return dao.insertAllFeeds(newFeeds);
}
}
Я считаю, что это, вероятно, наименее эффективный способ сделать это. Я был бы признателен за любые предложения о том, как подойти к этой задаче. Я уже посмотрел на ExecutorService, но не уверен, что это правильный путь.
Ответ №1:
Я предлагаю использовать loopj, асинхронную клиентскую библиотеку HTTP. Вам нужно будет провести рефакторинг вашего кода, чтобы сделать его управляемым событиями, но это должно стоить затраченных усилий.