Soy nuevo en la programación de Android y tengo problemas al pasar una ArrayList de un Parcelable a un fragmento. Esta es la actividad que se lanza (¡funcionando bien!) Donde feedlist es un ArrayList de una música parcelable .
Intent in = new Intent(context, ListMusicsActivity.class);
in.putExtra("arrayMusic", feedList);
activity.startActivity(in);
El método del fragmento 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());
}
}
El código del fragmento:
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;
}
}
Creo que el problema esta en la linea
listMusics = (ArrayList<Music>) getArguments().getSerializable("arrayMusic");
Finalmente esta es mi clase de Música:
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];
}
};
}
Cuando ejecuto este código, el problema que obtengo es una excepción java.lang.NullPointerException en el método Fragment onCreateView () . Apreciaría mucho si alguien me indicara la dirección correcta para ver dónde estoy fallando.
EDITAR : Problema resuelto: solo necesitaba agregar esta línea al método del fragmento Activity onCreate () (de lo contrario, getArguments () devolvería nulo):
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, frag).commit();
Y agregue esto al código del fragmento:
@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));
}
}
donde, listMusics es una ArrayList
de Parcelable
Music.
fuente
Respuestas:
Dos cosas. Primero, no creo que esté agregando los datos que desea pasar al fragmento correctamente. Lo que necesita para pasar al fragmento es un paquete, no una intención. Por ejemplo, si quisiera enviar un
int
valor a un fragmento, crearía un paquete, pondría elint
en ese paquete y luego establecería ese paquete como un argumento para usar cuando se creó el fragmento.Bundle bundle = new Bundle(); bundle.putInt(key, value); fragment.setArguments(bundle);
En segundo lugar, para recuperar esa información, necesita obtener los argumentos enviados al fragmento. Luego extrae el valor en función de la clave con la que lo identificó. Por ejemplo en tu fragmento:
Bundle bundle = this.getArguments(); if (bundle != null) { int i = bundle.getInt(key, defaulValue); }
Lo que estás obteniendo cambia dependiendo de lo que pones. Además, el valor predeterminado suele ser,
null
pero no es necesario. Depende de si establece un valor predeterminado para ese argumento.Por último, no creo que puedas hacer esto en
onCreateView
. Creo que debes recuperar estos datos dentro delonActivityCreated
método de tu fragmento . Mi razonamiento es el siguiente.onActivityCreated
se ejecuta después de que la actividad subyacente haya finalizado su propioonCreate
método. Si está colocando la información que desea recuperar dentro del paquete durante elonCreate
método de su actividad , no existirá durante su fragmentoonCreateView
. Intente usar estoonActivityCreated
y actualice suListView
contenido más tarde.fuente
Parcelable
interfaz.Bundle
admite agregar / obtenerParcelable
para que pueda enviarlos sin problema.Prefiero
Serializable
= sin código repetitivo. Para pasar datos a otros Fragmentos o Actividades, la diferencia de velocidad con aParcelable
no importa.También siempre proporcionaría un método auxiliar para un
Fragment
oActivity
, de esta manera, siempre sabrá qué datos se deben pasar. Aquí un ejemplo para suListMusicFragment
: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); ... }
fuente
Hay una razón simple por la que preferí el paquete debido a que no hay datos duplicados en la memoria. Consiste en un método público de inicio para el fragmento
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; } }
En dos palabras, creas una instancia del fragmento y mediante el método init (puedes llamarlo como quieras) pasas la referencia de tu lista sin crear una copia por serialización a la instancia del fragmento. Esto es muy útil porque si cambia algo en la lista, lo obtendrá en las otras partes de la aplicación y, por supuesto, usa menos memoria.
fuente
newInstance
ysetArguments
según lo recomendado.gran respuesta de @Rarw. Intente usar un paquete para pasar información de un fragmento a otro
fuente