【问题标题】:Sharing Intent - silently fails if too many items are shared共享意图 - 如果共享的项目太多,则静默失败
【发布时间】:2015-12-25 15:33:18
【问题描述】:

我使用附加功能共享媒体并且有以下问题:如果我共享太多项目,共享意图会静默失败。日志中没有调试消息或类似消息,也没有延迟选择目标表……如果我共享太多项目,什么也不会发生。大约 50 件物品似乎是极限......

有人知道为什么会这样吗?或者有解决方案吗?有没有办法查明我是否共享了太多 uri?

public static void shareMediaUris(Activity activity, ArrayList<Uri> uris)
{
    Intent sharingIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    sharingIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);// | Intent.FLAG_ACTIVITY_NEW_TASK);

    sharingIntent.setType("*/*");
    String[] mimetypes = {"image/*", "video/*"};
    sharingIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);

    sharingIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);

    finishShare(activity, sharingIntent);
}

public static void finishShare(Activity activity, Intent intent)
{
    List<ResolveInfo> resolveInfo = MainApp.get().getPackageManager().queryIntentActivities(intent, 0);
    if (!resolveInfo.isEmpty())
    {
        for (int i = resolveInfo.size() - 1; i >= 0; i--)
        {
            if (resolveInfo.get(i).activityInfo.packageName.equals(MainApp.get().getPackageName()))
                resolveInfo.remove(i);
        }

        if (resolveInfo.size() == 0)
            activity.startActivity(Intent.createChooser(intent, MainApp.get().getString(R.string.share_with)));
        else
        {
            List<Intent> targetedShareIntents = new ArrayList<Intent>();
            for (int i = 0; i < resolveInfo.size(); i++)
            {
                Intent targetedShareIntent = (Intent) intent.clone();
                targetedShareIntent.setPackage(resolveInfo.get(i).activityInfo.packageName);
                targetedShareIntent.setClassName(resolveInfo.get(i).activityInfo.packageName, resolveInfo.get(i).activityInfo.name);
                targetedShareIntents.add(targetedShareIntent);
            }
            Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(targetedShareIntents.size() - 1), activity.getString(R.string.share_with));
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[targetedShareIntents.size()]));
            activity.startActivity(chooserIntent);
        }
    }
    else
        activity.startActivity(Intent.createChooser(intent, MainApp.get().getString(R.string.share_with)));
}

【问题讨论】:

    标签: android android-intent share


    【解决方案1】:

    以下是 Google 问题跟踪器对此问题的了解:Issue 5878: Intent Extras Have Size Limitation。 IE。这是“按设计”的行为。

    我设法重现了它。如果我分享 500 URIs 它可以工作,如果我分享 1000 URIs - 它会默默地什么都不做(我相信,这正是你的经验),如果我分享数千 - 它会崩溃(大小限制,请参阅我的原始答案的一部分)。

    我查看了Android的源代码。
    在Instrumentation 类中,这个sn-p 启动选择器活动,不启动选择器活动或崩溃,取决于Intent 中Bundle 的大小。

            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
    

    更准确地说,Binder类的transactNative()方法:

    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
        return transactNative(code, data, reply, flags);
    }
    

    在这两种情况下,它都会返回 0 作为结果,即ActivityManager.START_SUCCESS。不仅如此,onPause() 的原始活动正在被调用!

    唯一的区别是它会立即调用原始活动的onResume(),您可以将其用作提示,表明出现问题。

    但总的来说,“选择器尚未启动”和应用程序崩溃之间的界限非常模糊:

    E/JavaBinder: !!! Binder 交易失败!!! (包裹大小=3100860)

    我建议

    • 限制应用内可能的共享项目数量,以避免这种行为

    • 将startActivity(chooserIntent) 包裹到try-catch 块中以避免由于TransactionTooLargeException 而导致崩溃

    • 如果在 startActivity(chooserIntent) 之后没有抛出异常,但调用了原始 Activity 的 onResume() - 将其视为异常(即通知用户,存在技术问题,用户必须选择更少要分享的项目)

    原始答案:我认为,您只是坚持使用Intent 的Bundle 的size-limit - 大约 1MB

    有一篇不错的文章,在这里进行了描述:Yet another post on Serializable vs Parcelable
    你可以在这里阅读更多信息:Is there some limits in android' bundle?

    【讨论】:

    • 感谢您的详细回答。对我来说,限制在 40 URIs 左右,500 对我来说就更好了......关于如何让它变得更好的任何想法?您可能只是在没有从显示的共享目标中删除应用程序本身的情况下尝试了它...我将限制要共享的项目(对我来说,100 或 250 个就可以了),但是大约 40 个似乎太低了...
    • @prom85 很明显,您可以尝试查看它是否改变了任何东西 - 禁用 finishShare 并用 activity.startActivity(Intent.createChooser(intent, MainApp.get().getString(R.string.share_with))); 替换它只是为了看看您的“限制”是否受到第二种方法的影响(让我们知道!)。如果它保持不变 - 我只能猜测,你的 URI 比我的大(我只是从模拟器中选择了相同的示例图像 500 次)。我会考虑更多。同时,我建议等待其他人是否可以分享他们对这个问题的见解。
    • 限制受我的第二种方法影响。无论如何(我已经忘记了),我现在使用自定义共享对话框,只处理此对话框的共享意图(不修改它!),对话框显示可能的共享目标......这样,我可以删除我自己的应用程序甚至以我想要的方式显示它们,并且我不会使用第二种方法增加意图大小......现在测试了这个,它似乎有一个接近 500 的限制......你的回答仍然有帮助,因为它指出了大小限制所以我现在知道如何处理这个问题。谢谢
    • @prom85 只是:50 和 500 相差 10 倍,您是否有 targetedShareIntents 附近的某个地方(只是好奇)?无论如何,我很高兴你已经弄清楚了:-)
    • 不明白你的问题是什么......我不再使用targetedShareIntents,我只是使用基本意图(不再克隆)。使用基本意图,我查询可能的目标应用程序并将它们显示在我自己的对话框中,然后如果用户选择一个目标,我只是更新基本意图,因为我在其上设置了组件,以便直接与目标应用...
    猜你喜欢
    • 1970-01-01
    • 2013-08-17
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多