#android #android-activity #parcelable
#Android #android-активность #разделяемый
Вопрос:
Итак, я гуглил большую часть вчерашнего дня и прошлую ночь и, похоже, просто не могу понять, как передать arraylist в подактивность. Существует множество примеров и фрагментов, передающих примитивные типы данных, но у меня есть arraylist типа address (адрес.java ниже).
Я нашел много информации об этом в stackoverflow и по всему Интернету, но ничего, что привлекло бы много внимания, за исключением примера с геопунктом. Опять же, мне показалось, что они просто разделили объект GeoPoint на два целых числа и передали его. Я не могу этого сделать, потому что мой класс address может расширяться, чтобы включать целые числа, числа с плавающей точкой, что угодно. На данный момент приведенное ниже тестовое приложение состоит всего из двух строк для простоты. Я подумал, что если бы я мог заставить parcelalbe работать с этим, остальное могло бы последовать.
Может ли кто-нибудь опубликовать рабочий пример для ArrayList непримитивного объекта или, возможно, добавить приведенный ниже код, чтобы заставить это работать?
ОБНОВЛЕНИЕ: приведенный ниже код теперь работает после ответов / редактирования. Спасибо!
/* helloParcel.java */
public class helloParcel extends Activity
{
// holds objects of type 'address' == name and state
private ArrayList <address> myList;
@Override
public void onCreate (Bundle savedInstanceState)
{
super.onCreate (savedInstanceState);
setContentView (R.layout.main);
Button b1 = (Button) findViewById(R.id.button1);
b1.setOnClickListener(ocl);
myList = new ArrayList();
address frank = new address ("frank", "florida");
address mary = new address ("mary", "maryland");
address monty = new address ("monty", "montana");
myList.add (frank);
myList.add (mary);
myList.add (monty);
// add the myList ArrayList() the the extras for the intent
}
OnClickListener ocl = new OnClickListener()
{
@Override
public void onClick(View v)
{
// fill parceable and launch activity
Intent intent = new Intent().setClass(getBaseContext (), subActivity.class);
// for some reason, I remember a posting saying it's best to create a new
// object to pass. I have no idea why..
ArrayList <address> addyExtras = new ArrayList <address>();
for (int i = 0; i < myList.size(); i )
addyExtras.add (myList.get(i));
intent.putParcelableArrayListExtra ("mylist", addyExtras);
startActivity(intent);
}
};
}
/* address.java */
public class address implements Parcelable
{
private String name;
private String state;
private static String TAG = "** address **";
public address (String n, String s)
{
name = n;
state = s;
Log.d (TAG, "new address");
}
public address (Parcel in)
{
Log.d (TAG, "parcel in");
name = in.readString ();
state = in.readString ();
}
public String getState ()
{
Log.d (TAG, "getState()");
return (state);
}
public String getName ()
{
Log.d (TAG, "getName()");
return (name);
}
public static final Parcelable.Creator<address> CREATOR
= new Parcelable.Creator<address>()
{
public address createFromParcel(Parcel in)
{
Log.d (TAG, "createFromParcel()");
return new address(in);
}
public address[] newArray (int size)
{
Log.d (TAG, "createFromParcel() newArray ");
return new address[size];
}
};
@Override
public int describeContents ()
{
Log.d (TAG, "describe()");
return 0;
}
@Override
public void writeToParcel (Parcel dest, int flags)
{
Log.d (TAG, "writeToParcel");
dest.writeString (name);
dest.writeString (state);
}
}
/* subActivity.java */
public class subActivity extends Activity
{
private final String TAG = "** subActivity **";
private ArrayList <address> myList;
@Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate (savedInstanceState);
Log.d (TAG, "onCreate() in subActivity");
setContentView(R.layout.subactivity);
TextView tv1 = (TextView) findViewById(R.id.tv_sub);
myList = getIntent().getParcelableArrayListExtra ("mylist");
Log.d (TAG, "got myList");
for (int i = 0; i < myList.size (); i )
{
address a = myList.get (i);
Log.d (TAG, "state:" a.getState ());
tv1.setText (a.getName () " is from " a.getState ());
}
}
}
Комментарии:
1. Отлично!!!!!!!!!!!!! Отлично сработало, я использовал это в первый раз. Спасибо
Ответ №1:
Я вижу здесь ряд проблем:
-
Зачем использовать addressParcelable? Почему бы не сделать address реализуемым Parcelable, а затем использовать:
intent.putParcelableArrayListExtra( "addresses", addyExtras );
-
Ваш разделяемый объект должен содержать статический СОЗДАТЕЛЬ. Подробности см. в документации.
-
На самом деле вы не добавляете никаких дополнительных функций к intent перед вызовом
startActivity()
. Смотрите пункт 1 для получения предложения здесь.
Я думаю, что вам нужно будет решить все эти проблемы, чтобы заставить его работать.
Комментарии:
1. В какой-то момент я подумал, что мне нужен дополнительный класс (реализующий Parcelable) для преобразования всего объекта заново. Я думаю, что именно оттуда пришел addressParcelable. Я удалил это из кода выше. Я реализовал ваши предложения, хотя, возможно, и не совсем правильно. Не могли бы вы взглянуть, когда у вас будет время? Получаю ошибку нулевого указателя в SubActivity (), которую я сейчас пытаюсь устранить.
2. Я думаю, что вам нужно вызвать GetIntent().getParcelableArrayList («mylist»), а не savedInstanceState.getParcelableArrayList («mylist»);
3. вы имеете в виду getParcelableArrayListExtra()? Пробовал это, но получаю новую ошибку (см. Недавно отредактированный код выше).
4. 🙂 Я думаю, что теперь это работает! Отредактированный выше код — пришлось модифицировать конструктор в классе address
5. Молодцы, что заставили это работать. Я думаю, вы могли бы обойтись без addyExtras и просто иметь intent.putParcelableArrayListExtra («mylist», myList); — что избавило бы вас от перебора списка
Ответ №2:
Это можно сделать НАМНОГО проще, без всей этой мучительной реализации Parcelable
… ArrayList
(но НЕ любое List
) есть Serializable
. Итак, вы можете поместить весь список с помощью putExtra()
и извлечь его с помощью getSerializableExtra()
, как сказал Сэм.
НО я хочу добавить еще одну важную вещь: объект, который хранится в вашем списке массивов, также должен быть реализован Serializable
… и все другие сложные объекты, которые может содержать объект (в вашем случае none), также должны это реализовывать (поэтому это рекурсивно — чтобы сериализовать объект, вы должны иметь возможность сериализовать все его поля).
Теперь вы можете спросить себя, зачем внедрять, Serializable
вместо Parcelable
, когда уже существуют методы для чтения и записи списков массивов parcelables? Что ж… разница в простоте — просто добавьте implements Serializable
и необязательно private static final long serialVersionUID = SOME_CONSTANT
, и все готово! Вот причина, по которой я никогда не использую Parcelable
— вы можете выполнять все эти вещи, используя Serializable
буквально 2 строки кода — вместо множества наследований методов и всего такого прочего…
Комментарии:
1. Преимущество Parcelable перед Serializable заключается в том, что это намного быстрее. Если ваш список большой, разница может быть заметной.
Ответ №3:
Вы можете передавать сериализуемые объекты через putExtra. ArrayList реализует Serializable.
Комментарии:
1. Огромная помощь. Спасибо. Можно было бы подумать, что это стало бы более очевидным.
Ответ №4:
Генеральный директор Майк прав!
putExtra()
и getSerializable()
будет хранить и извлекать ArrayList<>
ваши пользовательские объекты, при этом реализация интерфейса не требуется. Сработало для меня!
Комментарии:
1. Извините, я был неправ.. ваш объект должен реализовать Serializable .. но после этого он работает..