如何将 Android 房间加载延迟到 activity 和提示完成之后?

How do I delay Android Room loading until after activity and prompts complete?

问题: 我收到 null 数据库名称错误。我的 MainActiity.class 中的 Android Room 数据库调用继续执行,尽管有提示让用户选择数据库名称。

我正在尝试做的事情:我还在学习Android,但我正在尝试在一个单独的应用程序中锻炼,使用一个主 Room 数据库来管理应用程序使用的多个 Room 数据库的使用(这是一个沙盒类型的应用程序,可以发挥这个想法)。这个数据库管理功能运行良好,但事情是硬编码的。因此,我希望用户能够通过使用 sharedPreferences 和自定义 alert 提示来选择 create在安装第一个房间数据库名称 之后添加其他的。稍后添加它们的选项不是问题,因为将加载某些内容。但是,在初始应用程序启动时,我希望用户可以选择创建和命名第一个数据库而不是创建默认数据库——这并不是什么大不了的事,但为什么有一个潜在的默认数据库用户从不使用。我什至可以开发一种重命名方法,我会这样做,但允许用户这样做似乎很有意义。

我尝试了什么:我尝试创建一些方法来封装和分离出提示中的数据库调用,但代码仍然吹到数据库代码.我对延迟 Room 进行了一些搜索,但找不到任何具体的内容。我对他人的智慧持开放态度。

再次

Code,这只是一个 activity 因为我正在研究这个想法...同时也在学习。

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "DB_INFO";
    SharedPreferences sharedPreferences;
    SharedPreferences.Editor settings;
    String databaseName;
    String prevDB;

    Button button;

    MasterDatabase masterDB;
    List<MasterDatabaseList> mdbList;
    ArrayList<BaseDatabase> bdbList = new ArrayList<>();

    // Current Database
    int currentBaseDBIndex = -1;
    BaseDatabase currentDB = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.button);
        sharedPreferences = getSharedPreferences("AppSettings", MODE_PRIVATE);
        settings = sharedPreferences.edit();
        setupOnClickActions();
        startChecks();
        Toast.makeText(this, "database: " + databaseName + "\r\n" + "prevDB: " + prevDB, Toast.LENGTH_LONG).show();
    }

    private void startChecks(){
        if(isFirstTime()) {
            databaseName = PopupDialog.AlertInputBox(this, "Enter Research Project Name",
                    "Without spaces or special characters, enter a name for your research project.");
            settings.putString("database", databaseName);
            settings.commit();
            settings.apply();
            startDBs();
        }else{
            databaseName = PopupDialog.AlertInputBox(this, "Enter Research Project Name",
                    "Without spaces or special characters, enter a new or existing name for your research project.");
            settings.putString("prevDB", sharedPreferences.getString("database", ""));
            settings.putString("database", databaseName);
            settings.commit();
            settings.apply();
            prevDB = sharedPreferences.getString("prevDB", "");
            startDBs();
        }
    }

    private void startDBs(){
        masterDB = MasterDatabase.getInstance(this);
        mdbList = masterDB.getMasterDao().getAllDatabases();

        // Add a DB if none exists
        if(mdbList.size()<1){
            addBaseDB("sample.db");
        }
        setCurrentIndexDBandDao(databaseName); /* Add some data to db1 IF it exists (it should) --------------------- */

        if (currentBaseDBIndex > -1 && currentDB.getBaseDao().count() < 1) {
            currentDB.getBaseDao().insert(new BaseTable("Added " + databaseName + " ... etc."));

        }

        /* Extract and Log Data for ALL the BaseDatabase databases i.e. db1 and db2 */
        for(MasterDatabaseList masterdb: masterDB.getMasterDao().getAllDatabases()) {
            Log.d(TAG,"Database is " + masterdb.getDatabaseName());
            setCurrentIndexDBandDao(masterdb.getDatabaseName());
            if (currentBaseDBIndex > -1) {
                for(BaseTable bt: currentDB.getBaseDao().getAllBaseTables()) {
                    Log.d(TAG,"Extracted Base Table  row where MyData is" + bt.getMydata());
                }
            }
        }
    }


    // METHODS =========================================================================================================

    // Attempt to clear and reset SharedPreferences to a user first execution
    private void setupOnClickActions(){
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                settings.putBoolean("firstTime", false);
                settings.clear();
                settings.commit();
                settings.apply();
            }
        });
    }

    /* Add a new Database
         Note that it assumes that it will now be the current
         so the current values are set */
    private void addBaseDB(String baseDBName) {
        masterDB.getMasterDao().insert(new MasterDatabaseList(baseDBName));
    }

    /* Build/ReBuild the 3 Lists according to the master database*/
    private void buildBaseLists() {
        bdbList.clear();
        mdbList = masterDB.getMasterDao().getAllDatabases();
        // Loop through the databases defined in the master database adding the database and dao to the respective lists
        for (MasterDatabaseList masterDB: masterDB.getMasterDao().getAllDatabases()) {
            BaseDatabase baseDB = BaseDatabase.getInstance(this, masterDB.getDatabaseName());
            bdbList.add(baseDB);
        }
    }

    /* Set the currentDB according to the database name*/
    private void setCurrentIndexDBandDao(String baseDBName) {
        currentBaseDBIndex = getListIndexByBaseDBName(baseDBName);
        if(currentBaseDBIndex == -1) {
            addBaseDB(baseDBName);
            buildBaseLists();
            currentBaseDBIndex = getListIndexByBaseDBName(baseDBName);
        }
        if (currentBaseDBIndex > -1) {
            buildBaseLists();
        }
        currentDB = bdbList.get(currentBaseDBIndex);
    }

    /* Get the index according to the database name passed*/
    private int getListIndexByBaseDBName(String baseDBName) {
        if(mdbList==null)
            mdbList = masterDB.getMasterDao().getAllDatabases();
        int rv = -1; // default to not found
        for(int i=0; i < mdbList.size();i++) {
            if (mdbList.get(i).getDatabaseName().equals(baseDBName)) {
                rv = i;
                break;
            }
        }
        return rv;
    }

    /* Output all rows from the BaseTable for data extracted by the BaseDaos getAllBaseTables */
    private void logBaseData(List<BaseTable> baseTableList) {
        Log.d(TAG,"Current Database Index is " + currentBaseDBIndex + " DB name is " + mdbList.get(currentBaseDBIndex).getDatabaseName());
        for(BaseTable bt: baseTableList) {
            Log.d(TAG,"\tMyData value is " + bt.getMydata());
        }
    }

    private boolean isFirstTime(){
        if (sharedPreferences.getBoolean("firstTime", true)) {
            settings.putBoolean("firstTime", false);
            settings.commit();
            settings.apply();
            return true;
        } else {
            return false;
        }
    }

}

