Android - 选择和查看任何类型的文件

时间:2017-04-07 13:26:28

标签: android android-intent

我希望用户能够在手机中选择任何文件类型,然后使用意图再次查看。

选择文件项我写这个(我使用Kotlin,Java中的同样问题):

    fun goToDocumentPicker() {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
        intent.addCategory(Intent.CATEGORY_OPENABLE)
        intent.type = "*/*"
        if (intent.resolveActivity(mContext.packageManager) != null)
            mContext.startActivityForResult(intent, REQUEST_DOCUMENT)
    }

并显示所选项目:

 fun showDocumentPreviewer(uri: Uri) {
        val i = Intent(Intent.ACTION_VIEW)
        i.data = uri
        mContext.startActivity(i)
    }

文档选择器工作正常,在onActivityResult我可以接收所选文档的Uri对象,但文档预览器无法打开该对象。已经尝试将mime-type设置为预览器的意图但不成功。我在Android中使用不正确的方式打开文件了吗?在Android中显示任何文件类型的任何通用方法? (因为我想支持许多文件类型)

选择了Uri:content://com.android.providers.media.documents/document/image:80

更新 根据@ CommonsWare的评论,我编辑了预览功能,如下所示:

fun showAttachmentPreviewer(uri: Uri, mimeType: String?) {
    Log.d("TEST", "Preview " + uri.toString())
    val intent = Intent(Intent.ACTION_VIEW, uri)
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

    val chooser = Intent.createChooser(intent, "Open with")
    if (intent.resolveActivity(mContext.packageManager) != null)
        mContext.startActivity(chooser)
    else
        mContext.showSnackBar("No suitable application to open file")
}

现在应用程序总是崩溃,崩溃日志如下:

  

java.lang.SecurityException:Uid 10202没有uri的权限   0 @   内容://com.android.providers.media.documents/document/audio:17915

更新2: 我的应用在mContext.startActivity(chooser)行崩溃了。这是完整的崩溃日志:

  

致命的例外:主要                                                                    处理:com.makeit.lite,PID:12851                                                                    java.lang.SecurityException:Uid 10477没有uri的权限   0 @   内容://com.android.providers.media.documents/document/image:24776                                                                        在android.os.Parcel.readException(Parcel.java:1540)                                                                        在android.os.Parcel.readException(Parcel.java:1493)                                                                        在   android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2514)                                                                        在   android.app.Instrumentation.execStartActivity(Instrumentation.java:1494)                                                                        在android.app.Activity.startActivityForResult(Activity.java:3913)                                                                        在   android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:50)                                                                        在   android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:79)                                                                        在android.app.Activity.startActivityForResult(Activity.java:3860)                                                                        在   android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:859)                                                                        在android.app.Activity.startActivity(Activity.java:4184)                                                                        在android.app.Activity.startActivity(Activity.java:4152)                                                                        在   com.makeit.lite.attachment.AttachmentNavigator.showAttachmentPreviewer(AttachmentNavigator.kt:92)                                                                        在   com.makeit.lite.attachment.list.AttachmentListPresenter.onAttachmentClicked(AttachmentListPresenter.kt:37)                                                                        在   com.makeit.lite.attachment.list.AttachmentListFragment $ onViewCreated $ 1.onItemClick(AttachmentListFragment.kt:39)                                                                        在   eu.davidea.viewholders.FlexibleViewHolder.onClick(FlexibleViewHolder.java:121)                                                                        在android.view.View.performClick(View.java:5156)                                                                        在android.view.View $ PerformClick.run(View.java:20755)                                                                        在android.os.Handler.handleCallback(Handler.java:739)                                                                        在android.os.Handler.dispatchMessage(Handler.java:95)                                                                        在android.os.Looper.loop(Looper.java:145)                                                                        在android.app.ActivityThread.main(ActivityThread.java:5835)                                                                        at java.lang.reflect.Method.invoke(Native Method)                                                                        在java.lang.reflect.Method.invoke(Method.java:372)                                                                        在   com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:1399)                                                                        在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

