共享意图 - 如果共享的项目太多,则静默失败
Sharing Intent - silently fails if too many items are shared
我使用附加功能共享媒体并遇到以下问题:如果我共享太多项目,共享意图会自动失败。日志或类似内容中没有调试消息,也没有延迟 select 目标 sheet... 如果我共享太多项目,什么也不会发生。大约 50 个项目似乎是极限...
有谁知道为什么会这样?或者有解决方案吗?有没有办法查明我是否分享了太多 uris?
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)));
}
以下是 Google 的问题跟踪器对这个问题的了解:Issue 5878: Intent Extras Have Size Limitation。 IE。这是“设计”行为。
我设法重现了它。如果我分享 500 URI
s 它有效,如果我分享 1000 URI
s - 它默默地什么也不做(我相信,这正是你的经验),如果我分享几千 - 它崩溃(size-limit,请参阅我的原始答案部分)。
我查看了Android的源代码。
在 Instrumentation
class 此代码段启动 chooser-activity,不启动 chooser-activity 或崩溃,取决于 Bundle
在 Intent
的大小。
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
更准确地说,transactNative()
Binder
class 的方法:
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);
}
在这两种情况下,non-crash 都是 returns 0 作为结果,即 ActivityManager.START_SUCCESS
。不止如此,原来activity的onPause()
正在被调用!
唯一的区别是 它会立即调用原始 activity 的 onResume()
,您可以将其用作提示,表明出现了问题。
但总的来说,"chooser hasn't started" 和应用程序崩溃之间的界限非常模糊:
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 3100860)
我建议
限制应用内可能共享项目的数量以避免这种行为
将startActivity(chooserIntent)
包装到try-catch
块中以避免由于TransactionTooLargeException
导致崩溃
如果在 startActivity(chooserIntent)
之后未抛出异常,但调用了原始 Activity 的 onResume()
- 将其视为与异常相同的方式(即通知用户,存在技术问题,用户必须 select 更少的项目来共享)
原回答: 我想,你只是坚持size-limit Intent
的 Bundle
- 大约 1MB
有一篇不错的文章,在此处对其进行了描述:Yet another post on Serializable vs Parcelable
你可以在这里阅读更多相关信息:Is there some limits in android' bundle?
我使用附加功能共享媒体并遇到以下问题:如果我共享太多项目,共享意图会自动失败。日志或类似内容中没有调试消息,也没有延迟 select 目标 sheet... 如果我共享太多项目,什么也不会发生。大约 50 个项目似乎是极限...
有谁知道为什么会这样?或者有解决方案吗?有没有办法查明我是否分享了太多 uris?
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)));
}
以下是 Google 的问题跟踪器对这个问题的了解:Issue 5878: Intent Extras Have Size Limitation。 IE。这是“设计”行为。
我设法重现了它。如果我分享 500 URI
s 它有效,如果我分享 1000 URI
s - 它默默地什么也不做(我相信,这正是你的经验),如果我分享几千 - 它崩溃(size-limit,请参阅我的原始答案部分)。
我查看了Android的源代码。
在 Instrumentation
class 此代码段启动 chooser-activity,不启动 chooser-activity 或崩溃,取决于 Bundle
在 Intent
的大小。
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
更准确地说,transactNative()
Binder
class 的方法:
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);
}
在这两种情况下,non-crash 都是 returns 0 作为结果,即 ActivityManager.START_SUCCESS
。不止如此,原来activity的onPause()
正在被调用!
唯一的区别是 它会立即调用原始 activity 的 onResume()
,您可以将其用作提示,表明出现了问题。
但总的来说,"chooser hasn't started" 和应用程序崩溃之间的界限非常模糊:
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 3100860)
我建议
限制应用内可能共享项目的数量以避免这种行为
将
startActivity(chooserIntent)
包装到try-catch
块中以避免由于TransactionTooLargeException
导致崩溃
如果在
startActivity(chooserIntent)
之后未抛出异常,但调用了原始 Activity 的onResume()
- 将其视为与异常相同的方式(即通知用户,存在技术问题,用户必须 select 更少的项目来共享)
原回答: 我想,你只是坚持size-limit Intent
的 Bundle
- 大约 1MB
有一篇不错的文章,在此处对其进行了描述:Yet another post on Serializable vs Parcelable
你可以在这里阅读更多相关信息:Is there some limits in android' bundle?