Android应用之《宋词三百首》(一)

来源:互联网 发布:anywhere软件源地址 编辑:程序博客网 时间:2024/04/28 22:41

今天我们通过一个实际的案例来综合运用一下Android技术中各方面的知识,模仿《宋词三百首》写一个应用,代码里面所有的资源均来自互联网,仅用于学习,请勿作商业用途。


(1)第一步新建Android工程,修改应用图标,将72x72的app icon拷贝到drawable-hdpi文件夹下,将96x96的app icon拷贝到drawable-xhdpi文件夹下,然后修改AndroidManifest.xml文件里的内容如下:

<span style="font-family:Comic Sans MS;font-size:18px;"><application        android:icon="@drawable/icon"</span>

然后修改strings.xml的内容如下:

<span style="font-family:Comic Sans MS;font-size:18px;"><string name="app_name">宋词三百首</string>    <string name="title_activity_main">宋词三百首</string></span>

修改应用名称,将AndroidManifest.xml文件中的内容修改如下:

<span style="font-family:Comic Sans MS;font-size:18px;">android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name=".ui.SplashActivity"            android:label="@string/title_activity_main" ></span>

经过以上的工作,App的图标和名称都已经修改OK;

(2)下面我们来写第一个界面:欢迎界面

首先将背景图片welcome.jpg拷贝到drawable-hdpi下面,然后在layout文件夹下面新建一个activity_splash.xml,内容如下:

<span style="font-family:Comic Sans MS;font-size:18px;"><?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></span>

然后在src下面新建一个SplashActivity.java文件,代码已经详细注释,内容如下:

<span style="font-family:Comic Sans MS;font-size:18px;">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);}}</span>

运行效果如下图:


(2)接着我们写第二个界面,在写第二个界面之前我们还需要做一些准备工作,就是准备数据,所有的数据都存储在songci.xml这样一个文件中,在这里我截取其一点片段如下:

<span style="font-family:Comic Sans MS;font-size:18px;"><?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></span>

我们将songci.xml放在assets文件夹下面,因为xml文件有点大,在打包成apk文件的时候会被压缩,造成读取的时候产生IOException,关于这个问题的更多详细请参考IOEXception while reading from inputstream,所以我们将songci.xml文件的改名为songci.mp3,以避免这样的问题。


其次就是几个知识点的预备工作(如果你已经熟悉这些知识,请跳过):

SAX解析XML

PULL解析XML

那么下面我们开始对XML数据进行解析和封装:

首先创建一个接口ISongCiParser,其内容如下:

<span style="font-family:Comic Sans MS;font-size:18px;">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;}</span>

这里插入一点写代码时候遇到的问题:因为之前想用SAX解析器去解析XML,但是做到一半的时候发现有问题,就是<desc></desc>之间的内容包含了很多<p></p><strong></strong><br></br>这样的标签对,SAX解析的时候把里面的内容都当作element进行了分割获取值,但是我想要的是<desc></desc>之间的所有内容作为一个值,所以用SAX做到一半的时候就果断改用PULL解析器来解析,解析得很顺利,没有出现问题。继续......

接着我们写一个PULL解析实现类SongCiParserImpl,其内容如下:

<span style="font-family:Comic Sans MS;font-size:18px;">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();}}}</span>

这一步写好了,我们就可以在Activity里面去直接使用了,在MainActivity当中我已经把SAX的部分注释掉了,其他的代码也做了详细的注释,内容如下:

<span style="font-family:Comic Sans MS;font-size:18px;">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);}});    }}</span>

因为这里面有一个自定义的Adapter,所以这里给出MainListViewAdapter的定义,方便大家阅读:(这个类我没有加注释,如果读者感觉阅读困难,建议先看一下这篇文章自定义ListView)

<span style="font-family:Comic Sans MS;font-size:18px;">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;}}</span>

附上一张MainActivity的界面截图:


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


3 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 感冒吃了白参怎么办 吃辣的嗓子疼怎么办 美团客户更改地址怎么办 忘记steam的账户名称怎么办 重置手机忘了密码怎么办 sp下行短信费扣怎么办 hr公司业务员招不到人怎么办 卖房中介被房倒压房子怎么办 电脑放不了dvd光盘怎么办 股东迟迟不交齐股本金怎么办 wps转pdf就乱了怎么办 被有用分期骗了怎么办 找不到以前有用分期的账号怎么办 打工去韩国不懂韩语怎么办? 想去韩国整容没钱怎么办 专接本没接上怎么办 抄写经文写错了怎么办 在外地修车被宰怎么办 国外汇款公司名称写错了怎么办 增值税专票没有机器编码怎么办 发票右上角的编码打不全怎么办 税票名称开错了怎么办 开票名称开错了怎么办 退休党员不交党费怎么办 cad打不出来字怎么办 用cad打不出来字怎么办 打字总打错字母怎么办 mac做ppt卡住了怎么办 mac的ppt卡住了怎么办 淘宝店铺被屏蔽了怎么办 淘宝申请售后卖家拒绝怎么办 淘宝投诉卖家入口关闭怎么办 遇见最喜欢孩子的父母怎么办 房屋备案表丢了怎么办 淘宝发布商品没有品牌怎么办 电子发票名称写错了怎么办 合同写错了划掉怎么办 进京证日期错了怎么办 买车时谈的协议与合同不一致怎么办 新车上牌找不到流水号怎么办 开票数量比入库数量少怎么办