简体   繁体   English

如何在不阻塞 UI 线程的情况下用 Room 中的数据填充微调器

[英]How to fill spinner with data from Room without blocking UI thread

I have pre-populated an Android Room database with the names of sports teams in a table.我已经在一个表中预先填充了一个带有运动队名称的 Android Room 数据库。 I want to populate a spinner on the activity below with those names.我想用这些名称在下面的活动中填充一个微调器。 I need to run several similar tasks as well and cannot use the main thread for this.我还需要运行几个类似的任务,并且不能为此使用主线程。 How can I do this using asynctask or executor?如何使用 asynctask 或 executor 执行此操作?

This data is not live and will not change, but will be called to populate several different widgets.这些数据不是实时的,不会改变,但会被调用来填充几个不同的小部件。

`//Activity`

    public class RegisterPlayers extends AppCompatActivity {
    public static PlayerRegistryDatabase playerRegistryDatabase;
`@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register_players);
createTeamsSpinner();
}
    private Spinner createTeamsSpinner() {
        Spinner spinner = findViewById(R.id.rank1);
        List<Teams> teamName = PlayerRegistryDatabase.getInstance(this).playerRegistryDao().getAllTeams();
        List<String> teamNameStrings = new LinkedList<>();
        for (int i = 0; i < teamName.size(); i++) {
            teamNameStrings.add(teamName.get(i).getTeamName());
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_dropdown_item_1line,
                teamNameStrings);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        return spinner;
    }
}
`

`//Teams Class`    


    @Entity
`public class Teams {private String conferenceName;`

    @PrimaryKey@NonNull
    private String teamName;

    public Teams(String conferenceName, String teamName) {
        this.conferenceName = conferenceName;
        this.teamName = teamName;
    }

    public String getConferenceName() {
        return conferenceName;
    }

    public void setConferenceName(String conferenceName) {
        this.conferenceName = conferenceName;
    }

    public String getTeamName() {
        return teamName;
    }

    public void setTeamName(String teamName) {
        this.teamName = teamName;
    }

    public static Teams[] populateData() {
        return new Teams[] {
                new Teams("W", "Panthers"),
                new Teams("W", "Eagles"),
                new Teams("E", "Bulldogs"),
                new Teams("E", "Cheetahs"),
        };
    }`

`//Dao`

`@Dao
public interface PlayerRegistryDao {`

    @Insert
    void insertAll(Teams... teamName);

    @Query("SELECT * FROM Teams")
    List<Teams> getAllTeams();
`}`

`//Database`

    @Database(entities = {PlayerRegistry.class, Teams.class}, version = 1, exportSchema = false)
`public abstract class PlayerRegistryDatabase extends RoomDatabase {`

    private static PlayerRegistryDatabase buildDatabase(final Context context) {
        return Room.databaseBuilder(context,
                PlayerRegistryDatabase.class,
                "teams")
                .addCallback(new Callback() {
                    @Override
                    //@NonNull error, tried android support option
                    public void onCreate(@NonNull SupportSQLiteDatabase db) {
                        super.onCreate(db);
                        Executors.newSingleThreadScheduledExecutor().execute(new Runnable() {
                            @Override
                            public void run() {
                                getInstance(context).playerRegistryDao().insertAll(Teams.populateData());
                            }
                        });
                    }
                })
                .build();
    }

I expect the activity to load with the spinner populated with the team names from the Teams table, but the app crashes before displaying the activity with an error related to queries not being permitted to run on the main thread.我希望活动加载时使用填充有团队表中的团队名称的微调器,但应用程序在显示活动之前崩溃,并出现与不允许在主线程上运行的查询相关的错误。

According to the android documentation you have to use a repository to populate your ui.根据 android 文档,您必须使用存储库来填充您的 ui。

Here is my code with a sample spinner populate from a simple room entity.这是我的代码,其中包含从简单房间实体填充的示例微调器。

My entity.我的实体。

@Entity(tableName = Category.TABLE_NAME)
public class Category implements Parcelable {

    //constructor setters and getters
    protected Category(Parcel in) {
        id = in.readLong();
        name = in.readString();
    }

    public static final Creator<Category> CREATOR = new Creator<Category>() {
        @Override
        public Category createFromParcel(Parcel in) {
            return new Category(in);
        }

        @Override
        public Category[] newArray(int size) {
            return new Category[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(id);
        dest.writeString(name);
    }

    /** The name of the Cheese table. */
    public static final String TABLE_NAME = "category";

    /** The name of the ID column. */
    public static final String COLUMN_ID = BaseColumns._ID;

    /** The name of the name column. */
    public static final String COLUMN_NAME = "name";

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(index = true, name = COLUMN_ID)
    private long id;

    @ColumnInfo(name = COLUMN_NAME)
    private String name;

    public Category(){
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

My dao, takes care to return LiveData.我的 dao,负责返回 LiveData。

@Dao
public interface CategoryDao {

    @Query("SELECT COUNT(*) FROM " + Category.TABLE_NAME)
    LiveData<Integer> count();

    @Insert
    long insert(Category category);

    @Query("SELECT * FROM " +Category.TABLE_NAME)
    LiveData<List<Category>> selectAll();



    @Query("DELETE FROM " + Category.TABLE_NAME + " WHERE " + Category.COLUMN_ID + " = :id")
    int deleteById(long id);

    @Update
    int update(Category item);

    @Delete
    public void delete(Category item);


}

The repository, according to android best practices.存储库,根据 android 最佳实践。

public class CategoryRepository {

    private CategoryDao mDao;
    private LiveData<List<Category>> allItems;

    public CategoryRepository(Application application) {
        AppDatabase db = AppDatabase.getInstance(application);
        mDao = db.categoryDao();
        allItems = mDao.selectAll();
    }

    public LiveData<List<Category>> getAll() {
        return allItems;
    }

    public void insert(Category item) {
        new InsertAsyncTask(mDao).execute(item);
    }

    public void update(Category item) {
        new UpdateAsyncTask(mDao).execute(item);
    }

    public void delete(Category item) {
        new DeleteAsyncTask(mDao).execute(item);
    }


    private static class InsertAsyncTask extends AsyncTask<Category, Void, Void> {
        private CategoryDao asyncTaskDao;

        InsertAsyncTask(CategoryDao dao) {
            asyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(final Category... params) {
            asyncTaskDao.insert(params[0]);
            return null;
        }
    }

    private static class UpdateAsyncTask extends AsyncTask<Category, Void, Void> {
        private CategoryDao asyncTaskDao;

        UpdateAsyncTask(CategoryDao dao) {
            asyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(final Category... params) {
            asyncTaskDao.update(params[0]);
            return null;
        }
    }

    private static class DeleteAsyncTask extends AsyncTask<Category, Void, Void> {

        private CategoryDao asyncTaskDao;

        DeleteAsyncTask(CategoryDao dao) {
            asyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(final Category... params) {
            asyncTaskDao.delete(params[0]);
            return null;
        }
    }

}

Populate code from repository.从存储库填充代码。 Here we are, this is the last step and you got it !我们到了,这是最后一步,你明白了!

private void loadSpinnerData() {
        // database handler
        CategoryRepository categoryRepository = new CategoryRepository(getActivity().getApplication());

        // Creating adapter for spinner
        final ArrayAdapter<Category> dataAdapter = new ArrayAdapter<Category>(getActivity(),
                android.R.layout.simple_spinner_item, new ArrayList<Category>(0));

        // Drop down layout style - list view with radio button
        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        // attaching data adapter to spinner
        editCategorySpinner.setAdapter(dataAdapter);

        categoryRepository.getAll().observe(this, new Observer<List<Category>>() {

            @Override
            public void onChanged(@Nullable final List<Category> items) {
                // tri de la liste
                Collections.sort(items, new Comparator<Category>() {
                    public int compare(Category obj1, Category obj2) {
                        // ## Ascending order
                        return obj1.getName().compareToIgnoreCase(obj2.getName());
                    }
                });
                // ajout dans la list et refresh
                dataAdapter.addAll(items);
                dataAdapter.notifyDataSetChanged();
            }
        });

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM