大家好!今天我试图解决下一个问题:我已经为语言列表创建了房间数据库,预先填充了五个准备好的对象,然后我试图将它们转移到spinner适配器中:
Language
对象的实体和DAO代码:
@Entity
public class Language {
@PrimaryKey
private long id;
@ColumnInfo(name = "language")
private String language;
public Language(String language) {
this.language = language;
}
public static Language[] populateData() {
return new Language[]{new Language("English"), new Language("French"), new Language(
"Spanish"), new Language("Russian"), new Language("Italian")};
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
@Dao
public interface LanguageDao {
@Query("SELECT * FROM language")
List<Language> getAll();
@Insert
void insertAll(Language... languages);
}
此外,我在AppDatabase
类中使用Singleton创建了数据库对象,如下所示:
@Database(entities = {Language.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
private static AppDatabase INSTANCE;
public abstract LanguageDao languageDao();
public synchronized static AppDatabase getInstance(Context context) {
if (INSTANCE == null) {
INSTANCE = buildDatabase(context);
}
return INSTANCE;
}
private static AppDatabase buildDatabase(final Context context) {
return Room.databaseBuilder(context, AppDatabase.class, "my-database")
.addCallback(new Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
Executors.newSingleThreadScheduledExecutor().execute(new Runnable() {
@Override
public void run() {
getInstance(context).languageDao()
.insertAll(Language.populateData());
}
});
}
})
.allowMainThreadQueries()
.build();
}
}
如您所见,我已将语言对象的预填充数据插入到数据库实例中。我知道这里不推荐allowMainThreadQueries()
方法(只是用它来简化当前的训练)。
此外,我创建了以下方法,该方法返回spinner对象并将其放入活动代码中:
private Spinner createLanguageSpinner(){
Spinner spinner = findViewById(R.id.language_spinner);
List<Language> languages = AppDatabase.getInstance(this).languageDao().getAll();
List<String>languageStrings = new LinkedList<>();
for(int i = 0; i < languages.size(); i++){
languageStrings.add(languages.get(i).getLanguage());
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line,
languageStrings);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
return spinner;
}
我的问题在这里:
List<Language> languages = AppDatabase.getInstance(this).languageDao().getAll();
我无法用预定义的对象填充当前列表,这导致空的微调器没有可供选择的选项。你能告诉我哪里出错吗?我还想听听有关如何简化适配器创建的意见。
答案 0 :(得分:0)
我参加聚会有点晚了,但是如果有人也有这个问题的话。
问题是您试图插入没有PrimaryKey id
值的新对象。结果,您在数据库中得到一个空表。
您要么应该手动设置id
值,例如:
@Entity
public class Language {
...
public Language(long id, String language) {
this.id = id; // or create method to generate a unique id as a PrimaryKey value must be unique
this.language = language;
}
public static Language[] populateData() {
return new Language[]{
new Language(1, "English"),
new Language(2, "French"),
new Language(3, "Spanish"),
new Language(4, "Russian"),
new Language(5, "Italian")
};
}
}
或使用PrimaryKey的autoGenerate
属性让SQLite生成唯一ID:
@PrimaryKey(autoGenerate = true)
private long id;
有关更多信息,请参见reference。
不需要对代码进行其他更改。
第二个问题:
我也想听听有关如何简化 创建适配器
您可以为微调器创建一个自定义适配器,并将List<Language>
直接传递给它:
public class MyAdapter extends BaseAdapter implements SpinnerAdapter {
private LayoutInflater mInflater;
private List<Language> mItems;
public MyAdapter(Context context, List<Language> items) {
mInflater = LayoutInflater.from(context);
mItems = items;
}
@Override
public int getCount() {
return mItems.size();
}
@Override
public Object getItem(int position) {
return mItems.get(position);
}
@Override
public long getItemId(int position) {
return mItems.get(position).getId();
}
// This is for the default ("idle") state of the spinner.
// You can use a custom layout or use the default one.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = mInflater.inflate(R.layout.spinner_item, parent, false);
}
Language item = (Language) getItem(position);
TextView textView = view.findViewById(R.id.text);
textView.setText(item.getTitle());
return view;
}
// Drop down item view as stated in the method name.
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = mInflater.inflate(R.layout.spinner_dropdown_item, parent, false);
}
Language item = (Language) getItem(position);
TextView textView = view.findViewById(R.id.text);
textView.setText(item.getTitle());
return view;
}
}
在您的活动中:
List<Language> languages = AppDatabase.getInstance(this).languageDao().getAll();
Spinner spinner = findViewById(R.id.spinner);
MyAdapter myAdapter = new MyAdapter(this, languages);
spinner.setAdapter(myAdapter);
请参见BaseAdapter和SpinnerAdapter参考。
或者您可以使用ArrayAdapter
并简单地重写对象的toString
方法来确定将为列表中的项目显示什么文本(reference):
@Entity
public class Language {
...
@NonNull
@Override
public String toString() {
// A value you want to be displayed in the spinner item.
return language;
}
}
以及您的活动中:
List<Language> languages = AppDatabase.getInstance(this).languageDao().getAll();
Spinner spinner = findViewById(R.id.spinner);
// Pass your list as the third parameter. No need to convert it to List<String>
ArrayAdapter<Language> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, languages);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);