使用KivyMD调用Android文件管理器无法选中文件求助
用Android原生文件管理器替代MDFileManager时无法获取选中文件信息的问题
我希望用Android原生文件管理器替代MDFileManager,目前能成功打开文件管理器,但选中文件后无法正常获取选中的文件信息。已在buildozer.spec中配置相关权限,调试时在Android Studio出现错误,以下是我的KivyMD代码:
from kivy.lang import Builder from kivy.uix.boxlayout import BoxLayout from kivy.properties import ObjectProperty from kivy.app import App KV = ''' BoxLayout: orientation: 'vertical' Button: text: "Open File Manager" on_release: app.open_file_manager() Label: id: file_label text: "Selected File: None" halign: 'center' ScrollView: Label: id: file_content_label text: "" ''' class FileManagerApp(App): file_label = ObjectProperty() file_content_label = ObjectProperty() def build(self): return Builder.load_string(KV) def open_file_manager(self): from jnius import autoclass PythonActivity = autoclass('org.kivy.android.PythonActivity') Intent = autoclass('android.content.Intent') activity = PythonActivity.mActivity intent = Intent() intent.setAction(Intent.ACTION_OPEN_DOCUMENT) intent.setType("*/*") activity.startActivityForResult(intent, 0) def on_activity_result(self, requestCode, resultCode, data): if resultCode == -1: # Activity.RESULT_OK uri = data.getData() selected_file_name = self.get_file_name_from_uri(uri) self.root.ids.file_label.text = f"Selected File: {selected_file_name}" try: with open(uri.getPath(), 'rb') as file: raw_data = file.read() file_content = raw_data.decode('utf-8') self.file_content_label.text = file_content except Exception as e: self.root.ids.file_content_label.text = f"Error reading file: {e}" def get_file_name_from_uri(self, uri): resolver = autoclass('android.content.ContentResolver') resolver_instance = resolver(activity.getContentResolver()) cursor = resolver_instance.query(uri, None, None, None, None) if cursor.moveToFirst(): column_index = cursor.getColumnIndex('_display_name') return cursor.getString(column_index) if __name__ == '__main__': FileManagerApp().run()
问题分析与修复方案
核心问题点
- Kivy的
App类不会自动触发on_activity_result,必须通过JNI手动注册回调 ACTION_OPEN_DOCUMENT返回的是内容URI,不能直接用uri.getPath()打开文件,必须通过ContentResolver读取get_file_name_from_uri中未正确获取ContentResolver实例,且未关闭cursor导致内存泄漏- 缺少文件持久化权限请求,重启APP后可能无法访问已选中的文件
修正后的代码
from kivy.lang import Builder from kivy.uix.boxlayout import BoxLayout from kivy.app import App from jnius import autoclass, cast from android import mActivity KV = ''' BoxLayout: orientation: 'vertical' Button: text: "Open File Manager" on_release: app.open_file_manager() Label: id: file_label text: "Selected File: None" halign: 'center' ScrollView: Label: id: file_content_label text: "" text_size: self.width, None size_hint_y: None height: self.texture_size[1] ''' class FileManagerApp(App): def build(self): self.register_activity_result_callback() return Builder.load_string(KV) def register_activity_result_callback(self): # 注册Activity结果回调 PythonActivity = autoclass('org.kivy.android.PythonActivity') activity = PythonActivity.mActivity ActivityResultCallback = autoclass('android.app.Activity$OnActivityResultCallback') class MyCallback(ActivityResultCallback): def onActivityResult(self, requestCode, resultCode, data): self.parent.on_activity_result(requestCode, resultCode, data) self.callback = MyCallback() self.callback.parent = self activity.registerActivityResultCallback(self.callback) def open_file_manager(self): Intent = autoclass('android.content.Intent') intent = Intent(Intent.ACTION_OPEN_DOCUMENT) intent.setType("*/*") # 添加权限标记,确保能持久访问文件 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) mActivity.startActivityForResult(intent, 0) def on_activity_result(self, requestCode, resultCode, data): Activity = autoclass('android.app.Activity') if resultCode == Activity.RESULT_OK and data is not None: uri = data.getData() content_resolver = mActivity.getContentResolver() # 申请持久化权限 take_flags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION) content_resolver.takePersistableUriPermission(uri, take_flags) selected_file_name = self.get_file_name_from_uri(uri) self.root.ids.file_label.text = f"Selected File: {selected_file_name}" try: # 通过ContentResolver读取文件内容 input_stream = content_resolver.openInputStream(uri) input_stream = cast('java.io.InputStream', input_stream) raw_data = input_stream.read() input_stream.close() file_content = raw_data.decode('utf-8') self.root.ids.file_content_label.text = file_content except Exception as e: self.root.ids.file_content_label.text = f"Error reading file: {str(e)}" def get_file_name_from_uri(self, uri): content_resolver = mActivity.getContentResolver() cursor = content_resolver.query(uri, None, None, None, None) file_name = "Unknown" try: if cursor.moveToFirst(): column_index = cursor.getColumnIndex('_display_name') if column_index != -1: file_name = cursor.getString(column_index) finally: cursor.close() # 必须关闭cursor,避免内存泄漏 return file_name if __name__ == '__main__': FileManagerApp().run()
额外配置要求
在buildozer.spec中确保添加以下权限和配置:
android.permissions = READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, MANAGE_EXTERNAL_STORAGE android.api = 33 android.ndk = 25b
内容的提问来源于stack exchange,提问作者Harshit
相关产品推荐
相关产品推荐

