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
- Android应用之《宋词三百首》(一)
- Android应用之《宋词三百首》(一)
- Android应用之《宋词三百首》(二)
- Android应用之《宋词三百首》(二)
- 宋词
- 宋词
- 哲理故事三百篇(一)
- 躺尸三百首
- 唐山三百首
- Android版宋词赏析 测试版
- 组图:诗情画意----配图宋词十四首
- android之SQLite数据库应用(一)
- Android开发之AppWidget应用(一)
- Android开发之AppWidget应用(一)
- Android开发之AppWidget应用(一)
- Android高级应用之Handler(一)
- android之Email应用问题解决(一)
- android之时钟应用问题解决(一)
- Hdu 1085 Holding Bin-Laden Captive! 母函数
- 类似微信,微博,QQ的头像截图功能, 图片支持缩放
- SEO新手教学:如何给新站选择关键词。
- 小学生作文
- cocos2dx 2.2.3在Windows 7 64bit上搭建开发环境
- Android应用之《宋词三百首》(一)
- redis-dynamic string
- 晚上不能吃的食物
- 小学生作文
- 关于pr文件导入的问题
- 用了Mj下拉刷新 An instance 0xca90200 of class UITableView was deallocated while key value observers were s
- svn eclipse
- no permissions fastboot 解决
- CentOS开机启动服务