Android應用之《宋詞三百首》(一)

來源:互聯網
上載者:User

標籤:android   閱讀   

今天我們通過一個實際的案例來綜合運用一下Android技術中各方面的知識,模仿《宋詞三百首》寫一個應用,代碼裡面所有的資源均來自互連網,僅用於學習,請勿作商業用途。

(1)第一步建立Android工程,修改應用表徵圖,將72x72的app icon拷貝到drawable-hdpi檔案夾下,將96x96的app icon拷貝到drawable-xhdpi檔案夾下,然後修改AndroidManifest.xml檔案裡的內容如下:

<application        android:icon="@drawable/icon"

然後修改strings.xml的內容如下:

<string name="app_name">宋詞三百首</string>    <string name="title_activity_main">宋詞三百首</string>

修改應用程式名稱,將AndroidManifest.xml檔案中的內容修改如下:

android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name=".ui.SplashActivity"            android:label="@string/title_activity_main" >

經過以上的工作,App的表徵圖和名稱都已經修改OK;

(2)下面我們來寫第一個介面:歡迎介面

首先將背景圖片welcome.jpg拷貝到drawable-hdpi下面,然後在layout檔案夾下面建立一個activity_splash.xml,內容如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"     android:background="@drawable/welcome">    </LinearLayout>

然後在src下面建立一個SplashActivity.java檔案,代碼已經詳細注釋,內容如下:

