和我一起开发Android应用(三)

您所在的位置:网站首页 可以听单词的app 和我一起开发Android应用(三)

和我一起开发Android应用(三)

2024-07-16 01:52:41| 来源: 网络整理| 查看: 265

  接上一讲。本节我们把词典功能基本实现,首先上一个效果图,我发现大家比较关心界面方面的东西,我之前写的一个关于QQ界面的项目就很受欢迎,当然我现在能写出远比那个好看的界面。但是我想一个应用最核心的东西不完全在界面,一个好的创意,一个好的后台服务才是成功的关键,这也是我不断学习的方向。

  另外我发现在百度搜“悦词背单词91”搜索结果全是我在博客园的博文了。。。所以我把这个项目在91应用市场的下载地址粘上来吧,十分欢迎大家试用一下,有什么改进的意见请写在下面的评论里!地址:http://apk.91.com/Soft/Android/com.carlos.yueci-4.html

 

  今天我们就实现这个界面,一个能查词的词典。

  

  为了明确思路,把上一节的项目功能分析拷贝过来:

 功能分析:

功能1、查单词。

  实现方法:金山词霸开放平台提供了一个开放API,通过Http访问金山词霸API提供的URL,可以获得一个XML文档,这个文档就包含了要查询的单词的释义、例句、音标、声音的地址。通过解析该XML就可以获得单词的所有信息。

  所用到的技术:

    1)Http访问网络,并下载网络文件

    2)对SD卡进行操作,从SD卡(这里的SD卡是指手机默认的存储卡,因为有些手机既能能插SD卡又有内部存储,这里不涉及这个问题)中读取文件,和把从网络下载的文件存进SD卡。

    3)解析XML文件

    4)播放音乐(这个我后来封装成了一个类,专门从网络上查询某个单词,解析XML文件,并且将下载的Mp3文件存在SD卡中,然后播放该Mp3文件)

    5)数据库,这里涉及到第一个数据库,每查找一个单词之后,就会将该单词和释义存储到一个SQLite数据库中。这样一来,下一次查找这个单词时,先访问数据库,看看数据库中有没有这个单词,若有,就不用访问网络了。

   根据上面的分析,可见我们已经实现了Http网络模块,XML文件解析,还有三个内容,我们先实现这三个功能,然后再把UI搭建起来。

  (一)后台功能实现

    一、对SD进行操作。FileUtils类,一个专门用于实现讲输入流写入文件,从文件中获得输入流的类,当我们从网上搜索一个单词后,会把它对应的音频Mp3存储在本地的一个文件夹,这样当我们再查这个单词或者在背单词时遇到这个单词时,就不用再访问网络了。