更新3: 如果我将mimeType设置为intent:intent.type = mimeType并且应用程序不再崩溃。 mimeType是我从选择器意图获得的字符串(在content: uri旁边)。 mimeType值可以image/jpeg或基于所选文件类型的任何内容。虽然它不会崩溃,但是给定uri的文件也不会显示。如果我从Intent-Chooser中选择Gallery,则会打开并显示所有图像。我想第3个应用程序不知道如何在给定的uri确定文件。

以下是我的功能的最新来源:

fun showAttachmentPreviewer(uri: Uri, mimeType: String?) {
        Log.d("TEST", "Preview " + uri.toString() + " For type" + mimeType)
        val intent = Intent(Intent.ACTION_VIEW, uri)
        intent.type = mimeType //Can be "image/jpeg" or sth corresponding to the filetype.
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        val chooser = Intent.createChooser(intent, "Open with")
        if (intent.resolveActivity(mContext.packageManager) != null)
            mContext.startActivity(chooser)
        else
            mContext.showSnackBar("No suitable application to open file")
    }

4 个答案:

答案 0 :(得分:3)

  

我是否使用错误的方法在Android中打开文件?

首先,可能没有能够查看文件类型的应用程序。

其次,您尚未授予该应用查看内容的权限。在 - (NSManagedObjectModel *)managedObjectModel { if (_managedObjectModel != nil) { return _managedObjectModel; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"PPUSFAModel" withExtension:@"momd"]; //I earlier was PPUSFAModel 16, i added new model version PPUSFAModel 17. _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return _managedObjectModel; } - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (_persistentStoreCoordinator != nil) { return _persistentStoreCoordinator; } NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:SQLITENAME]; NSError *error = nil; _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) { //Error } return _persistentStoreCoordinator; } - (void)saveContext { __block NSError *error = nil; NSManagedObjectContext *managedObjectContext = self.managedObjectContext; [managedObjectContext performBlockAndWait:^{ if (managedObjectContext != nil && _persistentStoreCoordinator != nil) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. // DLog(@"Unresolved error %@, %@", error, [error userInfo]); //abort(); } } }]; } 上使用addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

答案 1 :(得分:0)

如果要对文件执行完美功能,则应使用任何第三方库来实现此功能。

您应该查看以下链接,了解文件选择器的最常见库: -

https://android-arsenal.com/tag/35?sort=created

答案 2 :(得分:0)

  val intent = Intent(Intent.ACTION_VIEW, uri)
  intent.type = mimeType 

更改为

  val intent = Intent(Intent.ACTION_VIEW);
  intent.setDataAndType (uri, mimeType ); 

您应该使用一个语句设置uri和mime类型。否则接收应用将为uri收到null。大多数应用程序不会告诉您他们没有收到uri。例如,Gallery应用程序没有。

我不知道Kotlin的确切功能名称。

答案 3 :(得分:0)

首先,我想对@GreenApps,@ Ankit和@CommonsWare表示感谢。谁花时间调查我的问题。

我在将源提取到分离的简单项目时终于找到了根本原因。这是因为我用这种方式将uri-string解析成uri-instance(根本原因的代码没有包含在我的问题中。我的道歉):

val uri = Uri.parse(URLDecoder.decode(uriString, "UTF-8")) as Uri

当我改为val uri = Uri.parse(uriString)时,问题就解决了。

顺便说一下,我想在我的Github上分享选择器和预览器的示例代码,以便有人可能需要看看。 java源位于master分支上,Kotlin源位于kotlin-version分支上。使用这个简单的代码,现在我可以选择任何文件类型(图像,音频,视频,pdf,xlsx,...),然后通过Intent.ACTION_VIEW打开它。

这是:

  

https://github.com/IHNEL/UriPickerPreviewer