Android开发:Spinner选中后用动态RecyclerView展示Assets中对应数据库表
嗨,作为Android开发新手,你的需求其实挺典型的,我来一步步帮你拆解实现,确保每一步都清晰易懂:
1. 先把Assets里的数据库复制到应用可读写目录
因为assets文件夹里的文件是只读的,没法直接操作,所以首先得把数据库复制到应用的私有存储目录(比如/data/data/你的包名/databases/)。可以写一个数据库帮助类来处理这个逻辑:
public class DBHelper extends SQLiteOpenHelper { private static String DB_NAME = "你的数据库名.db"; private static String DB_PATH; private SQLiteDatabase myDatabase; private final Context myContext; public DBHelper(Context context) { super(context, DB_NAME, null, 1); this.myContext = context; DB_PATH = context.getFilesDir().getParent() + "/databases/"; } // 复制assets里的数据库到本地 public void copyDatabase() throws IOException { InputStream myInput = myContext.getAssets().open(DB_NAME); String outFileName = DB_PATH + DB_NAME; OutputStream myOutput = new FileOutputStream(outFileName); byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer)) > 0) { myOutput.write(buffer, 0, length); } myOutput.flush(); myOutput.close(); myInput.close(); } // 打开数据库 public void openDatabase() throws SQLException { String myPath = DB_PATH + DB_NAME; myDatabase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); } @Override public synchronized void close() { if (myDatabase != null) myDatabase.close(); super.close(); } @Override public void onCreate(SQLiteDatabase db) {} @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} // 查询指定表的明星数据(姓名+照片BLOB) public Cursor getStarData(String tableName) { return myDatabase.query(tableName, new String[]{"姓名列名", "BLOB列名"}, null, null, null, null, null); } }
注意把代码里的你的数据库名.db、姓名列名、BLOB列名替换成你实际的名称。
2. 主Activity里的Spinner配置与跳转逻辑
在你的主Activity里,先初始化Spinner,设置选项列表,然后监听选中事件,跳转到展示RecyclerView的Activity:
public class MainActivity extends AppCompatActivity { private Spinner tableSpinner; private String[] tableOptions = {"Hollywood Stars", "其他选项1", "其他选项2"}; // 注意这里要和Spinner选项对应实际的表名 private String[] tableNames = {"hollywoodstars", "table1", "table2"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tableSpinner = findViewById(R.id.spinner); ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, tableOptions); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); tableSpinner.setAdapter(adapter); tableSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { // 获取选中的表名 String selectedTableName = tableNames[position]; // 跳转到展示数据的Activity Intent intent = new Intent(MainActivity.this, StarListActivity.class); intent.putExtra("TABLE_NAME", selectedTableName); startActivity(intent); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); // 首次复制数据库(可以加个判断,避免每次都复制) try { DBHelper dbHelper = new DBHelper(this); File dbFile = new File(DBHelper.DB_PATH + DBHelper.DB_NAME); if (!dbFile.exists()) { dbHelper.copyDatabase(); } } catch (IOException e) { e.printStackTrace(); } } }
3. 新建展示RecyclerView的Activity与Adapter
首先创建StarListActivity的布局文件activity_star_list.xml,里面放一个RecyclerView:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/star_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
然后创建RecyclerView的Item布局item_star.xml,用来展示姓名和照片:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:orientation="horizontal" android:gravity="center_vertical"> <ImageView android:id="@+id/star_image" android:layout_width="80dp" android:layout_height="80dp" android:scaleType="centerCrop"/> <TextView android:id="@+id/star_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:textSize="18sp"/> </LinearLayout>
接下来编写RecyclerView的Adapter,重点处理BLOB转Bitmap的逻辑:
public class StarAdapter extends RecyclerView.Adapter<StarAdapter.StarViewHolder> { private Cursor cursor; private Context context; public StarAdapter(Context context, Cursor cursor) { this.context = context; this.cursor = cursor; } @NonNull @Override public StarViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item_star, parent, false); return new StarViewHolder(view); } @Override public void onBindViewHolder(@NonNull StarViewHolder holder, int position) { if (!cursor.moveToPosition(position)) { return; } // 获取姓名 String starName = cursor.getString(cursor.getColumnIndexOrThrow("姓名列名")); // 获取BLOB数据并转成Bitmap byte[] imageBytes = cursor.getBlob(cursor.getColumnIndexOrThrow("BLOB列名")); Bitmap starBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); holder.starName.setText(starName); holder.starImage.setImageBitmap(starBitmap); } @Override public int getItemCount() { return cursor.getCount(); } // 更新Cursor(如果数据有变化的话) public void swapCursor(Cursor newCursor) { if (cursor != null) { cursor.close(); } cursor = newCursor; if (newCursor != null) { notifyDataSetChanged(); } } public static class StarViewHolder extends RecyclerView.ViewHolder { ImageView starImage; TextView starName; public StarViewHolder(@NonNull View itemView) { super(itemView); starImage = itemView.findViewById(R.id.star_image); starName = itemView.findViewById(R.id.star_name); } } }
最后完成StarListActivity的代码,获取传递的表名,查询数据库并给RecyclerView设置Adapter:
public class StarListActivity extends AppCompatActivity { private RecyclerView starRecyclerView; private StarAdapter starAdapter; private DBHelper dbHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_star_list); starRecyclerView = findViewById(R.id.star_recycler_view); starRecyclerView.setLayoutManager(new LinearLayoutManager(this)); // 获取传递过来的表名 String tableName = getIntent().getStringExtra("TABLE_NAME"); // 初始化数据库并查询数据 dbHelper = new DBHelper(this); try { dbHelper.openDatabase(); Cursor cursor = dbHelper.getStarData(tableName); starAdapter = new StarAdapter(this, cursor); starRecyclerView.setAdapter(starAdapter); } catch (SQLException e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); // 关闭数据库和Cursor if (dbHelper != null) { dbHelper.close(); } if (starAdapter != null) { starAdapter.swapCursor(null); } } }
一些注意事项
- 记得把所有占位符(比如数据库名、列名)替换成你实际的内容
- 如果BLOB数据很大,考虑用异步任务或者协程来处理,避免主线程阻塞
- 可以给ImageView加个占位图,防止Bitmap加载慢的时候显示空白
- 首次复制数据库的逻辑可以优化,比如用SharedPreference记录是否已经复制过,避免每次启动都判断文件
内容的提问来源于stack exchange,提问作者Nitin Pareek
相关产品推荐
相关产品推荐