package com.carlos.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import android.os.Environment; public class FileUtils { private String SDPATH; public FileUtils(){ SDPATH=Environment.getExternalStorageDirectory()+"/"; //System.out.println(Environment.getExternalStorageDirectory().getAbsolutePath()); } //创建文件,一定不会返回空 /** * * @param path 直接创建文件即可,无需考虑文件夹有没有创建,若文件已存在返回null * @param fileName * @return */ public File createSDFile(String path,String fileName){ File file=null; createSDDir(path); try{ file=new File(SDPATH+path+fileName); if(file.exists() && file.isFile()){ return null; } file.createNewFile(); //创建文件 }catch(Exception e){ e.printStackTrace(); } return file; } //创建目录,如果存在同名文件夹则返回该文件夹,否则创建文件 public File createSDDir(String dirName){ File dir=new File(SDPATH+dirName); if(dir.exists() && dir.isDirectory()){ return dir; } dir.mkdirs(); //可创建多级文件夹 return dir; } //这里写相对目录 public ArrayList listContentsOfFile(String path){ ArrayList list=new ArrayList(); File file=new File(SDPATH+path); File[] fileList=file.listFiles(); if(fileList==null) return list; for(int i=0; i0){ if(isOverWrite==false)//首先看看数据库中有没有这个单词,若词典库中已经有了这一个单词,所以不再操作 return; else{ //执行更新操作 dbW.update(tableName, values, "word=?",new String[]{ w.getWord()}); } }else{ dbW.insert(tableName, null, values); //这里可能会发生空指针异常,到时候考虑 } }catch(Exception e){ }finally{ if(cursor!=null) cursor.close(); } } //判断数据库中是否存在某个单词 public boolean isWordExist(String word){ Cursor cursor=null; try{ cursor=dbR.query(tableName, new String[]{"word"}, "word=?", new String[]{word}, null, null, null); if(cursor.getCount()>0){ cursor.close(); return true; }else{ cursor.close(); return false; } }finally{ if(cursor!=null) cursor.close(); } } //从单词库中获得某个单词的信息,如果词库中没有改单词,那么返回null public WordValue getWordFromDict(String searchedWord){ WordValue w=new WordValue();//预防空指针异常 // db.execSQL("create table dict(word text,pse text,prone text,psa text,prona text," + // "interpret text, sentorig text, senttrans text)"); String[] columns=new String[]{"word", "pse","prone","psa","prona","interpret","sentorig","senttrans"}; String[] strArray=new String[8]; Cursor cursor=dbR.query(tableName, columns, "word=?", new String[]{searchedWord}, null, null, null); while(cursor.moveToNext()){ for(int i=0;i256) //是中文,或其他语言的的简略判断 tempWord="_"+URLEncoder.encode(tempWord); InputStream in=null; String str=null; try{ String tempUrl=NetOperator.iCiBaURL1+tempWord+NetOperator.iCiBaURL2; in=NetOperator.getInputStreamByUrl(tempUrl); if(in!=null){ new FileUtils().saveInputStreamToFile(in, "", "gfdgf.txt"); XMLParser xmlParser=new XMLParser(); InputStreamReader reader=new InputStreamReader(in,"utf-8"); JinShanContentHandler contentHandler=new JinShanContentHandler(); xmlParser.parseJinShanXml(contentHandler, new InputSource(reader)); wordValue=contentHandler.getWordValue(); wordValue.setWord(searchedWord); } }catch(Exception e){ e.printStackTrace(); } return wordValue; }

//以下几个方法都是获得某个单词的某一项信息,基本的思路还是先获得全部信息WordValue然后调用WordValue的get方法获得具体的信息。

//获取发音文件地址 public String getPronEngUrl(String searchedWord){ Cursor cursor=dbR.query(tableName, new String[]{"prone"}, "word=?", new String[]{searchedWord}, null, null, null); if(cursor.moveToNext()==false){ cursor.close(); return null; } String str=cursor.getString(cursor.getColumnIndex("prone")); cursor.close(); return str; } public String getPronUSAUrl(String searchedWord){ Cursor cursor=dbR.query(tableName, new String[]{"prona"}, "word=?", new String[]{searchedWord}, null, null, null); if(cursor.moveToNext()==false){ cursor.close(); return null; } String str=cursor.getString(cursor.getColumnIndex("prona")); cursor.close(); return str; } //获取音标 public String getPsEng(String searchedWord){ Cursor cursor=dbR.query(tableName, new String[]{"pse"}, "word=?", new String[]{searchedWord}, null, null, null); if(cursor.moveToNext()==false){ cursor.close(); return null; } String str=cursor.getString(cursor.getColumnIndex("pse")); cursor.close(); return str; } public String getPsUSA(String searchedWord){ Cursor cursor=dbR.query(tableName, new String[]{"psa"}, "word=?", new String[]{searchedWord}, null, null, null); if(cursor.moveToNext()==false){ cursor.close(); return null; } String str=cursor.getString(cursor.getColumnIndex("psa")); cursor.close(); return str; } /** * 若没有句子那么返回的链表的长度为0,若单词不存在那么直接返回null,所以最好对null和长度同时检验 * @param searchedWord * @return */ public String getInterpret(String searchedWord){ Cursor cursor=dbR.query(tableName, new String[]{"interpret"}, "word=?", new String[]{searchedWord}, null, null, null); if(cursor.moveToNext()==false){ cursor.close(); return null; } String str=cursor.getString(cursor.getColumnIndex("interpret")); cursor.close(); return str; } }

有了这个类以后大家可能会有一个比较明确的思路了,在接下来将UI时Activity中会实例化一个Dict对象,直接调用它的某些方法完成操作。

 

    三、音频播放

  当我们查到一个单词时,可能想听一听这个单词的发音,这时就需要根据数据库中prone/prona这一列的音频地址,从网络上获得音频输入流下载到SD卡,然后调用MediaPlayer播放音乐,这是一个一系列的动作,再后面背单词时因为要听单词的发音,会更多的用到这个操作,为此我封装了一个方法,专门完成这组操作。

package com.carlos.music; import java.io.InputStream; import java.io.InputStreamReader; import org.xml.sax.InputSource; import com.carlos.internet.NetOperator; import com.carlos.text_parser.JinShanContentHandler; import com.carlos.text_parser.XMLParser; import com.carlos.utils.FileUtils; import com.carlos.wordcontainer.Dict; import com.carlos.wordcontainer.WordValue; import com.carlos.yueci.ReciteActivity; import android.content.Context; import android.media.MediaPlayer; import android.net.Uri; public class Mp3Player { public final static String MUSIC_ENG_RELATIVE_PATH="yueci/sounds/sounds_EN/"; public final static String MUSIC_USA_RELATIVE_PATH="yueci/sounds/sounds_US/"; public final static int ENGLISH_ACCENT=0; public final static int USA_ACCENT=1; public Context context=null; public String tableName=null; public MediaPlayer mediaPlayer=null; FileUtils fileU=null; Dict dict=null; public boolean isMusicPermitted=true; //用于对是否播放音乐进行保护性设置,当该变量为false时,可以阻止一次音乐播放 public Mp3Player(Context context,String tableName){ this.context=context; this.tableName=tableName; fileU=new FileUtils(); dict=new Dict(context,tableName); isMusicPermitted=true; } /** * 首先先看一下SD卡上有没有,若有则播放,没有执行下一步 * 看一下dict表中有没有单词的记录,若有,看一下发音字段是不是有美式发音或英式发音,若无则退出 * 若没有字段记录,访问网络下载Mp3然后播放 * 一个Activity中一般只能有一个Voice成员变量,对应的也就只有一个MediaPlayer对象,这样才能对播放 * 状态进行有效控制 * 该方法原则上只能在线程中调用 * @param word * @param accent */ public void playMusicByWord(String word , int accent,boolean isAllowedToUseInternet, boolean isPlayRightNow){ if(word==null || word.length()

是不是有点晕呢?我把布局分成几块就懂了。

Part One:

这是顶部的横条,这是一个RelativeLayout,里面有以后Back 按钮, 搜索按钮, 删除EditText内容的按钮,还有一个EditText,对应的代码如下:

 

这一块就是TextView ImageButton(加入单词本)进行的一个Relative布局,没什么特别之处:布局代码如下

这是两个TextView ,释义的TextView使用了一个LayerList做背景,布局代码:

layer_list_dict_item_back layerList位于drawable文件夹中,可搜索layerlist的使用方法学习

 

这是一个ListView,它也采用了layerlist作背景。

 

设计好布局文件后,我们很容易理解各个控件的作用,接下来我们就要写Activity子类,用于实例化各个控件,设置监听器,实现各个按钮的功能。

在写Activity之前,首先就成员变量的命名做一个说明,因为个Activity中的控件很多,如果随便命名很容易混乱,这里我采用了一种根据属性和类命名的方法,大家可以参考:

比如 上面有一个“放大镜”的搜索按钮,这是一个ImageButton 同时它是属于DictActivity的,它的功能是开始查单词,那么就将这个ImageButton对象命名为:

           ImageButton  imageBtnDictSearch=(ImageButton)findViewById(R.id.image_btn_dict_search);

在设置布局文件后把id也设置成相同的名字,这样就不会搞混了,根据我的经验这种命名方式非常高效。

下面就给出DictActivity类:

package com.carlos.yueci; import java.security.KeyStore; import java.util.ArrayList; import java.util.Currency; import java.util.HashMap; import com.carlos.adapter.DictSentenceListAdapter; import com.carlos.database.DataBaseHelper; import com.carlos.music.Mp3Player; import com.carlos.yueci.R; import com.carlos.wordcontainer.Dict; import com.carlos.wordcontainer.WordValue; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.inputmethodservice.Keyboard.Key; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.method.ScrollingMovementMethod; import android.view.KeyCharacterMap.KeyData; import android.view.KeyEvent; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import android.widget.TextView.OnEditorActionListener; public class DictActivity extends Activity{ public TextView textDictWord=null; public TextView textDictPhonSymbolEng=null; public TextView textDictPhonSymbolUSA=null; public TextView textDictInterpret=null; public ListView listViewDictSentence=null; public ImageButton imageBtnDictAddToWordList=null; public ImageButton imageBtnDictHornEng=null; public ImageButton imageBtnDictHornUSA=null; public ImageButton imageBtnDictSerach=null; public ImageButton imageBtnDictBackToGeneral=null; public ImageButton imageBtnDictDelteEditText=null; public Button buttonDictDialogConfirm=null; public Button buttonDictDialogCancel=null; public EditText editTextDictSearch=null; public Dict dict=null; public WordValue w=null; public DataBaseHelper dbGlossaryHelper=null; public SQLiteDatabase dbGlossaryR=null; public SQLiteDatabase dbGlossaryW=null; public Mp3Player mp3Box=null; public static String searchedWord=null; public Handler dictHandler=null; public void initial(){ textDictWord=(TextView) findViewById(R.id.text_dict_word); textDictInterpret=(TextView)findViewById(R.id.text_dict_interpret); textDictPhonSymbolEng=(TextView)findViewById(R.id.text_dict_phosymbol_eng); textDictPhonSymbolUSA=(TextView)findViewById(R.id.text_dict_phosymbol_usa); listViewDictSentence=(ListView)findViewById(R.id.listview_dict_sentence); imageBtnDictAddToWordList=(ImageButton)findViewById(R.id.image_btn_dict_add_to_wordlist); imageBtnDictBackToGeneral=(ImageButton)findViewById(R.id.image_btn_dict_back_to_general); imageBtnDictHornEng=(ImageButton)findViewById(R.id.image_btn_dict_horn_accent_eng); imageBtnDictHornUSA=(ImageButton)findViewById(R.id.image_btn_dict_horn_accent_usa); imageBtnDictSerach=(ImageButton)findViewById(R.id.image_btn_dict_search); imageBtnDictDelteEditText=(ImageButton)findViewById(R.id.image_btn_dict_delete_all); editTextDictSearch=(EditText)findViewById(R.id.edit_text_dict); editTextDictSearch.setOnEditorActionListener(new EditTextDictEditActionLis()); dict=new Dict(DictActivity.this, "dict"); mp3Box=new Mp3Player(DictActivity.this, "dict"); dbGlossaryHelper=new DataBaseHelper(DictActivity.this, "glossary"); dbGlossaryR=dbGlossaryHelper.getReadableDatabase(); dbGlossaryW=dbGlossaryHelper.getWritableDatabase(); dictHandler=new Handler(Looper.getMainLooper()); //对searchedWord进行初始化 Intent intent=this.getIntent(); searchedWord=intent.getStringExtra("word"); if(searchedWord==null) searchedWord=""; //设置查找的文本 textDictWord.setText(searchedWord); } /** * 该方法可能需要访问网络,因此放在线程里进行 * @param word */ public void searchWord(String word){ //调用该方法后首先初始化界面 dictHandler.post(new RunnableDictSetTextInterface(searchedWord, "", "", "", null, null)); w=null; //对w进行初始化 if(dict.isWordExist(word)==false){ //数据库中没有单词记录,从网络上进行同步 if((w=dict.getWordFromInternet(word))==null ||w.getWord().equals("")){ return; } //错词不添加进词典 dict.insertWordToDict(w, true); //默认添加到词典中 }//能走到这一步说明从网上同步成功,数据库中一定存在单词记录 w=dict.getWordFromDict(word); if(w==null){ //这里又进一步做了保护,若词典中还是没有,那么用空字符串代替 w=new WordValue(); } String searchStr=w.getWord(); String phoSymEng=w.getPsE(); String phoSymUSA=w.getPsA(); String interpret=w.getInterpret(); ArrayList sentList=w.getOrigList(); //一定不会是null ArrayList sentInChineseList=w.getTransList(); dictHandler.post(new RunnableDictSetTextInterface(searchedWord, phoSymEng, phoSymUSA, interpret, sentList, sentInChineseList)); if(phoSymEng.equals("")==false && phoSymUSA.equals("")==false){ //只有有音标时才去下载音乐 mp3Box.playMusicByWord(searchedWord, Mp3Player.ENGLISH_ACCENT, true, false); mp3Box.playMusicByWord(searchedWord, Mp3Player.USA_ACCENT, true, false); } } public void setOnClickLis(){ imageBtnDictBackToGeneral.setOnClickListener(new IBDictBackToGeneralClickLis() ); imageBtnDictHornEng.setOnClickListener(new IBDictPlayMusicByAccentClickLis(Mp3Player.ENGLISH_ACCENT)); imageBtnDictHornUSA.setOnClickListener(new IBDictPlayMusicByAccentClickLis(Mp3Player.USA_ACCENT)); imageBtnDictAddToWordList.setOnClickListener(new IBDictAddWordToGlossaryClickLis()); imageBtnDictDelteEditText.setOnClickListener(new IBDictDeleteEditTextClickLis()); imageBtnDictSerach.setOnClickListener(new IBDictSearchClickLis()); } public void showAddDialog(){ if(searchedWord==null) return; AlertDialog dialog=new AlertDialog.Builder(DictActivity.this).create(); dialog.show(); Window window=dialog.getWindow(); window.setContentView(R.layout.dialog_if_layout); buttonDictDialogConfirm=(Button)window.findViewById(R.id.dialog_confirm); buttonDictDialogCancel=(Button)window.findViewById(R.id.dialog_cancel); buttonDictDialogConfirm.setOnClickListener(new BDictDialogConfirmClickLis(dialog)); buttonDictDialogCancel.setOnClickListener(new BDictDialogCancelClickLis(dialog)); TextView dialogText=(TextView)window.findViewById(R.id.dialog_text); dialogText.setText("把"+searchedWord+"添加到单词本?"); } public void insertWordToGlossary(){ if(w==null || w.getInterpret().equals("")){ Toast.makeText(DictActivity.this, "单词格式错误", Toast.LENGTH_SHORT).show(); return; //若是不是有效单词,那么将不能添加到单词本 } boolean isSuccess=dbGlossaryHelper.insertWordInfoToDataBase(searchedWord, w.getInterpret(), false); if(isSuccess){ Toast.makeText(DictActivity.this, "添加成功", Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(DictActivity.this, "单词已存在", Toast.LENGTH_SHORT).show(); } } @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_dict); initial(); setOnClickLis(); new ThreadDictSearchWordAndSetInterface().start(); } @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); mp3Box.isMusicPermitted=true; } @Override protected void onPause() { // TODO Auto-generated method stub mp3Box.isMusicPermitted=false; super.onPause(); } public class ThreadDictSearchWordAndSetInterface extends Thread{ @Override public void run() { // TODO Auto-generated method stub super.run(); searchWord(searchedWord); } } public class RunnableDictSetTextInterface implements Runnable{ String searchStr=null; String phoSymEng=null; String phoSymUSA=null; String interpret=null; ArrayList sentList=null; ArrayList sentInChineseList=null; public RunnableDictSetTextInterface(String searchStr, String phoSymEng, String phoSymUSA, String interpret, ArrayList sentList, ArrayList sentInChineseList) { super(); this.searchStr = searchStr; this.phoSymEng = "英["+phoSymEng+"]"; this.phoSymUSA = "美["+phoSymUSA+"]"; this.interpret = interpret; this.sentList = sentList; this.sentInChineseList = sentInChineseList; } @Override public void run() { // TODO Auto-generated method stub textDictWord.setText(searchStr); textDictPhonSymbolEng.setText(phoSymEng); textDictPhonSymbolUSA.setText(phoSymUSA); textDictInterpret.setText(interpret); if(sentList==null ||sentInChineseList==null){ //对链表为空进行防护 // textDictSentence.setText(""); return; } int count=0; if(sentList.size()

适配器类:

package com.carlos.adapter; import java.util.ArrayList; import java.util.HashMap; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; public class DictSentenceListAdapter extends BaseAdapter{ private Context context=null; private int resources; private ArrayList list=null; private String[] from; private int[] to; /** * 这里仿照的是SimpleAdapter的形参列表 * @param context * @param Resources * @param list * @param from * @param to */ public DictSentenceListAdapter(Context context, int resources, ArrayList list, String[] from, int[] to) { super(); this.context = context; this.resources = resources; this.list = list; this.from = from; this.to = to; } @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return arg0; } @Override public View getView(int position, View contentView, ViewGroup arg2) { // TODO Auto-generated method stub LayoutInflater inflater=LayoutInflater.from(context); contentView=inflater.inflate(resources, null); TextView text=(TextView)contentView.findViewById(to[0]); text.setText((String)(list.get(position).get(from[0]))); return contentView; } }

 

  这样,“悦词-i背单词”应用的查单词功能就完全实现了,另外这里的布局文件中用到了很多背景资源,

等所有UI搭建完成后我会把资源文件上传上来,今天的教程就到这里了~

 

 

 

 

 

 

 



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