Ответ 1
У меня была та же проблема, что и у OP.
Проблема заключалась в том, что через Intent
, который запускает IntentService
, я пропускаю огромный ArrayList
(около 4000 элементов Parcelable
). Диагностировать его было крайне сложно, так как он "молчал" на клиентском устройстве, поэтому я не получил отчета об ошибке ACRA.
Во всяком случае, я использовал быстрый и грязный трюк, чтобы исправить проблему - в основном, чтобы сохранить ArrayList
в статическом элементе, который я использовал для установки/получения ArrayList, а не пытаться передать его через Intent.
В ходе дальнейшего исследования (некоторые тесты других устройств) я обнаружил, что был выброшен TransactionTooLargeException
. Подробнее об этом здесь.
Здесь мой тестовый код, если кто-то захочет реплицировать:
Тестовый код
Если вы хотите заставить его работать, измените значение 4000
на нечто гораздо меньшее.
ArrayList<ParcelableNameValuePair> testArrayList = new ArrayList<>();
for (int i = 0; i < 4000; i++) {
testArrayList.add(new ParcelableNameValuePair("name" + i, "value" + i));
}
TestIntentService.startAction(AdminHomeActivity.this, testArrayList);
TestIntentService.java
public class TestIntentService extends IntentService {
private static final String LOG_TAG = TestIntentService.class.getSimpleName();
private static final String TEST_ACTION = "com.example.action.FOO";
private static final String EXTRA_PARAM1 = "com.example.extra.PARAM1";
private static final String EXTRA_PARAM2 = "com.example.extra.PARAM2";
public TestIntentService() {
super("TestIntentService");
}
public static void startAction(Context context, ArrayList<ParcelableNameValuePair> testArrayList) {
Log.d(LOG_TAG, "1. startAction()");
Utilities.makeToast(context, "1. startAction()");
try {
int arrayListSize = (testArrayList == null) ? -1 : testArrayList.size();
Log.d(LOG_TAG, "2. arrayListSize: " + arrayListSize);
Utilities.makeToast(context, "2. arrayListSize: " + arrayListSize);
Intent intent = new Intent(context, TestIntentService.class);
intent.setAction(TEST_ACTION);
//intent.putExtra(EXTRA_PARAM1, testArrayList);
intent.putParcelableArrayListExtra(EXTRA_PARAM2, testArrayList);
/**
* This line should result in a call to onHandleIntent() but, if we're sending a huge ArrayList, it doesn't...
*/
context.startService(intent);
}
catch(Exception e) {
Log.e(LOG_TAG, "Exception starting service", e);
Utilities.makeToast(context, "Exception starting service: " + e);
}
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d(LOG_TAG, "3. onHandleIntent()");
Utilities.makeToast(getApplicationContext(), "3. onHandleIntent()");
try {
if (intent != null) {
final String action = intent.getAction();
if (TEST_ACTION.equals(action)) {
ArrayList<ParcelableNameValuePair> testArrayList = intent.getParcelableArrayListExtra(EXTRA_PARAM1);
int testArrayListSize = (testArrayList == null) ? -1 : testArrayList.size();
Log.d(LOG_TAG, "4. testArrayListSize: " + testArrayListSize);
Utilities.makeToast(getApplicationContext(), "4. testArrayListSize: " + testArrayListSize);
ArrayList<ParcelableNameValuePair> testArrayList2 = intent.getParcelableArrayListExtra(EXTRA_PARAM2);
int testArrayList2Size = (testArrayList2 == null) ? -1 : testArrayList2.size();
Log.d(LOG_TAG, "5. testArrayList2Size: " + testArrayList2Size);
Utilities.makeToast(getApplicationContext(), "5. testArrayList2Size: " + testArrayList2Size);
}
}
}
catch(Exception e) {
Log.e(LOG_TAG, "Exception handling service intent", e);
Utilities.makeToast(getApplicationContext(), "Exception handling service intent: " + e);
}
}
}
ParcelableNameValuePair.java
public class ParcelableNameValuePair implements Parcelable {
private String name, value;
public ParcelableNameValuePair(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(name);
out.writeString(value);
}
public static final Parcelable.Creator<ParcelableNameValuePair> CREATOR = new Parcelable.Creator<ParcelableNameValuePair>() {
public ParcelableNameValuePair createFromParcel(Parcel in) {
return new ParcelableNameValuePair(in);
}
public ParcelableNameValuePair[] newArray(int size) {
return new ParcelableNameValuePair[size];
}
};
private ParcelableNameValuePair(Parcel in) {
name = in.readString();
value = in.readString();
}
}
Как я уже сказал, я использовал быстрое и грязное решение, чтобы обойти эту проблему. Я думаю, что лучшим решением для приложения было бы записать ArrayList
в файловую систему, затем передать ссылку на этот файл (например, имя_файла/путь) через Intent на IntentService
, а затем позволить IntentService
получить содержимое файла и преобразовать его обратно в ArrayList
.
Когда файл IntentService
сделал с файлом, он должен либо удалить его, либо передать инструкцию обратно в приложение через локальную широковещательную рассылку, чтобы удалить созданный файл (передав обратно ту же ссылку на файл, которая была ему предоставлена)).