BaseDatabase - databaseName是因为变量为空而出错的地方

@Database(
        entities = {BaseTable.class},
        version = 1
)
public abstract class BaseDatabase extends RoomDatabase {
    public abstract BaseDao getBaseDao();

    private static final int NUMBER_OF_THREADS = 4;
    public static final ExecutorService databaseWriteExecutor =
            Executors.newFixedThreadPool(NUMBER_OF_THREADS);

    public static BaseDatabase getInstance(Context context, String databaseName) {
        BaseDatabase instance = null;
        if (databaseName != null) {
            return Room.databaseBuilder(context, BaseDatabase.class, databaseName)
                    .allowMainThreadQueries()
                    .build();
        }
        return instance;
    }
}

这是一个包含 2 个活动的示例。第一个MainActivity那个

  • 显示可用数据库的列表(none 首先)
    • 点击一个数据库可以选择它(它不会被访问或创建(如果是新的))
  • 允许通过在 EditText 中输入数据库名称将数据库添加到可用数据库(不会创建或访问)。
  • 允许第二个 activity 传递数据库名称,然后 activity 可以打开数据库(如果不存在则创建它)。
    • 请注意,数据库未被访问。

所以首先是 MasterDatabaseList class(实体):-

@Entity(tableName = MasterDatabaseList.TABLE_NAME,
        indices = { @Index(value = MasterDatabaseList.COL_DATABASE_NAME, unique = true)
        }
)
class MasterDatabaseList {
    public static final String TABLE_NAME = "masterdatabaselist";
    public static final String COl_ID = "id";
    public static final String COL_DATABASE_NAME = "databasename";
    public static final String[] ALL_COLUMNS = new String[]{
            COl_ID, COL_DATABASE_NAME
    };
    @PrimaryKey
    @ColumnInfo(name = COl_ID)
    Long id;
    @ColumnInfo(name = COL_DATABASE_NAME)
    String databaseName;

    public MasterDatabaseList() {}
    @Ignore
    public MasterDatabaseList(String databaseName) {
        this.databaseName = databaseName;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getDatabaseName() {
        return databaseName;
    }
    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }
}
  • 类似于(但注意一些添加的常量)

