Android SQLite电影票APP:预订信息存储及登录后读取问题咨询
Android电影票预订APP:预订信息存储与历史记录读取问题解决方案
问题描述
我正在开发一款Android电影票预订APP,登录功能采用SQLite数据库存储用户名与密码,登录成功后进入预订页面,用户可通过Spinner控件选择电影、影院和场次。需要实现以下两个功能:
- 将Spinner选中的电影、影院、场次信息关联当前登录用户存入数据库
- 用户再次登录时,读取并显示其之前的预订记录
目前登录与注册功能正常,但上述功能无法实现:尝试用类似之前保存成绩的updateBooking方法存储预订信息未成功,再次登录时无法读取并展示历史预订记录,预期选中的预订信息能成功保存并在下次登录时显示。现有实现代码如下:
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/etUsername" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Username" /> <EditText android:id="@+id/etPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Password" android:inputType="textPassword" /> <Button android:id="@+id/btnLogin" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Login" /> <Button android:id="@+id/btnRegister" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Register" /> </LinearLayout>
LoginActivity.java
package com.example.myapplication; import android.content.Intent; import android.os.Bundle; import android.widget.*; import androidx.appcompat.app.AppCompatActivity; public class LoginActivity extends AppCompatActivity { EditText etUsername, etPassword; Button btnLogin, btnRegister; DBHelper dbHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etUsername = findViewById(R.id.etUsername); etPassword = findViewById(R.id.etPassword); btnLogin = findViewById(R.id.btnLogin); btnRegister = findViewById(R.id.btnRegister); dbHelper = new DBHelper(this); btnRegister.setOnClickListener(v -> { String user = etUsername.getText().toString(); String pass = etPassword.getText().toString(); if (dbHelper.registerUser(user, pass)) { Toast.makeText(this, "User Registered!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "User Exists!", Toast.LENGTH_SHORT).show(); } }); btnLogin.setOnClickListener(v -> { String user = etUsername.getText().toString(); String pass = etPassword.getText().toString(); if (dbHelper.loginUser(user, pass)) { Intent i = new Intent(this, MainActivity.class); i.putExtra("username", user); startActivity(i); finish(); } else { Toast.makeText(this, "Invalid login", Toast.LENGTH_SHORT).show(); } }); } }
activity_booking.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/tvWelcome" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" /> <Spinner android:id="@+id/spMovie" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Spinner android:id="@+id/spTime" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btnBook" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Book Ticket" /> </LinearLayout>
MainActivity.java
package com.example.myapplication; import android.os.Bundle; import android.widget.*; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { Spinner spMovie, spTime; Button btnBook; TextView tvWelcome; DBHelper dbHelper; String username; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_booking); spMovie = findViewById(R.id.spMovie); spTime = findViewById(R.id.spTime); btnBook = findViewById(R.id.btnBook); tvWelcome = findViewById(R.id.tvWelcome); dbHelper = new DBHelper(this); username = getIntent().getStringExtra("username"); tvWelcome.setText("Welcome, " + username); String[] movies = {"Inception", "Interstellar", "Oppenheimer"}; String[] times = {"10:00 AM", "1:00 PM", "4:00 PM", "7:00 PM"}; spMovie.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, movies)); spTime.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, times)); btnBook.setOnClickListener(v -> { String movie = spMovie.getSelectedItem().toString(); String time = spTime.getSelectedItem().toString(); if (dbHelper.saveBooking(username, movie, time)) { Toast.makeText(this, "Ticket Booked!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Booking Failed!", Toast.LENGTH_SHORT).show(); } }); } }
DBHelper.java
package com.example.myapplication; import android.content.*; import android.database.Cursor; import android.database.sqlite.*; public class DBHelper extends SQLiteOpenHelper { public static final String DB_NAME = "MovieApp.db"; public DBHelper(Context context) { super(context, DB_NAME, null, 1); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE users(username TEXT PRIMARY KEY, password TEXT)"); db.execSQL("CREATE TABLE bookings(username TEXT, movie TEXT, time TEXT)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldV, int newV) { db.execSQL("DROP TABLE IF EXISTS users"); db.execSQL("DROP TABLE IF EXISTS bookings"); onCreate(db); } public boolean registerUser(String username, String password) { SQLiteDatabase db = getWritableDatabase(); Cursor c = db.rawQuery("SELECT * FROM users WHERE username=?", new String[]{username}); if (c.getCount() > 0) return false; ContentValues cv = new ContentValues(); cv.put("username", username); cv.put("password", password); return db.insert("users", null, cv) != -1; } public boolean loginUser(String username, String password) { SQLiteDatabase db = getReadableDatabase(); Cursor c = db.rawQuery("SELECT * FROM users WHERE username=? AND password=?", new String[]{username, password}); return c.getCount() > 0; } public boolean saveBooking(String username, String movie, String time) { SQLiteDatabase db = getWritableDatabase(); ContentValues cv = new ContentValues(); cv.put("username", username); cv.put("movie", movie); cv.put("time", time); return db.insert("bookings", null, cv) != -1; } }
问题分析与解决方案
核心问题点
DBHelper仅实现了预订信息插入方法,缺少查询用户历史预订记录的方法- 预订页面无展示历史记录的UI控件,也未调用查询逻辑加载数据
bookings表未设置主键,易产生重复数据
分步修改
1. 完善DBHelper,添加查询方法与优化表结构
升级数据库版本,为bookings表添加自增主键,并新增查询用户预订记录的方法:
package com.example.myapplication; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class DBHelper extends SQLiteOpenHelper { public static final String DB_NAME = "MovieApp.db"; private static final int DB_VERSION = 2; public DBHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE users(username TEXT PRIMARY KEY, password TEXT)"); db.execSQL("CREATE TABLE bookings(id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, movie TEXT, time TEXT)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion < 2) { db.execSQL("ALTER TABLE bookings ADD COLUMN id INTEGER PRIMARY KEY AUTOINCREMENT"); } } // 保留原有registerUser、loginUser、saveBooking方法不变 // 添加查询用户预订记录的方法 public List<Map<String, String>> getUserBookings(String username) { List<Map<String, String>> bookings = new ArrayList<>(); SQLiteDatabase db = getReadableDatabase(); Cursor cursor = db.rawQuery("SELECT movie, time FROM bookings WHERE username=? ORDER BY id DESC", new String[]{username}); if (cursor.moveToFirst()) { do { Map<String, String> booking = new HashMap<>(); booking.put("movie", cursor.getString(cursor.getColumnIndexOrThrow("movie"))); booking.put("time", cursor.getString(cursor.getColumnIndexOrThrow("time"))); bookings.add(booking); } while (cursor.moveToNext()); } cursor.close(); return bookings; } }
2. 修改预订页面布局,添加历史记录展示控件
在activity_booking.xml中新增展示历史记录的TextView:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <!-- 保留原有控件 --> <TextView android:id="@+id/tvWelcome" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" /> <Spinner android:id="@+id/spMovie" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Spinner android:id="@+id/spTime" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btnBook" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Book Ticket" /> <!-- 新增历史记录展示区域 --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="你的历史预订记录" android:textSize="16sp" android:layout_marginTop="20dp" android:textStyle="bold"/> <TextView android:id="@+id/tvBookingHistory" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="暂无预订记录"/> </LinearLayout>
3. 修改MainActivity,加载并展示历史记录
添加加载历史记录的方法,并在页面创建、预订成功后调用:
package com.example.myapplication; import android.os.Bundle; import android.widget.*; import androidx.appcompat.app.AppCompatActivity; import java.util.List; import java.util.Map; public class MainActivity extends AppCompatActivity { Spinner spMovie, spTime; Button btnBook; TextView tvWelcome, tvBookingHistory; DBHelper dbHelper; String username; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_booking); spMovie = findViewById(R.id.spMovie); spTime = findViewById(R.id.spTime); btnBook = findViewById(R.id.btnBook); tvWelcome = findViewById(R.id.tvWelcome); tvBookingHistory = findViewById(R.id.tvBookingHistory); dbHelper = new DBHelper(this); username = getIntent().getStringExtra("username"); tvWelcome.setText("Welcome, " + username); String[] movies = {"Inception", "Interstellar", "Oppenheimer"}; String[] times = {"10:00 AM", "1:00 PM", "4:00 PM", "7:00 PM"}; spMovie.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, movies)); spTime.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, times)); // 页面创建时加载历史记录 loadBookingHistory(); btnBook.setOnClickListener(v -> { String movie = spMovie.getSelectedItem().toString(); String time = spTime.getSelectedItem().toString(); if (dbHelper.saveBooking(username, movie, time)) { Toast.makeText(this, "Ticket Booked!", Toast.LENGTH_SHORT).show(); // 预订成功后刷新历史记录 loadBookingHistory(); } else { Toast.makeText(this, "Booking Failed!", Toast.LENGTH_SHORT).show(); } }); } // 加载并展示历史预订记录 private void loadBookingHistory() { List<Map<String, String>> bookings = dbHelper.getUserBookings(username); if (bookings.isEmpty()) { tvBookingHistory.setText("暂无预订记录"); return; } StringBuilder historyText = new StringBuilder(); for (int i = 0; i < bookings.size(); i++) { Map<String, String> booking = bookings.get(i); historyText.append(String.format("%d. 电影:%s,场次:%s\n", i+1, booking.get("movie"), booking.get("time"))); } tvBookingHistory.setText(historyText.toString()); } }
4. 修复AndroidManifest注册问题
确保MainActivity已在Manifest中注册:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapplication"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyApplication"> <activity android:name=".LoginActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".MainActivity" android:exported="false"/> </application> </manifest>
验证效果
- 用户登录后,页面自动加载并展示历史预订记录
- 点击预订按钮后,新记录存入数据库并实时刷新展示
- 再次登录同一账号,可查看所有历史预订记录
内容的提问来源于stack exchange,提问作者Harsheen Kaur
相关产品推荐
相关产品推荐

