英语学习app开发笔记
最近在写一款英语学习的软件,现在按照功能实现的流程,把每个功能的实现方法整理出来,便于之后的修改。
按钮界面跳转功能
主界面代码
button1=(Button) findViewById(com.example.grt.AviationEnglish.R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Pilot.this,section_one.class);
startActivity(intent);
}
});
class section_one
public class section_one extends AppCompatActivity {
Button button5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_section_one);
button5=(Button) findViewById(R.id.button5);
button5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(section_one.this,letter_spell.class);
startActivity(intent);
}
});
}
}
activity_section_one.xml
数据库实现存储功能
使用了litepal 1.6.1。
LitePal是一款开源的Android数据库框架,采用对象关系映射(ORM)模式,将常用的数据库功能进行封装,可以不用写一行SQL语句就可以完成创建表、增删改查的操作。并且很轻量级,jar包不到100k,几乎零配置。
在build.grade中添加
implementation files('libs/litepal-1.6.1-src.jar')
import android.database.sqlite.SQLiteDatabase;
import org.litepal.crud.DataSupport;
import org.litepal.tablemanager.Connector;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
创建数据库中的词条类。具有词条类就可以按照词条的类别将数据存入数据库中。
package com.example.grt.English;
import org.litepal.crud.DataSupport;
public class english extends DataSupport{
private String entry;
private String word;
private int audio;
public english(String entry,String word,int audio) {
this.entry=entry;
this.word=word;
this.audio=audio;
}
public String getEntry() {
return entry;
}
public void setEntry(String entry) {
this.entry = entry;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public String getText() {
return " "+entry+" "+word;
}
public int getAudio() {
return audio;
}
public void setAudio(int audio) {
this.audio = audio;
}
}
从raw中读取文件
将词条以一定格式按照文本文件的格式存入raw文件夹中。
主界面代码
Resources res=this.getResources();
InputStream in=null;
BufferedReader br =null;
in=res.openRawResource(com.example.grt.English.R.raw.database);
String str;
br =new BufferedReader(new InputStreamReader(in,"GBK"));
int times=0;
while ((str=br.readLine())!=null){
}
将文件内容存入数据库
逐行读取文本文件,单词与释义被"-"符号分割,每行一个词条。
try {
SQLiteDatabase english = Connector.getDatabase();
List<pilot_english> newsList=new ArrayList<>();
Resources res=this.getResources();
InputStream in=null;
BufferedReader br =null;
in=res.openRawResource(com.example.grt.AviationEnglish.R.raw.database);
String str;
br =new BufferedReader(new InputStreamReader(in,"GBK"));
int times=0;
while ((str=br.readLine())!=null){
String[] tmp=str.split("-");
newsList.add(new english(tmp[0],tmp[1],audio[times]));
times=times+1;
if(times%100==0){
DataSupport.saveAll(newsList);
newsList.clear();
}
}
DataSupport.saveAll(newsList);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
适配器Adapter
Adapter是用来帮助填出数据的中间桥梁,简单点说:将各种数据以合适的形式显示在View中给用户看。Adapter有很多的接口,抽象类,子类可以使用。是一个可以仔细研究的内容。
由于搜索后的词条需要在listview中被显示出来,因此需要用到Adapter的知识点。
import android.widget.ArrayAdapter;
public class EntryAdapter extends ArrayAdapter {
private final int resourceId;
Context context;
public EntryAdapter(Context context, int textViewResourceId, List<pilot_english> objects) {
super(context, textViewResourceId, objects);
this.context=context;
resourceId = textViewResourceId;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final english english_entry = (pilot_english) getItem(position); // 获取当前项的实例
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//实例化一个对象
TextView list_item = (TextView) view.findViewById(R.id.entry_name);//获取该布局内的文本视图
list_item.setText(english_entry.getText());//为文本视图设置文本内容
return view;
}
}
未搜索时将部分项目显示在界面上
如同文曲星一样的电子辞典,在键入关键字前,listview上从第一个词条向下显示。
public class search extends AppCompatActivity{
private static List<english> entry_pool = new ArrayList<english>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
final ListView lisT=(ListView) findViewById(R.id.listview1);
for(int i=1;i<16;i++){
english entry=DataSupport.find(english.class, i);
entry_pool.add(entry);
}
EntryAdapter adapter=new EntryAdapter(search.this,R.layout.list_item,entry_pool);
ListView listview=(ListView)findViewById(R.id.listview1);
listview.setAdapter(adapter);
}
}
搜索栏使用
搜索栏为SearchView 类别,目前使用其onQueryTextSubmit()与onQueryTextChange()两个函数。
SearchView searchBar=(SearchView) findViewById(R.id.search);
final ListView lisT=(ListView) findViewById(R.id.listview1);
searchBar.setSubmitButtonEnabled(true);
searchBar.setBackgroundColor(Color.parseColor("#88d47c"));
searchBar.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
// 当点击搜索按钮时触发该方法
@Override
public boolean onQueryTextSubmit(String query) {
}
// 当搜索内容改变时触发该方法
@Override
public boolean onQueryTextChange(String newText) {
return true;
}
});
搜索并将结果显示在listview中
无论是onQueryTextSubmit(String query) 函数还是onQueryTextChange(String newText)函数,都会传入参数query 或是 newText,其实就是搜索栏中键入的内容。根据搜索栏中键入的内容,需要和数据库中的词条逐一进行比对。键入内容可能和单词相匹配,也有可能和词条相匹配,这样就需要把键入的字符串与它们做匹配。使用的代码为:
List<pilot_english> all=DataSupport.findAll(english.class);
for(int i=1;i<num;i++){
if(all.get(i).getEntry().contains(query)||all.get(i).getWord().contains(query)){
entry_pool.add(all.get(i));
}
主要使用字符串的contains()函数进行匹配。
SearchView函数
SearchView searchBar=(SearchView) findViewById(R.id.search);
final ListView lisT=(ListView) findViewById(R.id.listview1);
searchBar.setSubmitButtonEnabled(true);
searchBar.setBackgroundColor(Color.parseColor("#88d47c"));
listview.setAdapter(adapter);
searchBar.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
// 当点击搜索按钮时触发该方法
@Override
public boolean onQueryTextSubmit(String query) {
entry_pool.clear();
int num=DataSupport.count(english.class);
List<pilot_english> all=DataSupport.findAll(english.class);
for(int i=1;i<num;i++){
if(all.get(i).getEntry().contains(query)||all.get(i).getWord().contains(query)){
entry_pool.add(all.get(i));
}
}
EntryAdapter adapter=new EntryAdapter(search.this,R.layout.list_item,entry_pool);
ListView listview=(ListView)findViewById(R.id.listview1);
listview.setAdapter(adapter);
return true;
}
// 当搜索内容改变时触发该方法
@Override
public boolean onQueryTextChange(String newText) {
entry_pool.clear();
int num=DataSupport.count(english.class);
List<pilot_english> all=DataSupport.findAll(english.class);
for(int i=1;i<num;i++){if(all.get(i).getEntry().contains(newText)||all.get(i).getWord().contains(newText)){
entry_pool.add(all.get(i));
}
}
EntryAdapter adapter=new EntryAdapter(search.this,R.layout.list_item,entry_pool);
ListView listview=(ListView)findViewById(R.id.listview1);
listview.setAdapter(adapter);
return true;
}
});
搜索功能目前稍慢,可以尝试通过检索首字母的方式加快搜索速度
listview添加点击方法
通常点击listview中的词条,应该跳转到该词条对应的界面。可以在搜索界面对应的class类中添加如下代码,以实现点击相应功能。
ListView listview=(ListView)findViewById(R.id.listview1);
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String item = ((TextView)view).getText().toString();
Toast.makeText(search.this,"item=",Toast.LENGTH_LONG).show();
System.out.println("===OnItemClick(AdapterView<?> parent="+parent+",View view="+view+",int position="+position+",long id ="+id+")====");
}
});
音频播放功能 listview内部按钮点击事件
listview中每一条list包含了一个imagebutton,想设置点击imagebutton时的函数,需要在 Adapter类的getview中设置点击事件。这里通过ViewHolder中的button变量获取到view中imagebutton对应的ID,然后对其设置OnClickListener。
public class ViewHolder {
public ImageButton button;
public int audio;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder = new ViewHolder();
final pilot_english english_entry = (pilot_english) getItem(position); // 获取当前项的Fruit实例
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//实例化一个对象
TextView list_item = (TextView) view.findViewById(R.id.entry_name);//获取该布局内的文本视图
list_item.setText(english_entry.getText());//为文本视图设置文本内容
holder.button=(ImageButton) view.findViewById(R.id.imageButton);
holder.audio=english_entry.getAudio();
view.setTag(holder);
View.OnClickListener listener=new View.OnClickListener(){
@Override
public void onClick(View v)
{
MediaPlayer mp =MediaPlayer.create(context,holder.audio);
mp.start();
}
};
holder.button.setOnClickListener(listener);
return view;
}
界面背景图
界面设置纯色的方法:
在对应界面xml文件内设置 android:background
使用主流图片加载库Glide
有时背景需要加载图片时,容易因为图片在解析的过程中被弄的极大,导致内存溢出,导致不同机型上可能出现闪退的情况。Glide是主流的加载库之一,作为一个被google推荐的开源库,它有着跟随页面周期、支持gif和webp、支持多种数据源等特点,是一个值得进一步学习的图片加载库。
其使用简便,只需添加对应jar后加入如下代码。
在build.gradle
implementation files('libs/glide-3.7.0.jar')
import com.bumptech.glide.Glide;
int resource = com.example.grt.AviationEnglish.R.drawable.back_two;
ImageView imageView = (ImageView) findViewById(com.example.grt.AviationEnglish.R.id.imageView1);
imageView.setScaleType(ImageView.ScaleType. CENTER_CROP);
Glide.with(this).load(resource).into(imageView);