2015-12-25 1 views
1

Я обмениваюсь средствами массовой информации с прилагаемой функцией и имею следующую проблему: если я разделяю слишком много элементов, намерение совместного использования не работает. Нет отладочного сообщения в журнале или аналогичном и без отложенного целевого листа ... Просто ничего не происходит, если я разделяю слишком много элементов. Где-то около 50 предметов, как представляется, являются предел ...Sharing Intent - бесшумно терпит неудачу, если слишком много предметов разделяются

Кто-нибудь знает, почему это происходит? Или есть решение для этого? Есть ли способ узнать, не разделяю ли я слишком много урисов?

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))); 
} 

ответ

1

Вот что компании Google Issue Tracker знает об этой проблеме: Issue 5878: Intent Extras Have Size Limitation. То есть это «по дизайну« Поведение.

Мне удалось воспроизвести его. Если я разделяю 500 URI s, он работает, если я разделяю 1000 URI s - он молча ничего не делает (я считаю, это ваш опыт), если я делюсь несколькими тысячами - он падает (размер-размер, см. Часть моего первоначального ответа).

Я проверил исходный код Android.
В классе Instrumentation этот фрагмент запускает операцию выбора, а не начинает операцию выбора или сбоев, зависит от размера 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:

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() первоначальной деятельности, которую вы можете использовать в качестве подсказки, что-то пошло не так.

Но в целом, так как есть очень размыто линия между "Chooser не началась" и приложение разбился с:

E/JavaBinder: !!! СРОК ДЕЙСТВИЯ СДЕЛКИ !!! (Размер посылки = 3100860)

Я хотел бы предложить, чтобы

  • предельного числа возможных общих элементов внутри приложения только, чтобы избежать этого

  • оберточной startActivity(chooserIntent) в try-catch блока чтобы избежать аварии из-за TransactionTooLargeException

  • в случае если после startActivity(chooserIntent) исключение не было выбрано, но onResume() изначально называется Activity - обрабатывайте его так же, как исключение (т.уведомляет пользователя, что есть техническая проблема, и пользователь должен выбрать меньше элементов для обмена)

Оригинальный ответ: Я думаю, вы просто застряли с размерного предела из Intent «s Bundle - это около 1 Мб

Там хорошая статья, которая описывает его здесь: Yet another post on Serializable vs Parcelable
И вы можете прочитать об этом здесь: Is there some limits in android' bundle?

+0

Спасибо за подробный ответ. Для меня предел составляет около 40 'URI', 500 будет для меня более чем прекрасным ... Любые идеи о том, как сделать это лучше? Вероятно, вы просто попробовали это, не удалив приложение из показанных целей для общего доступа ... Я ограничу элементы для обмена (что-то вроде 100 или 250 будет хорошо для меня), но что-то примерно 40 кажется слишком низким ... – prom85

+0

@ prom85 Очевидная вещь, которую вы можете попробовать увидеть, если она что-то изменит - отключите 'finishShare' и замените ее на' activity.startActivity (Intent.createChooser (намерение, MainApp.get(). GetString (R.string.share_with))), 'просто чтобы увидеть, если ваш« предел »каким-либо образом затронут вашим вторым методом (и дайте нам знать!). Если он останется прежним - я могу просто догадаться, что ваши URI как-то больше, чем мои (я просто выбрал одно и то же изображение образца из эмулятора 500 раз). Я подумаю об этом подробнее. Тем временем я предлагаю подождать, если кто-нибудь еще сможет поделиться своими соображениями относительно вопроса. –

+0

Ограничение влияет на мой второй метод. В любом случае (я уже забыл), теперь я использую пользовательское диалоговое окно совместного доступа и просто обрабатываю намерение общего доступа к этому диалоговому окну (без его изменения!), И в диалоговом окне отображаются возможные цели для общего доступа ... Таким образом, я могу удалить свое собственное приложение и даже отображать их так, как я хочу, и я не увеличиваю размер намерений со вторым методом ... Протестировал это сейчас, кажется, есть предел где-то около 500 ... Еще ваш ответ помогает, поскольку он указал размер поэтому я знаю, как это сделать. Спасибо – prom85