Я новичок в программировании Android, и у меня возникают проблемы при передаче ArrayList Parcelable фрагменту. Это запущенное действие (работающее хорошо!), Где список каналов представляет собой список массивов музыки .
Intent in = new Intent(context, ListMusicsActivity.class);
in.putExtra("arrayMusic", feedList);
activity.startActivity(in);
Метод фрагмента Activity onCreate ():
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activitymusiclist);
if(savedInstanceState != null)
{
ListMusicFragment frag = new ListMusicFragment();
frag.setArguments(getIntent().getExtras());
}
}
Код фрагмента:
public class ListMusicFragment extends SherlockFragment{
private ArrayList<Music> listMusics = new ArrayList<Music>();
private ListView listMusic;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
listMusics = (ArrayList<Music>) getArguments().getSerializable("arrayMusic");
View view = inflater.inflate(R.layout.musiclistview, container, false);
listMusic = (ListView) view.findViewById(R.id.musicListView);
listMusic.setAdapter(new MusicBaseAdapter(getActivity(), listMusics));
return view;
}
}
Я думаю проблема в линии
listMusics = (ArrayList<Music>) getArguments().getSerializable("arrayMusic");
Наконец, это мой класс музыки:
public class Music implements Parcelable{
private String url;
private String artist;
private String title;
private String duration;
private String info_url;
private String lyrics;
public Music(String url, String artist, String title,
String duration, String lyrics, String info_url)
{
this.url = url;
this.artist = artist;
this.title = title;
this.duration = duration;
this.lyrics = lyrics;
this.info_url = info_url;
}
public Music(Parcel in)
{
url = ParcelUtils.readString(in);
artist = ParcelUtils.readString(in);
title = ParcelUtils.readString(in);
duration = ParcelUtils.readString(in);
info_url = ParcelUtils.readString(in);
lyrics = ParcelUtils.readString(in);
}
public String getUrl()
{
return url;
}
public String getArtist()
{
return artist;
}
public String getTitle()
{
return title;
}
public String getDuration()
{
return duration;
}
public String getLyrics()
{
return lyrics;
}
public String getInfo()
{
return info_url;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
ParcelUtils.writeString(dest, url);
ParcelUtils.writeString(dest, artist);
ParcelUtils.writeString(dest, title);
ParcelUtils.writeString(dest, duration);
ParcelUtils.writeString(dest, lyrics);
ParcelUtils.writeString(dest, info_url);
}
public static final Parcelable.Creator<Music> CREATOR =
new Parcelable.Creator<Music>() {
public Music createFromParcel(Parcel in)
{
return new Music(in);
}
public Music[] newArray(int size)
{
return new Music[size];
}
};
}
Когда я запускаю этот код, возникает проблема с исключением java.lang.NullPointerException в методе Fragment onCreateView () . Я был бы очень признателен, если бы кто-нибудь указал мне правильное направление, чтобы увидеть, где я терплю неудачу.
РЕДАКТИРОВАТЬ : Проблема решена: мне просто нужно было добавить эту строку в метод фрагмента Activity onCreate () (в противном случае getArguments () вернет null):
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, frag).commit();
И добавьте это в код фрагмента:
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
Bundle bundle = getArguments();
if(bundle != null)
{
listMusics = bundle.getParcelableArrayList("arrayMusic");
listMusic.setAdapter(new MusicBaseAdapter(getActivity(), listMusics));
}
}
где listMusics это ArrayList
из Parcelable
музыки.
источник
Ответы:
Две вещи. Во-первых, я не думаю, что вы правильно добавляете данные, которые хотите передать фрагменту. Что вам нужно передать фрагменту, так это связку, а не намерение. Например, если бы я хотел отправить
int
значение фрагменту, я бы создал пакет, поместил егоint
в этот пакет, а затем установил этот пакет в качестве аргумента, который будет использоваться при создании фрагмента.Bundle bundle = new Bundle(); bundle.putInt(key, value); fragment.setArguments(bundle);
Во-вторых, чтобы получить эту информацию, вам нужно получить аргументы, отправленные фрагменту. Затем вы извлекаете значение на основе ключа, которым вы его идентифицировали. Например в вашем фрагменте:
Bundle bundle = this.getArguments(); if (bundle != null) { int i = bundle.getInt(key, defaulValue); }
То, что вы получаете, меняется в зависимости от того, что вы ставите. Также обычно используется значение по умолчанию,
null
но не обязательно. Это зависит от того, устанавливаете ли вы значение по умолчанию для этого аргумента.Наконец, я не думаю, что вы можете сделать это в
onCreateView
. Я думаю, вы должны получить эти данные вonActivityCreated
методе вашего фрагмента . Я рассуждаю следующим образом.onActivityCreated
запускается после того, как базовая операция завершила свой собственныйonCreate
метод. Если вы размещаете информацию, которую хотите получить, в пакете во время вашегоonCreate
метода действия, она не будет существовать во время вашего фрагментаonCreateView
. Попробуйте использовать этоonActivityCreated
и просто обновите своеListView
содержимое позже.источник
Parcelable
интерфейс.Bundle
поддерживает добавление / получение,Parcelable
так что вы также можете отправить их без проблем.Я предпочитаю
Serializable
не использовать шаблонный код. Для передачи данных другим фрагментам или действиям разница в скоростиParcelable
не имеет значения.Я также всегда предоставляю вспомогательный метод для
Fragment
илиActivity
, таким образом, вы всегда знаете, какие данные должны быть переданы. Вот пример для вашегоListMusicFragment
:private static final String EXTRA_MUSIC_LIST = "music_list"; public static ListMusicFragment createInstance(List<Music> music) { ListMusicFragment fragment = new ListMusicFragment(); Bundle bundle = new Bundle(); bundle.putSerializable(EXTRA_MUSIC_LIST, music); fragment.setArguments(bundle); return fragment; } @Override public View onCreateView(...) { ... Bundle bundle = intent.getArguments(); List<Music> musicList = (List<Music>)bundle.getSerializable(EXTRA_MUSIC_LIST); ... }
источник
Я предпочел связку по простой причине, потому что в памяти нет повторяющихся данных. Он состоит из публичного метода init для фрагмента
private ArrayList<Music> listMusics = new ArrayList<Music>(); private ListView listMusic; public static ListMusicFragment createInstance(List<Music> music) { ListMusicFragment fragment = new ListMusicFragment(); fragment.init(music); return fragment; } public void init(List<Music> music){ this.listMusic = music; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.musiclistview, container, false); listMusic = (ListView) view.findViewById(R.id.musicListView); listMusic.setAdapter(new MusicBaseAdapter(getActivity(), listMusics)); return view; } }
В двух словах, вы создаете экземпляр фрагмента с помощью метода init (вы можете вызывать его как хотите), вы передаете ссылку на свой список, не создавая копию путем сериализации экземпляру фрагмента. Это очень полезно, потому что если вы измените что-то в списке, вы получите это в других частях приложения и, конечно, вы используете меньше памяти.
источник
newInstance
иsetArguments
как рекомендовано.отличный ответ @Rarw. Попробуйте использовать пакет для передачи информации от одного фрагмента к другому
источник