概述
文章目录
- Room
- 介绍和依赖
- 简单案列
- 代码优化
- RecyclerView
- CardView,波纹效果和网页跳转
- 增加隐藏
- 数据迁移
- 破坏式迁移
- SQL语句方式(※)
Room
介绍和依赖
官网地址: https://developer.android.google.cn/jetpack/androidx/releases/room
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// // optional - RxJava support for Room
// implementation "androidx.room:room-rxjava2:$room_version"
//
// // optional - Guava support for Room, including Optional and ListenableFuture
// implementation "androidx.room:room-guava:$room_version"
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
简单案列
-
导入依赖
def room_version = "2.2.5" implementation "androidx.room:room-runtime:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" testImplementation "androidx.room:room-testing:$room_version"
-
编写实体类
package com.example.roombasic; import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; /** * @author codekiller * @date 2020/11/16 17:42 * @Description TODO */ @Entity public class Word { @PrimaryKey(autoGenerate = true) private int id; @ColumnInfo(name = "english_word") private String word; @ColumnInfo(name = "chinese_meaning") private String chineseMeaning; public Word(){} public Word(String word, String chineseMeaning) { this.word = word; this.chineseMeaning = chineseMeaning; } public int getId() { return id; } public void setId(int id) { this.id = id; } public Word setIdc(int id){ this.id = id; return this; } public String getWord() { return word; } public void setWord(String word) { this.word = word; } public String getChineseMeaning() { return chineseMeaning; } public void setChineseMeaning(String chineseMeaning) { this.chineseMeaning = chineseMeaning; } }
-
编写数据库操作Dao类
package com.example.roombasic; import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.Query; import androidx.room.Update; import java.util.List; /** * @author codekiller * @date 2020/11/16 17:44 * @Description Dao: Database Access Object */ @Dao public interface WordDao { @Insert void insertWords(Word... words); @Update void updateWords(Word... words); @Delete void deleteWords(Word... words); @Query("DELETE FROM WORD") void deleteAllWords(); @Query("SELECT * FROM WORD ORDER BY ID DESC") List<Word> getAllWords(); }
-
数据库类
@Database(entities = {Word.class}, version = 1, exportSchema = false) public abstract class WordDatabase extends RoomDatabase { public abstract WordDao getWordDao(); }
-
界面
-
具体的数据库操作
package com.example.roombasic; import androidx.appcompat.app.AppCompatActivity; import androidx.room.Room; import androidx.room.util.StringUtil; import android.os.Bundle; import android.widget.Button; import android.widget.TextView; import java.util.List; public class MainActivity extends AppCompatActivity { WordDatabase wordDatabase; WordDao wordDao; TextView textView; Button insertButton,updateButton,clearButton,deleteButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); wordDatabase = Room.databaseBuilder(this,WordDatabase.class,"word_database") .allowMainThreadQueries() .build(); textView = findViewById(R.id.textView2); insertButton = findViewById(R.id.insertButton); updateButton = findViewById(R.id.updateButton); clearButton = findViewById(R.id.clearButton); deleteButton = findViewById(R.id.deleteButton); wordDao = wordDatabase.getWordDao(); updateView(); //插入操作 insertButton.setOnClickListener(v->{ Word word1 = new Word("Hello","你好"); Word word2 = new Word("World","世界"); wordDao.insertWords(word1,word2); updateView(); }); //更新操作 updateButton.setOnClickListener(v->{ Word word = new Word("spring","春天"); word.setId(1); wordDao.updateWords(word); updateView(); }); //清除操作 clearButton.setOnClickListener(v->{ wordDao.deleteAllWords(); updateView(); }); //删除操作 deleteButton.setOnClickListener(v->{ wordDao.deleteWords(new Word().setIdc(4)); updateView(); }); } void updateView(){ List<Word> words = wordDao.getAllWords(); String text = ""; for (int i=words.size()-1;i>=0;--i) { text += words.get(i).getId()+":"+words.get(i).getWord()+" = "+words.get(i).getChineseMeaning()+";n"; } textView.setText(text); } }
-
运行相关操作可以在我们的文件中看到
代码优化
在上面的例子中,我们可以看到,数据库的操作都是放在主线程里面进行执行的,这显然不是太好。而且我们的mainActivity里面代码太多了,现在对代码进行一些修改。
看下文件结构
-
Word不变
-
WordDao不变
-
WordDatabase,采用单例模式
@Database(entities = {Word.class}, version = 1, exportSchema = false) public abstract class WordDatabase extends RoomDatabase { private static WordDatabase INSTANCE; /** * @Description 单例获取 * @date 2020/11/17 8:14 * @param context * @return */ public static synchronized WordDatabase getDatabase(Context context){ if(INSTANCE == null){ INSTANCE = Room.databaseBuilder(context, WordDatabase.class, "word_database") .allowMainThreadQueries() .build(); } return INSTANCE; } public abstract WordDao getWordDao(); }
-
WordRepository,封装数据库的操作
public class WordRepository { private LiveData<List<Word>> allWordsLive; private WordDao wordDao; public WordRepository(Context context) { WordDatabase wordDatabase = WordDatabase.getDatabase(context); wordDao = wordDatabase.getWordDao(); allWordsLive = wordDao.getAllWords(); } public LiveData<List<Word>> getAllWordsLive() { return allWordsLive; } public void insertWords(Word... words) { new InsertAsyncTask(wordDao).doInBackground(words); } public void updateWords(Word... words) { new UpdateAsyncTask(wordDao).doInBackground(words); } public void deleteWords(Word... words) { new DeleteAsyncTask(wordDao).doInBackground(words); } public void deleteAllWords() { new DeleteAllAsyncTask(wordDao).doInBackground(); } static class InsertAsyncTask extends AsyncTask<Word, Void, Void> { private WordDao wordDao; public InsertAsyncTask(WordDao wordDao) { this.wordDao = wordDao; } @Override protected Void doInBackground(Word... words) { wordDao.insertWords(words); return null; } } static class UpdateAsyncTask extends AsyncTask<Word, Void, Void> { private WordDao wordDao; public UpdateAsyncTask(WordDao wordDao) { this.wordDao = wordDao; } @Override protected Void doInBackground(Word... words) { wordDao.updateWords(words); return null; } } static class DeleteAsyncTask extends AsyncTask<Word, Void, Void> { private WordDao wordDao; public DeleteAsyncTask(WordDao wordDao) { this.wordDao = wordDao; } @Override protected Void doInBackground(Word... words) { wordDao.deleteWords(words); return null; } } static class DeleteAllAsyncTask extends AsyncTask<Void, Void, Void> { private WordDao wordDao; public DeleteAllAsyncTask(WordDao wordDao) { this.wordDao = wordDao; } @Override protecteds Void doInBackground(Void... voids) { this.wordDao.deleteAllWords(); return null; } } }
注意一点:AsyncTask已经被弃用了
-
WordViewModel
public class WordVIewModel extends AndroidViewModel { private WordRepository wordRepository; public WordVIewModel(@NonNull Application application) { super(application); wordRepository = new WordRepository(application); } public LiveData<List<Word>> getAllWordsLive() { return wordRepository.getAllWordsLive(); } public void insertWords(Word... words) { wordRepository.insertWords(words); } public void updateWords(Word... words) { wordRepository.updateWords(words); } public void deleteWords(Word... words) { wordRepository.deleteWords(words); } public void deleteAllWords() { wordRepository.deleteAllWords(); } }
-
MainActivity
public class MainActivity extends AppCompatActivity { TextView textView; Button insertButton,updateButton,clearButton,deleteButton; private WordVIewModel wordVIewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); wordVIewModel = new ViewModelProvider(this).get(WordVIewModel.class); textView = findViewById(R.id.textView2); insertButton = findViewById(R.id.insertButton); updateButton = findViewById(R.id.updateButton); clearButton = findViewById(R.id.clearButton); deleteButton = findViewById(R.id.deleteButton); wordVIewModel.getAllWordsLive().observe(this,(words)->{ StringBuilder text = new StringBuilder(); for (int i=words.size()-1;i>=0;--i) { text.append(words.get(i).getId()).append(":").append(words.get(i).getWord()).append(" = ").append(words.get(i).getChineseMeaning()).append(";n"); } textView.setText(text.toString()); }); //插入操作 insertButton.setOnClickListener(v->{ Word word1 = new Word("Hello","你好"); Word word2 = new Word("World","世界"); wordVIewModel.insertWords(word1,word2); }); //更新操作 updateButton.setOnClickListener(v->{ Word word = new Word("spring","春天"); word.setId(1); wordVIewModel.updateWords(word); }); //清除操作 clearButton.setOnClickListener(v->{ wordVIewModel.deleteAllWords(); }); //删除操作 deleteButton.setOnClickListener(v->{ wordVIewModel.deleteWords(new Word().setIdc(10)); }); } }
RecyclerView
RecyclerView的优点
- 进行item回收复用
- RecyclerView封装了viewholder的回收复用,也就是说RecyclerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的逻辑被封装了,写起来更加简单。
- 提供了一种插拔式的体验,高度的解耦,异常的灵活,针对一个Item的显示RecyclerView专门抽取出了相应的类,来控制Item的显示,使其的扩展性非常强。例如:你想控制横向或者纵向滑动列表效果可以通过LinearLayoutManager这个类来进行控制(与GridView效果对应的是GridLayoutManager,与瀑布流对应的还StaggeredGridLayoutManager等),也就是说RecyclerView不再拘泥于ListView的线性展示方式,它也可以实现GridView的效果等多种效果。你想控制Item的分隔线,可以通过继承RecyclerView的ItemDecoration这个类,然后针对自己的业务需求去抒写代码。
- 可以控制Item增删的动画,可以通过ItemAnimator这个类进行控制,当然针对增删的动画,RecyclerView有其自己默认的实现。
首先修改一下插入操作代码
insertButton.setOnClickListener(v->{
String[] english = {
"Hello",
"World",
"Android",
"Google",
"Studio",
"Project",
"Database",
"Recycler",
"View",
"String",
"Value",
"Integer"
};
String[] chinese = {
"你好",
"世界",
"安卓系统",
"谷歌公司",
"工作室",
"项目",
"数据库",
"回收站",
"视图",
"字符串",
"价值",
"整数类型"
};
for(int i=0;i<chinese.length;i++){
wordVIewModel.insertWords(new Word(english[i], chinese[i]));
}
});
使用RecyclerView
创建layout
创建元素的layout
创建一个Adapter
package com.example.roombasic;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
/**
* @author codekiller
* @date 2020/11/17 9:20
* @Description TODO
*/
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
List<Word> allWords = new ArrayList<>();
public void setAllWords(List<Word> allWords){
this.allWords = allWords;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View itemView = layoutInflater.inflate(R.layout.cell_normal,parent,false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Word word = allWords.get(position);
holder.textViewNumber.setText(String.valueOf(position+1));
holder.textViewEnglish.setText(word.getWord());
holder.textViewChinese.setText(word.getChineseMeaning());
}
@Override
public int getItemCount() {
return allWords.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
TextView textViewNumber, textViewEnglish, textViewChinese;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
textViewNumber = itemView.findViewById(R.id.textViewNumber);
textViewChinese = itemView.findViewById(R.id.textViewChinese);
textViewEnglish = itemView.findViewById(R.id.textViewEnglish);
}
}
}
修改MainAdapter代码
package com.example.roombasic;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.room.Room;
import androidx.room.util.StringUtil;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import java.util.List;
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
Button insertButton,updateButton,clearButton,deleteButton;
MyAdapter myAdapter;
private WordVIewModel wordVIewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wordVIewModel = new ViewModelProvider(this).get(WordVIewModel.class);
insertButton = findViewById(R.id.insertButton);
updateButton = findViewById(R.id.updateButton);
clearButton = findViewById(R.id.clearButton);
deleteButton = findViewById(R.id.deleteButton);
recyclerView = findViewById(R.id.recyclerView);
myAdapter = new MyAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(myAdapter);
wordVIewModel.getAllWordsLive().observe(this,(words)->{
myAdapter.setAllWords(words);
myAdapter.notifyDataSetChanged();
});
//插入操作
insertButton.setOnClickListener(v->{
String[] english = {
"Hello",
"World",
"Android",
"Google",
"Studio",
"Project",
"Database",
"Recycler",
"View",
"String",
"Value",
"Integer"
};
String[] chinese = {
"你好",
"世界",
"安卓系统",
"谷歌公司",
"工作室",
"项目",
"数据库",
"回收站",
"视图",
"字符串",
"价值",
"整数类型"
};
for(int i=0;i<chinese.length;i++){
wordVIewModel.insertWords(new Word(english[i], chinese[i]));
}
});
//更新操作
updateButton.setOnClickListener(v->{
Word word = new Word("spring","春天");
word.setId(1);
wordVIewModel.updateWords(word);
});
//清除操作
clearButton.setOnClickListener(v->{
wordVIewModel.deleteAllWords();
});
//删除操作
deleteButton.setOnClickListener(v->{
wordVIewModel.deleteWords(new Word().setIdc(10));
});
}
}
CardView,波纹效果和网页跳转
创建一个新的layout,记得三个textView的id,和cell_normal中相同的就行
设置一下margin,CardView下修改
修改Adapter
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View itemView = layoutInflater.inflate(R.layout.cell_card,parent,false);
return new MyViewHolder(itemView);
}
波纹效果
相当于
再修改背景样式
运行之后发现,可点击,但是波纹效果是在后面的,此时要修改一下前景
效果图演示
这里有一个小功能,就是跳转到有道词典了。修改adapter
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Word word = allWords.get(position);
holder.textViewNumber.setText(String.valueOf(position+1));
holder.textViewEnglish.setText(word.getWord());
holder.textViewChinese.setText(word.getChineseMeaning());
holder.itemView.setOnClickListener(v->{
Uri uri = Uri.parse("https://m.youdao.com/dict?le=eng&q=" + holder.textViewEnglish.getText());
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
holder.itemView.getContext().startActivity(intent);
});
}
增加隐藏
-
增加一个switch
-
增加一个字段
@ColumnInfo(name = "chinese_invisible") private boolean chineseInvisible;
-
修改adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { private List<Word> allWords = new ArrayList<>(); private WordVIewModel wordVIewModel; public MyAdapter(WordVIewModel wordVIewModel) { this.wordVIewModel = wordVIewModel; } public void setAllWords(List<Word> allWords){ this.allWords = allWords; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); View itemView = layoutInflater.inflate(R.layout.cell_card2,parent,false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { Word word = allWords.get(position); holder.textViewNumber.setText(String.valueOf(position+1)); holder.textViewEnglish.setText(word.getWord()); holder.textViewChinese.setText(word.getChineseMeaning()); holder.aSwitchChineseInvisible.setOnCheckedChangeListener(null); //控制显示和隐藏中文 if(word.isChineseInvisible()){ //GONE 会隐藏,而且会释放空间(改变位置),而invisible仅仅是不显示。 holder.textViewChinese.setVisibility(View.GONE); holder.aSwitchChineseInvisible.setChecked(true); } else { holder.textViewChinese.setVisibility(View.VISIBLE); holder.aSwitchChineseInvisible.setChecked(false); } //进行有道词典搜索 holder.itemView.setOnClickListener(v->{ Uri uri = Uri.parse("https://m.youdao.com/dict?le=eng&q=" + holder.textViewEnglish.getText()); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); holder.itemView.getContext().startActivity(intent); }); //switch监听 holder.aSwitchChineseInvisible.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked){ holder.textViewChinese.setVisibility(View.GONE); word.setChineseInvisible(true); wordVIewModel.updateWords(word); }else{ holder.textViewChinese.setVisibility(View.VISIBLE); word.setChineseInvisible(false); wordVIewModel.updateWords(word); } } }); } @Override public int getItemCount() { return allWords.size(); } static class MyViewHolder extends RecyclerView.ViewHolder{ TextView textViewNumber, textViewEnglish, textViewChinese; Switch aSwitchChineseInvisible; public MyViewHolder(@NonNull View itemView) { super(itemView); textViewNumber = itemView.findViewById(R.id.textViewNumber); textViewChinese = itemView.findViewById(R.id.textViewChinese); textViewEnglish = itemView.findViewById(R.id.textViewEnglish); aSwitchChineseInvisible = itemView.findViewById(R.id.chineseInvisible); } } }
这一点尤为重要
holder.aSwitchChineseInvisible.setOnCheckedChangeListener(null);
-
修改MainActvity
一定要避免两次刷新,不然后卡顿
wordVIewModel.getAllWordsLive().observe(this,(words)->{ int temp = myAdapter.getItemCount(); myAdapter.setAllWords(words); //避免两种刷新冲突 if(temp != words.size()) { myAdapter.notifyDataSetChanged(); } });
数据迁移
我们此时有一个需求,在原有的word表中增加一个字段,应该怎么做?
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name = "english_word")
private String word;
@ColumnInfo(name = "chinese_meaning")
private String chineseMeaning;
@ColumnInfo(name = "bar_data")
private boolean bar;
破坏式迁移
修改数据库的version和增加.fallbackToDestructiveMigration()
,这种方式就是将现有结构清空,然后创建新的数据库,是一种破坏式的创建。不推荐
@Database(entities = {Word.class}, version = 2, exportSchema = false)
public abstract class WordDatabase extends RoomDatabase {
private static WordDatabase INSTANCE;
/**
* @Description 单例获取
* @date 2020/11/17 8:14
* @param context
* @return
*/
public static synchronized WordDatabase getDatabase(Context context){
if(INSTANCE == null){
INSTANCE = Room.databaseBuilder(context, WordDatabase.class, "word_database")
//.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build();
}
return INSTANCE;
}
public abstract WordDao getWordDao();
}
SQL语句方式(※)
其实就是运行一个sql语句,对表结构进行修改
@Database(entities = {Word.class}, version = 2, exportSchema = false)
public abstract class WordDatabase extends RoomDatabase {
private static WordDatabase INSTANCE;
/**
* @Description 单例获取
* @date 2020/11/17 8:14
* @param context
* @return
*/
public static synchronized WordDatabase getDatabase(Context context){
if(INSTANCE == null){
INSTANCE = Room.databaseBuilder(context, WordDatabase.class, "word_database")
//.allowMainThreadQueries()
.addMigrations(MIGRATION_1_2)
.build();
}
return INSTANCE;
}
public abstract WordDao getWordDao();
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("alter table word add column bar_data INTEGER not null default 1");
}
};
}
查看结果,将我们的数据库表信息存储到本地,存储前记得刷新!!!然后用DB Brower for SQLite打开word_database文件。
通过这种方式,我们也能执行任何sql语句
最后
以上就是活泼月光为你收集整理的Android-Room,RecyclerView,CardView的简单使用以及数据迁移的全部内容,希望文章能够帮你解决Android-Room,RecyclerView,CardView的简单使用以及数据迁移所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复