Простой RSS-клиент на Android
Пошаговое руководство по созданию RSS-клиента на Android. Статья для начинающих разработчиков. Android – операционная система для мобильных устройств от Google. Система очень перспективная и динамично развивается. Базовые навыки разработки будут совсем не лишними. Осторожно много скриншотов!
1. Начало
Вначале нужно зайти на официальный сайт и ознакомиться с возможностями последней версии Android 2.2. На сайте есть специальный раздел для разработчиков. Тут можно скачать все необходимые инструменты, найти инструкцию по установке, инструкцию по созданию первого приложения и справку по пакетам и классам библиотеки.
2. Установка SDK
На компьютере должен быть установлен JDK версии 5 или 6. Для разработки под Android нужно скачать и установить Android SDK, в котором есть эмулятор Android. Далее нужно установить Eclipse версии 3.4 или 3.5. И последнее, нужно установить плагин ADT для Eclipse.
3. Создание RSS-клиента
За основу я взял статью Creating Rss Reader in Android. Но в статье есть ошибки, и получить рабочей приложение сразу не получится. По моей просьбе, автор выложил полный рабочий проект. Но пока шла переписка, я сам исправил ошибки и написал свою версию программы.
3.1. Создание проекта
Запускаем Eclipse, выбираем меню File->New->Project. Запускается диалог New Project, выбираем папку Android и проект Android Project, жмем Next.
Открывается окно New Android Project. Заполняем поле Project name: uRSS, Выбираем в таблице Build Target строку Android 2.2. Дальше нужно заполнить свойства проекта в разделе Properties.
Application name: uRSS.
Package name: rembo.network.urss.
RSSactivity.
Min SDK Version: 8.
Жмем Next и в следующем окне ничего не меняем и жмем Finish.
Все проект создан.
3.2. Написание кода
Eclipse создаст много папок и файлов проекта (в них легко запутаться).
Главные файлы такие:
src/rembo.network.rss/RSSactivity.java – файл с классом RSSactivity, который задает логику главного окна (тут напишем обработчики событий);
res/layout/main.xml – XML описание главного окна (тут создадим элементы управления);
AndroidManifest.xml – файл описания свойств приложения (тут свяжем XML описание с кодом и зададим разрешение на работу в сети).
Для начала зададим содержимое главного окна в файле res/layout/main.xml. Главное окно будет построено на основе контейнера LinearLayout. Оно содержит надпись TextView, поле для ввода текста EditText, кнопку Button и список ListView. Обратите внимание, что у каждого элемента есть android:id. Это идентификатор по которому с элементом интерфейса можно связаться из кода.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/label" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Enter RSS URL:" /> <EditText android:id="@+id/rssURL" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@android:drawable/editbox_background" android:text="http://feeds.feedburner.com/MicrosoftUserGroupVinnitsya" /> <Button android:id="@+id/fetchRss" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10dip" android:text="Fetch Rss" /> <ListView android:id="@+id/rssListView" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
Для элемента списка нужно задать содержимое. Для этого создайте файл res/layout/list_item.xml.
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp" android:textSize="13sp" android:autoLink="all" > </TextView>
При нажатии на элемент списка, новость должна открыться в новом окне. Создадим файл res/layout/rss_item_displayer.xml для этого окна.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/titleTextView" android:text="Title:" android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="10dp" android:textSize="13sp" android:autoLink="all" /> <TextView android:id="@+id/contentTextView" android:text="Content:" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="13sp" android:autoLink="all" /> </LinearLayout>
Итак, интерфейс создан. Теперь нужно писать код. Создаем новый класс RssItem в файле src/rembo.network.rss/RssItem.java. Класс получает RSS содержимое из Интернета.
package rembo.network.urss; import java.util.*; import java.text.*; import java.net.*; import java.io.*; import javax.xml.parsers.*; import org.w3c.dom.*; public class RssItem { private String title; private String description; private Date pubDate; private String link; public RssItem(String title, String description, Date pubDate, String link) { this.title = title; this.description = description; this.pubDate = pubDate; this.link = link; } public String getTitle() { return this.title; } public String getLink() { return this.link; } public String getDescription() { return this.description; } public Date getPubDate() { return this.pubDate; } @Override public String toString() { SimpleDateFormat sdf = new SimpleDateFormat("MM/dd - hh:mm:ss"); String result = getTitle() + " ( " + sdf.format(this.getPubDate()) + " )"; return result; } public static ArrayList<RssItem> getRssItems(String feedUrl) { ArrayList<RssItem> rssItems = new ArrayList<RssItem>(); RssItem rssItemT = new RssItem("MSUG news", "Best IT news.", new Date(), "http://msug.vn.ua/"); rssItems.add(rssItemT); try { //open an URL connection make GET to the server and //take xml RSS data URL url = new URL(feedUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream is = conn.getInputStream(); //DocumentBuilderFactory, DocumentBuilder are used for //xml parsing DocumentBuilderFactory dbf = DocumentBuilderFactory .newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); //using db (Document Builder) parse xml data and assign //it to Element Document document = db.parse(is); Element element = document.getDocumentElement(); //take rss nodes to NodeList NodeList nodeList = element.getElementsByTagName("item"); if (nodeList.getLength() > 0) { for (int i = 0; i < nodeList.getLength(); i++) { //take each entry (corresponds to <item></item> tags in //xml data Element entry = (Element) nodeList.item(i); Element _titleE = (Element) entry.getElementsByTagName( "title").item(0); Element _descriptionE = (Element) entry .getElementsByTagName("description").item(0); Element _pubDateE = (Element) entry .getElementsByTagName("pubDate").item(0); Element _linkE = (Element) entry.getElementsByTagName( "link").item(0); String _title = _titleE.getFirstChild().getNodeValue(); String _description = _descriptionE.getFirstChild().getNodeValue(); Date _pubDate = new Date(_pubDateE.getFirstChild().getNodeValue()); String _link = _linkE.getFirstChild().getNodeValue(); //create RssItemObject and add it to the ArrayList RssItem rssItem = new RssItem(_title, _description, _pubDate, _link); rssItems.add(rssItem); } } } } catch (Exception e) { e.printStackTrace(); } return rssItems; } }
Теперь создадим класс RssItemDisplayer в файле src/rembo.network.rss/RssItemDisplayer.java. Он отвечает за логику окна, которое показывает полный текст новости. Обратите внимание как по id элемента управления его получают в коде TextView titleTv = (TextView)findViewById(R.id.titleTextView);
package rembo.network.urss; import android.app.Activity; import android.os.Bundle; import android.widget.*; import java.util.*; import java.text.*; import java.net.*; import java.io.*; import javax.xml.parsers.*; import org.w3c.dom.*; import android.view.*; public class RssItemDisplayer extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rss_item_displayer); RssItem selectedRssItem = RSSactivity.selectedRssItem; //Bundle extras = getIntent().getExtras(); TextView titleTv = (TextView)findViewById(R.id.titleTextView); TextView contentTv = (TextView)findViewById(R.id.contentTextView); String title = ""; SimpleDateFormat sdf = new SimpleDateFormat("MM/dd - hh:mm:ss"); title = "\n" + selectedRssItem.getTitle() + " ( " + sdf.format(selectedRssItem.getPubDate()) + " )\n\n"; String content = ""; content += selectedRssItem.getDescription() + "\n" + selectedRssItem.getLink(); titleTv.setText(title); contentTv.setText(content); } }
Теперь пишем код класса RSSactivity в файле src/rembo.network.rss/ RSSactivity.java.java. Он отвечает за логику главного окна. Обратите внимание как создаются обработчики событий для клика по кнопке и по элементу списка fetchRss.setOnClickListener(new View.OnClickListener()…
package rembo.network.urss; import android.app.Activity; import android.os.Bundle; import android.widget.*; import java.util.*; import java.text.*; import java.net.*; import java.io.*; import javax.xml.parsers.*; import org.w3c.dom.*; import android.view.*; import android.view.View; import android.widget.*; import android.content.*; public class RSSactivity extends Activity { public static RssItem selectedRssItem = null; String feedUrl = ""; ListView rssListView = null; ArrayList<RssItem> rssItems = new ArrayList<RssItem>(); ArrayAdapter<RssItem> aa = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // get textview from our layout.xml final TextView rssURLTV = (TextView) findViewById(R.id.rssURL); // get button from layout.xml Button fetchRss = (Button) findViewById(R.id.fetchRss); // define the action that will be executed when the button is clicked. fetchRss.setOnClickListener(new View.OnClickListener() { //@Override public void onClick(View v) { feedUrl = rssURLTV.getText().toString(); //TextView TVtitle=(TextView)findViewById(R.id.label); //CharSequence cs="fetching"; //TVtitle.setText(cs); aa.notifyDataSetChanged(); refressRssList(); //cs="Feed:"; //TVtitle.setText(cs); } }); // get the listview from layout.xml rssListView = (ListView) findViewById(R.id.rssListView); // here we specify what to execute when individual list items clicked rssListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { //@Override public void onItemClick(AdapterView<?> av, View view, int index, long arg3) { selectedRssItem = rssItems.get(index); // we call the other activity that shows a single rss item in // one page Intent intent = new Intent( "rembo.network.urss.displayRssItem"); startActivity(intent); } }); //adapters are used to populate list. they take a collection, //a view (in our example R.layout.list_item aa = new ArrayAdapter<RssItem>(this, R.layout.list_item, rssItems); //here we bind array adapter to the list rssListView.setAdapter(aa); feedUrl = rssURLTV.getText().toString(); refressRssList(); } private void refressRssList() { ArrayList<RssItem> newItems = RssItem.getRssItems(feedUrl); rssItems.clear(); rssItems.addAll(newItems); //TextView TVtitle=(TextView)findViewById(R.id.label); //CharSequence cs="0"; //if(newItems.size()>0) cs="is 1"; //if(newItems.size()>5) cs="is 5"; ///TVtitle.setText(cs); aa.notifyDataSetChanged(); } }
Остался последний штрих. Нужно связать интерфейс и код в файле AndroidManifest.xml и разрешить приложению выход в Интернет.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="rembo.network.urss" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".RSSactivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".RssItemDisplayer" android:label="Display Rss Item"> <intent-filter> <action android:name="rembo.network.urss.displayRssItem" /> <category android:name="android.intent.category.DEFAULT"></category> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
3.3. Запуск
Пора запускать наше приложение. Но вначале нужно создать виртуальную машину. Для этого в Eclipse переходим в меню Window->Android SDK and AVD Manager.
Жмем New и выбираем свойства виртуальной машины. В разделе Hardware обязательно нужно добавить GSM modem, поддержку Touchscreeen, Device ram size и Max VM application heap size (при такой конфигурации устройство удачно подключается к Интернету). Жмем Create AVD (тут придется немного подождать).
Жмем кнопку старт и запускаем виртуальную машину. Тут нужно запастись терпением. Ждать придется минут 10-20, пока машина не загрузится. Убедитесь, что виртуальное устройство подключено к Интернету. Если нет, то попробуйте перегрузиться или создать новую машину.
После запуска виртуальной машины переходим в Eclipse и запускаем приложение (жмем Run). Снова придется подождать минут 5, пока приложение установится на виртуальную машину и запустится. Если приложение не запускается, то попробуйте выключить виртуальную машину и запустить приложение (тут уже придется долго ждать, пока виртуальная машина стартует снова).