package com.example.songcidemo.ui;import com.example.songcidemo.R;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.view.Window;/** *App歡迎介面 */public class SplashActivity extends Activity {/** * 啟動時最先執行的回調方法 */@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//設定介面沒有標題列requestWindowFeature(Window.FEATURE_NO_TITLE);//指定介面的布局檔案setContentView(R.layout.activity_splash);//初始化一個HandlerHandler handler = new Handler();//Runnable是一個線程,在1500毫秒以後執行線程對象handler.postDelayed(new Runnable() {@Overridepublic void run() {//從SplashActivity跳轉到MainActivityIntent intent = new Intent(SplashActivity.this, MainActivity.class);startActivity(intent);//在後台關閉掉SplashActivitySplashActivity.this.finish();}},  1500);}}

運行效果如:


(2)接著我們寫第二個介面,在寫第二個介面之前我們還需要做一些準備工作,就是準備資料,所有的資料都儲存在songci.xml這樣一個檔案中,在這裡我截取其一點片段如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?><root><node><title><![CDATA[洞仙歌·泗州中秋作]]></title><auth><![CDATA[晁補之]]></auth><desc><![CDATA[<p>  洞仙歌·泗州①中秋作 </p> <p>  <strong>晁補之</strong> </p> <p>  青煙冪②處,碧海飛金鏡。永夜閑階臥桂影。 </p> <p>  露涼時、零亂多少寒螿③,神京④遠,惟有藍橋⑤路近。 </p> <p>  水晶簾不下,雲母屏⑥開,冷浸佳人⑦淡脂粉。 </p> <p>  待都將許多明,付與金尊,投曉共、流霞⑧傾盡。 </p> <p>  更攜取、胡床⑨上南樓,看玉做人間,素鞦韆傾。</p> <p><br />【注釋】<br />  ①泗州:安徽泗縣。 </p> <p>  ②冪(mì):遮蓋。 </p> <p>  ③寒螿(jiāng):寒蟬。 </p> <p>  ④ 神京:指北宋京城汴梁。 </p> <p>  ⑤藍橋:在陝西藍田縣東南,橋架藍水之上,故名。世傳其地有仙窟,唐裴航遇雲英於此橋。 </p> <p>  ⑥ 雲母屏:雲母為花崗岩主要成分,可作屏風,豔麗光澤。 </p> <p>  ⑦佳人:這裡指席間的女性 </p> <p>  ⑧流霞:仙酒名。語意雙關,既指酒,也指朝霞 </p> <p>  ⑨胡床:古代一種輕便坐具,可以摺疊。</p> <p>【譯文】<br />  青色的煙雲,遮住了月影,從碧海般的晴空裡飛出一輪金燦燦的明鏡。長夜的空階上臥著掛樹的斜影。夜露漸涼之是時,多少秋蟬零亂地嗓鳴思念京都路遠,論路近唯有月宮仙境,高卷水晶簾兒,展開雲母屏風,美人的淡淡脂粉浸潤了夜月的清冷。待我許多月色澄輝,傾入金樽,直到拂曉連同流霞全都傾盡。再攜帶一張胡床登上南樓,看白玉鋪成的人間,領略素白澄潔的千頃清秋。</p>]]></desc></node>

我們將songci.xml放在assets檔案夾下面,因為xml檔案有點大,在打包成apk檔案的時候會被壓縮,造成讀取的時候產生IOException,關於這個問題的更多詳細請參考IOEXception while reading from inputstream,所以我們將songci.xml檔案的改名為songci.mp3,以避免這樣的問題。


其次就是幾個知識點的預備工作(如果你已經熟悉這些知識,請跳過):

SAX解析XML

PULL解析XML

那麼下面我們開始對XML資料進行解析和封裝:

首先建立一個介面ISongCiParser,其內容如下:

package com.example.songcidemo.data;import java.io.InputStream;import java.util.List;import com.example.songcidemo.bean.SongCi;public interface ISongCiParser {/** * 解析xml輸入資料流 *  * @param is輸入資料流 * @param scList裝載容器 * @throws Exception */public void parse(InputStream is,List<SongCi> scList) throws Exception;}

這裡插入一點寫代碼時候遇到的問題:因為之前想用SAX解析器去解析XML,但是做到一半的時候發現有問題,就是<desc></desc>之間的內容包含了很多<p></p><strong></strong><br></br>這樣的標籤對,SAX解析的時候把裡面的內容都當作element進行了分割擷取值,但是我想要的是<desc></desc>之間的所有內容作為一個值,所以用SAX做到一半的時候就果斷改用PULL解析器來解析,解析得很順利,沒有出現問題。繼續......

接著我們寫一個PULL解析實作類別SongCiParserImpl,其內容如下:

package com.example.songcidemo.data;import java.io.InputStream;import java.util.List;import org.xmlpull.v1.XmlPullParser;import android.util.Xml;import com.example.songcidemo.bean.SongCi;public class SongCiParserImpl implements ISongCiParser{//定義XML檔案標籤常量,常量值與XML檔案內的標籤名一致private static final String TAG_NODE = "node";private static final String TAG_TITLE = "title";private static final String TAG_AUTH = "auth";private static final String TAG_DESC = "desc";/** * 解析xml檔案的方法 *  * is輸入資料流 * scList裝載資料解析完後並封裝成SongCi的鏈表 */@Overridepublic void parse(InputStream is, List<SongCi> scList) throws Exception {SongCi sc = null;if(scList != null){scList.clear();}//擷取XmlPullParser執行個體XmlPullParser xpp = Xml.newPullParser();//為XmlPullParser執行個體設定輸入資料流,並設定輸入資料流的字元集是utf-8xpp.setInput(is,"utf-8");//擷取當前事件的類型,比如START_TAG,END_TAG,TEXT等等int eventType = xpp.getEventType();//如果目前時間的類型不是檔案結束的時候執行迴圈while(eventType != XmlPullParser.END_DOCUMENT){switch (eventType) {case XmlPullParser.START_DOCUMENT://do nothingbreak;//如果當前的事件類型是開始元素case XmlPullParser.START_TAG:if(xpp.getName().equals(TAG_NODE)){//如果遇到<node>就建立一個SongCi對象sc = new SongCi();}else if(xpp.getName().equals(TAG_TITLE)){//如果遇到<title>就將<title>後面的text傳遞給scsc.setTitle(xpp.nextText());}else if(xpp.getName().equals(TAG_AUTH)){//如果遇到<auth>就將<auth>後面的text傳遞給scsc.setAuth(xpp.nextText());}else if(xpp.getName().equals(TAG_DESC)){//如果遇到<desc>就將<desc>後面的text傳遞給scsc.setDesc(xpp.nextText());}break;case XmlPullParser.END_TAG:if(xpp.getName().equals(TAG_NODE)){//如果遇到</node>就將sc所關聯的對象加入到鏈表中scList.add(sc);sc = null;}break;default:break;}//進入下一個元素並觸發相應的事件eventType = xpp.next();}}}

這一步寫好了,我們就可以在Activity裡面去直接使用了,在MainActivity當中我已經把SAX的部分注釋掉了,其他的代碼也做了詳細的注釋,內容如下:

package com.example.songcidemo.ui;import java.io.InputStream;import java.util.ArrayList;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.xml.sax.InputSource;import org.xml.sax.XMLReader;import android.app.Activity;import android.content.Intent;import android.content.res.AssetManager;import android.os.Bundle;import android.view.View;import android.view.Window;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.ListView;import com.example.songcidemo.R;import com.example.songcidemo.bean.SongCi;import com.example.songcidemo.data.MainListViewAdapter;import com.example.songcidemo.data.SongCiParserImpl;import com.example.songcidemo.data.SongCiSaxHandler;import com.example.songcidemo.util.Global;public class MainActivity extends Activity {//聲明裝載SongCi類型的鏈表private ArrayList<SongCi> scList;//聲明了一個ListView變數private ListView mListView;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_main);        initData();//        saxParseXML();        pullParseXML();        setupViews();            }        private void initData(){    //初始化scList    scList = new ArrayList<SongCi>();    }        /**     * 用SAX解析器解析XML檔案     */    private void saxParseXML(){    try {    //擷取一個AssetManager對象    AssetManager assetManager = this.getAssets();    //通過assetManager的open方法擷取到songci.mp3的輸入資料流        InputStream inputStream = assetManager.open("songci.mp3");        //將inputstream的內容封裝成InputSource        InputSource inputSource = new InputSource(inputStream);        //擷取SAXParserFactory執行個體        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();        //擷取SAXParser對象        SAXParser saxParser = saxParserFactory.newSAXParser();        //擷取XMLReader對象        XMLReader xmlReader = saxParser.getXMLReader();        //初始化scSaxHandler        SongCiSaxHandler scSaxHandler = new SongCiSaxHandler(scList);        //將scSaxHandler傳遞給xmlReader        xmlReader.setContentHandler(scSaxHandler);        //開始解析xml檔案        xmlReader.parse(inputSource);                //關閉流        inputStream.close();                } catch (Exception e) {e.printStackTrace();}        }        /**     * 用PULL方式解析XML檔案     */    private void pullParseXML(){    try {InputStream is = this.getAssets().open("songci.mp3");SongCiParserImpl scpi = new SongCiParserImpl();scpi.parse(is, scList);} catch (Exception e) {e.printStackTrace();}    }        /**     * 初始化視圖     */    private void setupViews(){    mListView = (ListView) findViewById(R.id.lv_catelog);        //初始化自訂類型MainListViewAdapter的執行個體adapter,將scList傳遞給adapter的構造器    MainListViewAdapter adapter = new MainListViewAdapter(this, scList);        //將adapter傳遞給mListView    mListView.setAdapter(adapter);        mListView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {Global.currentSongCi = scList.get(position);Intent intent = new Intent(MainActivity.this, ContentActivity.class);startActivity(intent);}});    }}

因為這裡面有一個自訂的Adapter,所以這裡給出MainListViewAdapter的定義,方便大家閱讀:(這個類我沒有加註釋,如果讀者感覺閱讀困難,建議先看一下這篇文章自訂ListView)

package com.example.songcidemo.data;import java.util.ArrayList;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import com.example.songcidemo.R;import com.example.songcidemo.bean.SongCi;public class MainListViewAdapter extends BaseAdapter{private ArrayList<SongCi> scList;private Context context;public MainListViewAdapter(Context context, ArrayList<SongCi> scList){this.context = context;this.scList = scList;}@Overridepublic int getCount() {return scList.size();}@Overridepublic Object getItem(int position) {return scList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ListViewItemHolder holder;if(convertView == null){LayoutInflater inflater = LayoutInflater.from(context);convertView = inflater.inflate(R.layout.list_item, null);holder = new ListViewItemHolder();holder.titleTextView = (TextView) convertView.findViewById(R.id.tv_title);holder.authTextView = (TextView) convertView.findViewById(R.id.tv_auth);convertView.setTag(holder);}else{holder = (ListViewItemHolder) convertView.getTag();}SongCi sc = scList.get(position);String title = sc.getTitle();String auth = sc.getAuth();holder.titleTextView.setText(title);holder.authTextView.setText(auth);return convertView;}private class ListViewItemHolder{TextView titleTextView;TextView authTextView;}}

附上一張MainActivity的介面:


更多內容,下回分解......


Android應用之《宋詞三百首》(一)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.