获取Room中的预填充数据到微调器适配器

时间:2018-03-07 17:20:53

标签: android spinner android-room

大家好!今天我试图解决下一个问题:我已经为语言列表创建了房间数据库,预先填充了五个准备好的对象,然后我试图将它们转移到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();

我无法用预定义的对象填充当前列表,这导致空的微调器没有可供选择的选项。你能告诉我哪里出错吗?我还想听听有关如何简化适配器创建的意见。

1 个答案:

答案 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);

请参见BaseAdapterSpinnerAdapter参考。

或者您可以使用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);