Python Kivy应用数据库存储问题:APK打包后JsonStorage无法保存
登录/注册页面数据存储问题解决方案
一、修复JsonStorage在Android上的崩溃与存储问题
1. 改用应用专属存储路径
Android系统限制应用只能在专属目录写入文件,直接用相对路径"user_info.json"会触发权限错误。修改为Kivy App提供的user_data_dir路径,这是系统允许应用读写的安全目录:
from kivy.app import App from kivy.storage.jsonstore import JsonStore # ... 其他导入代码 class LoginApp(App): def build(self): # 拼接应用专属路径与存储文件名 self.stored_data = JsonStore(f"{self.user_data_dir}/user_info.json") return login_screen_sign_up(stored_data=self.stored_data) class login_screen_sign_up(FloatLayout): def __init__(self, stored_data, **kwargs): super().__init__(**kwargs) self.stored_data = stored_data # 接收存储实例,避免全局变量风险 # ... 后续控件初始化代码
2. 移除错误代码
- 删除
stored_data.store_load():JsonStore会自动加载文件,手动调用无意义且可能引发异常。 - 删除
Builder.load_file('user_info.json'):Builder用于加载KV语言布局文件,不能加载JSON数据文件,这是导致APK崩溃的直接原因之一。 - 删除
FloatInput类中的your text垃圾代码,修复语法错误:class FloatInput(TextInput): input_filter = 'float'
3. 修复用户名重复判断逻辑
原循环逻辑会覆盖之前的匹配结果,改用JsonStore自带的exists()方法更高效准确:
def click_me(self, instance): username = self.login_info_un.text password = self.login_info_pass.text confirm_pwd = self.login_info_pass_confirm.text if not all([username, password, confirm_pwd]): print('请填写所有字段') return if self.stored_data.exists(username): print('This username is already taken.') elif password != confirm_pwd: print('Passwords do not match.') else: self.stored_data.put(username, password=password) self.stored_data.store_sync() print('注册成功')
4. 避免初始化时的KeyError
原代码直接取stored_data.get('Beckett')['password'],若该用户不存在会抛出异常,修改为安全取值:
# 安全获取用户密码,不存在则显示默认文本 user_data = self.stored_data.get('Beckett', {}) password_text = user_data.get('password', '暂无用户数据') self.login_prompt = Label(text=password_text, size_hint=(0.3, 0.1), pos_hint={'x': 0.1, 'y': 0.6})
二、Buildozer配置调整
在buildozer.spec中添加必要权限和配置,确保Android端正常运行:
# 配置兼容的Android API级别(建议30及以上) android.api = 30 android.ndk = 25b # 添加存储读写权限 android.permissions = WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE # 确保依赖版本兼容 requirements = python3,kivy
三、替代方案:使用SQLite存储
如果需要更可靠的结构化存储,推荐使用Python标准库的sqlite3,Android端支持良好:
import sqlite3 from kivy.app import App class LoginApp(App): def build(self): db_path = f"{self.user_data_dir}/user_db.db" self.conn = sqlite3.connect(db_path) cursor = self.conn.cursor() # 创建用户表(不存在则创建) cursor.execute('CREATE TABLE IF NOT EXISTS users (username TEXT PRIMARY KEY, password TEXT)') self.conn.commit() return login_screen_sign_up(db_conn=self.conn) class login_screen_sign_up(FloatLayout): def __init__(self, db_conn, **kwargs): super().__init__(**kwargs) self.db_conn = db_conn # ... 控件初始化代码 def click_me(self, instance): username = self.login_info_un.text password = self.login_info_pass.text confirm_pwd = self.login_info_pass_confirm.text if not all([username, password, confirm_pwd]): print('请填写所有字段') return if password != confirm_pwd: print('Passwords do not match.') return try: cursor = self.db_conn.cursor() cursor.execute('INSERT INTO users VALUES (?, ?)', (username, password)) self.db_conn.commit() print('注册成功') except sqlite3.IntegrityError: print('This username is already taken.')
内容的提问来源于stack exchange,提问作者Beckett
相关产品推荐
相关产品推荐

