You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题分析与解决方案

核心问题点

  1. DBHelper仅实现了预订信息插入方法,缺少查询用户历史预订记录的方法
  2. 预订页面无展示历史记录的UI控件,也未调用查询逻辑加载数据
  3. 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>

验证效果

  1. 用户登录后,页面自动加载并展示历史预订记录
  2. 点击预订按钮后,新记录存入数据库并实时刷新展示
  3. 再次登录同一账号,可查看所有历史预订记录

内容的提问来源于stack exchange,提问作者Harsheen Kaur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 09:50:55