有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

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

我尝试的内容:我尝试创建一些方法来封装DB调用并将其从提示中分离出来,但代码仍然贯穿到DB代码中。我搜索了一下延迟Room,但找不到任何特定的内容。我乐于接受别人的智慧

代码再说一遍,这只是一项活动,因为我在玩弄这个想法。。。同时学习

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;
    }
}

共 (1) 个答案

  1. # 1 楼答案

    下面是一个包含2个活动的示例。第一个主要活动是

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

    因此,首先是MasterDatabaseList类(实体):-

    @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)

    • 主数据库

      @数据库( 实体={MasterDatabaseList.class}, 版本=1 ) 抽象类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;
        }
      

      }

    • previous answer起保持不变

    第二个活动使用选定数据库

    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。i、 e.只是表明您可以传递访问数据库所需的所有信息

    第二个活动布局活动使用选定的数据库。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>
    

    初始活动主要活动

    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();
        }
    }
    

    初始活动的布局活动\u主。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时显示:-

    enter image description here

    即没有可用的数据库(单击按钮不起任何作用)

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

    enter image description here

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

    enter image description here

    单击Test001:-

    enter image description here

    • Use Selected按钮已更改为Test001(可能应该是Use Test001)
    • 但是Test001数据库还没有被访问,因为没有必要

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

    enter image description here

    • 注意:如果在编辑文本中输入了现有数据库,则不会添加该数据库,也不会清除文本框

    单击Test002,按钮变为Test002,然后单击按钮,开始第二个活动:-

    enter image description here

    • 数据库未打开或访问(即进一步演示等待和执行操作)

    单击“完成”按钮返回第一个活动。尽管如此,数据库尚未打开/访问,但使用其他代码(基本类等)可能(可能在UseSelectedDatabase活动中)

    额外的作为基本表的概念证明???添加了上一个问题中的类,以及一些新用户???具有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活动中:

        ....
    
        /*
            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,结果显示数据库如下:-

    enter image description here

    也就是说,Test001虽然已经关闭,但显然已经像Test002一样创建了