MasterDatabaseDao

@Dao
abstract class MasterDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    abstract long insert(MasterDatabaseList masterDatabaseList);
    @Query("SELECT * FROM masterdatabaselist")
    abstract List<MasterDatabaseList> getAllDatabases();

    Cursor getAllDatabasesAsCursor() {
        MatrixCursor matrixCursor = new MatrixCursor(
                new String[]{
                        BaseColumns._ID, /* Cursor Adapter must use _id column for id) */
                        MasterDatabaseList.COL_DATABASE_NAME
                },
                0
        );
        for(MasterDatabaseList m: getAllDatabases()) {
            matrixCursor.addRow(new Object[]{m.id,m.databaseName});
        }
        return matrixCursor;
    }
}
  • 注意获取可用数据库列表作为游标的新方法(对于 ListView)

  • MasterDatabase

    @数据库( 实体 = {MasterDatabaseList.class}, 版本 = 1 ) 摘要 class MasterDatabase 扩展 RoomDatabase { 抽象 MasterDao getMasterDao();

      static volatile MasterDatabase instance = null;
      public static MasterDatabase getInstance(Context context) {
          if (instance == null) {
              instance = Room.databaseBuilder(context,MasterDatabase.class,"master.db")
                      .allowMainThreadQueries()
                      .build();
          }
          return instance;
      }
    

    }

  • 相同

第二个ActivityUseSelectedDatabase

public class UseSelectedDatabase extends AppCompatActivity {
    public static final String INTENT_EXTRA_DATABASEID = "database_id";
    public static final String INTENT_EXTRA_DATABASENAME = "database_name";

    long mDatabaseId;
    String mDatabaseName;
    TextView mDatabaseBeingUsed;
    Button mDoneButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_use_selected_database);
        mDatabaseBeingUsed = this.findViewById(R.id.database_name);
        mDoneButton = this.findViewById(R.id.done);


        mDatabaseId = this.getIntent().getLongExtra(INTENT_EXTRA_DATABASEID,-1);
        mDatabaseName = this.getIntent().getStringExtra(INTENT_EXTRA_DATABASENAME);
        mDatabaseBeingUsed.setText(mDatabaseName);
        setDoneButton();

        /*
            can now get an instance of the database
         */

    }
    
    private void setDoneButton() {
        mDoneButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }
}
  • 这不访问数据库,而只是接收主数据库中的数据库名称和ID。即只是表明您可以传递访问数据库所需的所有信息。

第二个活动布局activity_use_selected_database.xml:-

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".UseSelectedDatabase">

    <TextView
        android:id="@+id/database_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="No Database Set?"
        >
    </TextView>

    <Button
        android:id="@+id/done"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="DONE">
    </Button>

</LinearLayout>

初始Activity主要Activity:-

public class MainActivity extends AppCompatActivity {

    MasterDatabase mMasterDB;
    MasterDao mMasterDBDao;
    EditText mDBToAdd;
    Button mAddDB,mUseSelectedDatabase;
    ListView mDatabaseList;
    SimpleCursorAdapter mSCA;
    Cursor mCsr;
    long mSelectedDatabaseId = 0;
    String mSelectedDatabaseName = "";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDBToAdd = this.findViewById(R.id.database_name);
        mAddDB = this.findViewById(R.id.addDatabase);
        mUseSelectedDatabase = this.findViewById(R.id.useSelectedDatabase);
        mDatabaseList = this.findViewById(R.id.database_list);

        mMasterDB = MasterDatabase.getInstance(this);
        mMasterDBDao = mMasterDB.getMasterDao();


        setUpAddDBButton();
        setUpUseSelectedDatabaseButton();
        setOrRefreshDatabaseList();
    }

    private void setUpAddDBButton() {
        mAddDB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mDBToAdd.getText().toString().length() > 0) {
                    if (mMasterDBDao.insert(new MasterDatabaseList(mDBToAdd.getText().toString())) > 0) {
                        mDBToAdd.setText("");
                        setOrRefreshDatabaseList();
                    }
                }
            }
        });
    }
    private void setUpUseSelectedDatabaseButton() {
        mUseSelectedDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mSelectedDatabaseId > 0) {
                    Intent intent = new Intent(view.getContext(),UseSelectedDatabase.class);
                    intent.putExtra(UseSelectedDatabase.INTENT_EXTRA_DATABASEID, mSelectedDatabaseId);
                    intent.putExtra(UseSelectedDatabase.INTENT_EXTRA_DATABASENAME,mSelectedDatabaseName);
                    startActivity(intent);
                }
            }
        });
    }

    private void setOrRefreshDatabaseList() {
        mCsr = mMasterDBDao.getAllDatabasesAsCursor();
        if (mSCA == null) {
            mSCA = new SimpleCursorAdapter(
                    this.getApplicationContext(),
                    android.R.layout.simple_list_item_1,
                    mCsr,
                    new String[]{MasterDatabaseList.COL_DATABASE_NAME},
                    new int[]{android.R.id.text1},
                    0
            );
            mDatabaseList.setAdapter(mSCA);
            mDatabaseList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                /* Handle Clicking on an Item (i.e. prepare UseSelected Button) */
                @SuppressLint("Range")
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                    mSelectedDatabaseId = l;
                    if (l > 0) {
                        mSelectedDatabaseName = mCsr.getString(mCsr.getColumnIndex(MasterDatabaseList.COL_DATABASE_NAME));
                        mUseSelectedDatabase.setText(mSelectedDatabaseName);
                        mUseSelectedDatabase.setClickable(true);
                    } else {
                        mUseSelectedDatabase.setText("NO DATEBASE SELECTED");
                        mUseSelectedDatabase.setClickable(false);
                    }
                }
            });
        } else {
            mSCA.swapCursor(mCsr);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        setOrRefreshDatabaseList();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mCsr.close();
    }
}

初始Activity的布局activity_main.xml:-

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
    <EditText
        android:id="@+id/database_name"
        android:layout_width="500dp"
        android:layout_height="wrap_content"
        android:text="">
    </EditText>
    <Button
        android:id="@+id/addDatabase"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add Database"
        >
    </Button>
    <ListView
        android:id="@+id/database_list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </ListView>
    <Button
        android:id="@+id/useSelectedDatabase"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="NO SELECTED DATABASE"
        android:clickable="false"
        >
    </Button>

</LinearLayout>

演示

当第一个 运行 MainActivity 显示时:-

即没有可用的数据库(点击按钮没有任何反应)。

数据库 Test001 输入编辑文本,然后单击添加数据库:-

  • 在此阶段尚未创建 Test001 数据库。但是,MasterDatabase 已创建并添加了 Test001 行(即,如果数据库不存在,有时可以打开和创建该数据库):-

Test001 被点击:-

  • Use Selected 按钮已更改为 Test001(也许应该是 Use Test001)。
  • 仍然完全没有访问 Test001 数据库,因为没有必要。

数据库 Test002 输入编辑文本(添加后清除)并单击添加数据库:-

  • 请注意,如果将现有数据库输入编辑文本,则不会添加该数据库,也不会清除文本框。

单击 Test002,按钮更改为 Test002 并单击按钮,开始第二个 activity :-

  • 数据库未打开或访问(即进一步演示等待和做事)

单击“完成”按钮返回第一个 activity。数据库仍然没有 opened/accessed 但其他代码(Base????? 等)可能是(可能在 UseSelectedDatabase activity)。

Extra 作为 BaseTable 的概念证明??? class添加了上一个问题中的内容,以及一些新用户??? classes 与 BaseDatabase 为:-

@Database(
        entities = {BaseTable.class,User.class},
        version = 1
)
abstract class BaseDatabase extends RoomDatabase {
    abstract BaseDao getBaseDao();
    abstract UserDao getUserDao();

    public static BaseDatabase getInstance(Context context, String databaseName) {

        BaseDatabase db = Room.databaseBuilder(context, BaseDatabase.class, databaseName)
                .allowMainThreadQueries()
                .build();
        db.getOpenHelper().getWritableDatabase();
        return db;
    }
}

将以下内容添加到 UseSelectedDatabase activity:-

    ....

    /*
        can now get an instance of the database
     */

    db = BaseDatabase.getInstance(this,mDatabaseName);
    baseDao = db.getBaseDao();
    userDao = db.getUserDao();

    baseDao.insert(new BaseTable("X"));
    userDao.insert(new User("Snowman","Fred","Wlibur","Bloggs","password",0));

    List<BaseTable> baseTableList = baseDao.getAllBaseTables();
    List<User> userList = userDao.getAllUsers();

重新启动应用程序选择 Test001,然后选择 Test002 结果数据库显示为:-

即Test001,尽管它已关闭,但显然与 Test002 一样已创建。