I opening Fragment B from Fragment A with startActivityForResult when Fragment B closes I get String value from EditText to Fragment A and everything works fine but now I opening same Fragment B from Fragment A and I want it to have that earlier returned value but it disappears
here I'm storing purposeText value from editText but not saving to json yet I want it to be saved on exiting Fragment A
public class Cloud {
private static final String JSON_ID = "id";
private static final String JSON_PURPOSE = "purpose";
private UUID mId;
private String purposeText = "";
public Cloud() {
mId = UUID.randomUUID();
}
public Cloud(JSONObject json) throws JSONException {
mId = UUID.fromString(json.getString(JSON_ID));
if (json.has(JSON_PURPOSE)){
purposeText = json.getString(JSON_PURPOSE);
}
}
public JSONObject toJSON() throws JSONException{
JSONObject json = new JSONObject();
json.put(JSON_ID, mId.toString());
json.put(JSON_PURPOSE, purposeText);
return json;
}
#Override
//Using get and set methods to get it in private String
public String getPurposeText(){return purposeText;}
public void setPurposeText(String purpose){purposeText = purpose;}
public UUID getId() {return mId;};
}
In Fragment A I'm getting text and setting it to textview and it works, then setting it back to setter in Cloud class
public class AddFragment extends Fragment {
private static final String TAG = "Cload";
public static final String EXTRA_DREAM_ID = "com.example.tadas.dreamcload1.dream_id";
private static final int REQUEST_DATE = 0;
private static final int REQUEST_TEXT =1;
private Cloud dCloud;
private TextView purposeView;
private String comeBackPurpose;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
dCloud = new Cloud();
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getActivity().setTitle("Add new dream");
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup parent, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.fragment_add,parent,false);
purposeView = (TextView)v.findViewById(R.id.dream_purpose);
purposeView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getActivity(),DreamPurposeActivity.class);
startActivityForResult(i,REQUEST_TEXT);
}
});
return v;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_TEXT){
comeBackPurpose = data.getStringExtra("comeBackPurpose");
// Log.e(TAG,"SHITFACE " + comeBackPurpose);
purposeView.setText(comeBackPurpose);
dCloud.setPurposeText(comeBackPurpose);
Log.e(TAG,"SHITFACE " + dCloud.getPurposeText());
}
}
public static AddFragment newInstance(UUID dreamId) {
Bundle args = new Bundle();
args.putSerializable(EXTRA_DREAM_ID, dreamId);
AddFragment fragment = new AddFragment();
fragment.setArguments(args);
return fragment;
}
}
Now In Fragment B I'm trying to set that text back to EditText in onCreateView method but it gets default value, what should I do to fix that?
public class PurposeFragment extends Fragment {
public static final String EXTRA_D = "com.dropstudio.drea.dr_ids";
private static final String TAG = "Cload";
private EditText purposeEText;
private String purposeEditText;
private Cloud mCloud;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCloud = new Cloud();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dream_purpose_edit,container,false);
purposeEText = (EditText)v.findViewById(R.id.purpose_edit);
purposeEText.setText(mCloud.getPurposeText());
return v;
}
public void savePurpose(){
purposeEditText = purposeEText.getText().toString();
mCloud.setPurposeText(purposeEditText);
Intent returnIntent = new Intent();
returnIntent.putExtra("comeBackPurpose",purposeEditText);
getActivity().setResult(Activity.RESULT_OK,returnIntent);
getActivity().finish();
}
public static PurposeFragment newInstance(UUID dreaIds) {
Bundle args = new Bundle();
args.putSerializable(EXTRA_D, dreaIds);
PurposeFragment fragment = new PurposeFragment();
fragment.setArguments(args);
return fragment;
}
}
In Fragment B , you are creating a new Cloud object in onCreate() and trying to get the value from that object in onCreateView() which will always be null.
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCloud = new Cloud(); //New instance will be created
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dream_purpose_edit,container,false);
purposeEText = (EditText)v.findViewById(R.id.purpose_edit);
purposeEText.setText(mCloud.getPurposeText()); // 'mCloud' is a new object everytime and hence will not have your saved value
return v;
}
For your task, either use SharedPreferences or pass the saved value while instantiating Fragment B.
Related
I'm doing my final project that due tomorrow and I only have one thing left to do. But I already lost a lot of time on it. I am creating a recyclerview from a JSON that I obtain through Volley from the Adafruit API and everything is fine, the only thing i need is that when I clicking on the items different Intents are opened. I would greatly appreciate if someone could help me. I have to say that I am working on a fragment and there things are a little different.
The code of my Adapter:
public class AdafruitFeedAdapter extends RecyclerView.Adapter<AdafruitFeedAdapter.viewholder> {
ArrayList<FeedData> feedData;
public AdafruitFeedAdapter(ArrayList<FeedData> feedData) {
this.feedData = feedData;
}
#NonNull
#Override
public viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_feed, parent, false);
return new viewholder(v);
}
#Override
public void onBindViewHolder(#NonNull viewholder holder, int position) {
holder.setData(feedData.get(position));
}
#Override
public int getItemCount() {
return feedData.size();
}
public class viewholder extends RecyclerView.ViewHolder implements View.OnClickListener {
Button btnMisFeeds;
FeedData dataHolder;
public viewholder(#NonNull View itemView) {
super(itemView);
btnMisFeeds = itemView.findViewById(R.id.btnMisFeeds);
btnMisFeeds.setOnClickListener(this);
}
public void setData(FeedData feedData) {
dataHolder = feedData;
btnMisFeeds.setText(dataHolder.getName());
}
#Override
public void onClick(View v) {
}
}
The code of my fragment:
public class FragmentInicio extends Fragment {
Button btnControlar, btnAddFeed;
View view;
String temperatura, distancia, infrarrojo, polvo;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private static final String USER_PREFERENCES = "userPreferences";
private static final String TOKEN_KEY = "token";
private RequestQueue nQueue;
ArrayList<AdafruitFeed> adF;
AdafruitFeedAdapter adapterFeed;
RecyclerView recyclerView;
SharedPreferences userPreferences;
SharedPreferences.Editor userEditor;
String token;
public FragmentInicio() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment FragmentInicio.
*/
// TODO: Rename and change types and number of parameters
public static FragmentInicio newInstance(String param1, String param2) {
FragmentInicio fragment = new FragmentInicio();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_inicio, container, false);
btnControlar = view.findViewById(R.id.btnControlar);
btnAddFeed = view.findViewById(R.id.btnAddFeed);
btnControlar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(v.getContext(), ControlActivity.class));
}
});
btnAddFeed.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(v.getContext(), AgregarFeedActivity.class));
}
});
nQueue = SingletonRequest.getInstance(view.getContext()).getRequestQueue();
adF = new ArrayList<>();
userPreferences = view.getContext().getSharedPreferences(USER_PREFERENCES, Context.MODE_PRIVATE);
userEditor = userPreferences.edit();
token = userPreferences.getString(TOKEN_KEY, null);
getFeeds();
return view;
}
public void getFeeds() {
String url = "https://cleanbotapi.live/api/v1/feeds";
final JsonObjectRequest getFeeds = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerFeed);
recyclerView.setHasFixedSize(true);
LinearLayoutManager linearManager = new LinearLayoutManager(view.getContext());
recyclerView.setLayoutManager(linearManager);
final Gson gson = new Gson();
final AdafruitFeed adafruitFeed = gson.fromJson(response.toString(), AdafruitFeed.class);
adapterFeed = new AdafruitFeedAdapter(adafruitFeed.getListFeedData());
temperatura = adafruitFeed.getListFeedData().get(0).getName();
distancia = adafruitFeed.getListFeedData().get(1).getName();
infrarrojo = adafruitFeed.getListFeedData().get(2).getName();
polvo = adafruitFeed.getListFeedData().get(3).getName();
recyclerView.setAdapter(adapterFeed);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("errorPeticion", error.toString());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Authorization", "Bearer " + token);
return headers;
}
};
nQueue.add(getFeeds);
}
}
I trying to create an OnClickListener for everyone of my Adafruit feeds but i cant.
First of all the naming convention of a class should be in "PascalCase".
You need to define an interface that contains a method for your listener and pass it to the constructor of the adapter. And then also pass this listener to your ViewHolder by constructor.
Example:
public class AdafruitFeedAdapter extends RecyclerView.Adapter<AdafruitFeedAdapter.viewholder> {
public interface OnClickListener {
void onClick(FeedData data, int position);
}
ArrayList<FeedData> feedData;
OnClickListener clickListener;
public AdafruitFeedAdapter(ArrayList<FeedData> feedData,OnClickListener clickListener) {
this.feedData = feedData;
this.clickListener = clickListener;
}
...
#NonNull
#Override
public viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_feed, parent, false);
return new viewholder(v,clickListener);
}
}
And in your viewholder modify it like below:
...
OnClickListener clickListener;
public viewholder(#NonNull View itemView,OnClickListener clickListener) {
super(itemView);
this.clickListener = clickListener;
btnMisFeeds = itemView.findViewById(R.id.btnMisFeeds);
btnMisFeeds.setOnClickListener(this);
}
...
#Override
public void onClick(View v) {
clickListener.onClick(dataHolder,getBindingAdapterPosition());
}
...
And your fragment:
public class FragmentInicio extends Fragment implements AdafruitFeedAdapter.OnClickListener {
...
#override
public void onClick(FeedData data, int position){
// TODO: implement your intent action
}
...
}
And your adapter: adapterFeed = new AdafruitFeedAdapter(adafruitFeed.getListFeedData(),FragmentInicio.this);
i'm trying to add a custom layout to my settings app for personalization options with a clickable header image that launches a web url but the main preference layout is already set by my settings activiy, how can i remove the parent view so my custom layout can be inflated?
public class DEMENTED extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener {
private static final String TAG = "DEMENTED";
private static final String KEY_DEMENTED_GITHUB = "https://github.com/cphelps76";
private static final String KEY_DEMENTED_HEADER = "logo";
private static final String KEY_GESTURE_SETTINGS = "prefs_gesture";
Preference mlogo;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.demented_interface, container);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.demented_interface_settings);
mlogo = findPreference(KEY_DEMENTED_HEADER);
Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(getActivity(),
getPreferenceScreen(), KEY_GESTURE_SETTINGS);
}
#Override
protected int getMetricsCategory() {
return MetricsLogger.DEMENTED_INTERFACE;
}
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mlogo) {
launchUrl(KEY_DEMENTED_GITHUB);
return true;
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
public boolean onPreferenceChange(Preference preference, Object objValue) {
final String key = preference.getKey();
return true;
}
private void launchUrl(String url) {
Uri uriUrl = Uri.parse(url);
Intent whatever = new Intent(Intent.ACTION_VIEW, uriUrl);
getActivity().startActivity(whatever);
}
}
I solved my own problem by inflating my bas preference view in OnCreateView and finding the imageview id and then making my image clickable and setting an onclick listener
public class DEMENTED extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener, View.OnClickListener {
private static final String TAG = "DEMENTED";
private static final String KEY_DEMENTED_GITHUB = "https://github.com/cphelps76";
private static final String KEY_GESTURE_SETTINGS = "prefs_gesture";
private static final String KEY_HARDWARE_KEYS = "prefs_buttons";
private ImageView mLogoView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.demented_interface_settings);
removePreferences();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.preference_list_fragment, parent, false);
mLogoView = (ImageView)rootView.findViewById(R.id.logo);
updateView();
return rootView;
}
private boolean hasButtons() {
return getResources().getInteger(
com.android.internal.R.integer.config_deviceHardwareKeys) != 0;
}
private void removePreference(Preference preference) {
getPreferenceScreen().removePreference(preference);
}
private void removePreferences() {
Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(getActivity(),
getPreferenceScreen(), KEY_GESTURE_SETTINGS);
if (!hasButtons()) {
removePreference(KEY_HARDWARE_KEYS);
}
}
private void updateView() {
if (mLogoView != null) {
mLogoView.setClickable(true);
mLogoView.setOnClickListener(this);
}
}
#Override
public void onClick(View v) {
if (v == mLogoView) {
v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
launchUrl(KEY_DEMENTED_GITHUB);
}
}
#Override
protected int getMetricsCategory() {
return MetricsLogger.DEMENTED_INTERFACE;
}
public boolean onPreferenceChange(Preference preference, Object objValue) {
final String key = preference.getKey();
return true;
}
private void launchUrl(String url) {
Uri uriUrl = Uri.parse(url);
Intent demented = new Intent(Intent.ACTION_VIEW, uriUrl);
getActivity().startActivity(demented);
}
}
I made this code for an app it suppose to give a list of body part like arm and legs and one you click on one in the first fragment a list of exercise should appear in the second fragment this list is suppose to change if the user press another option and is there were I have the problem it displays the first option automatic but it not change after the user press another option please how can I change the content in the second fragment.
Main class
public class MainActivity extends Activity
implements WorkoutListFragment.WorkoutListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WorkoutDetailFragment frag = (WorkoutDetailFragment)
getFragmentManager().findFragmentById(R.id.detail_frag);
frag.setWorkoutId(1);
}
public void itemClicked(long id){
int itemSelected = (int)id;
String message = String.format("ID selected %d", itemSelected);
Log.v("DEBUG", message);
}
}
Second class
public class Workout {
private String name;
private String description;
public Workout(String name, String description) {
this.name = name;
this.description = description;
}
public static final Workout[] workouts= {
new Workout("Chest Workout", "3 Bench Press\n10Flys\nWide Dips"),
new Workout("Legs", "5 Squats\n3x12 Leg Curl\n3x10 Leg Press"),
new Workout("Back", "10 Pullups\n 3x8 Dumbell Rows"),
new Workout("Arms", "10 Biceps Curls\n10 Dips\n3x10 Preacher Curls")
};
public String getName() {
return name;
}
public String getDescription() {
return description;
}
#Override
public String toString() {
return this.name;
}
}
Third class
public class WorkoutDetailFragment extends Fragment {
private final String TAG = "DEBUG";
private long workoutId;
public WorkoutDetailFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_workout_detail, container, false);
}
#Override
public void onStart(){
super.onStart();
View view = getView();
if(view !=null){
TextView title = (TextView)view.findViewById(R.id.TextTitle);
Workout workout = Workout.workouts[(int)workoutId];
title.setText(workout.getName());
Log.v(TAG, workout.getName());
TextView description = (TextView)view.findViewById(R.id.TextDescription);
description.setText(workout.getDescription());
Log.v(TAG, workout.getDescription());
}
}
public void setWorkoutId(long id){
this.workoutId = id;
}
}
Fourth class
public class WorkoutListFragment extends ListFragment {
static interface WorkoutListener {
void itemClicked(long id);
}
private WorkoutListener listener;
public WorkoutListFragment() {
// Required empty public constructor
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
this.listener = (WorkoutListener)activity;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id){
if (listener != null){
listener.itemClicked(id);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// create a string array with workout names
String[] names = new String [Workout.workouts.length];
for (int i=0; i < names.length; i++){
names[i] = Workout.workouts[i].getName();
}
// Create an array adapter
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
inflater.getContext(),
android.R.layout.simple_list_item_1,
names);
// bind the adapter to the control
setListAdapter(adapter);
// this call gives you the default layout view for the
// ListFragment
return super.onCreateView(inflater, container, savedInstanceState);
}
}
Inside an onClickListener or whatever listens for clicks you should write this in your activity:
FragmentManager fragementManager = getFragmentManager();
fragementManager.beginTransaction().replace(R.id.layout, new NextFragment()).commit();
In this example R.id.layout should be the id of your layout in where your fragment is placed. NextFragment should be the class of the fragment you want to display.
Hope this helps! :)
I have MainActivity which has FragmentTabHost with several tabs. Each fragment in tab can be replaced with another fragment, so if we navigate back, we will see first displayed fragment for this tab (own stack for each tab). I have a quite working solution.
The below example demonstrates TabHost with 2 tabs and fragment classes for the first tab.
Is there any simpler, better or more elegant way to achieve this result?
AbstractPrimaryFragment.java. This class is a root fragment class that replaces fragments inside it. Other tab fragment classes can extend this superclass.
public abstract class AbstractPrimaryFragment extends Fragment {
// Simple framelayout.
private static final int RES_ID = R.layout.primary_fragment_layout;
protected static final int CONTENT_LAYOUT_ID = R.id.primary_fragment_layout;
protected Fragment mActiveFragment;
public AbstractPrimaryFragment()
{
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(RES_ID, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
// Check if active fragment is in layout, if not, make default fragment for this tab.
mActiveFragment = getChildFragmentManager().findFragmentById(CONTENT_LAYOUT_ID);
if (mActiveFragment == null)
{
mActiveFragment = makeDefaultActiveFragment();
String tag = getDefaultFragmentTag();
getChildFragmentManager().beginTransaction().add(CONTENT_LAYOUT_ID, mActiveFragment, tag).commit();
}
}
public boolean onBackPressed()
{
boolean backPressed = false;
final FragmentManager fragmentManager = getChildFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0)
{
fragmentManager.addOnBackStackChangedListener(new OnBackStackChangedListener()
{
#Override
public void onBackStackChanged()
{
mActiveFragment = fragmentManager.findFragmentById(CONTENT_LAYOUT_ID);
fragmentManager.removeOnBackStackChangedListener(this);
}
});
fragmentManager.popBackStack();
backPressed = true;
}
return backPressed;
}
protected abstract Fragment makeDefaultActiveFragment();
protected abstract String getDefaultFragmentTag(); }
Tab1PrimaryFragment.java
public class Tab1PrimaryFragment extends AbstractPrimaryFragment implements OnTab1Fragment1Listener {
private static final String FRAGMENT1_TAG = "tab1_fragment1";
private static final String FRAGMENT2_TAG = "tab2_fragment2";
#Override
protected Fragment makeDefaultActiveFragment()
{
return new Tab1Fragment1();
}
#Override
protected String getDefaultFragmentTag()
{
return FRAGMENT1_TAG;
}
#Override
public void onTab1Fragment1ButtonClick(Tab1Fragment1 tab1Fragment1)
{
Tab1Fragment2 tab1Fragment2 = new Tab1Fragment2();
getChildFragmentManager().beginTransaction().replace(CONTENT_LAYOUT_ID, tab1Fragment2, FRAGMENT2_TAG).addToBackStack(tab1Fragment1.getTag()).commit();
mActiveFragment = tab1Fragment2;
}}
Tab1Fragment1.class (default active fragment)
public class Tab1Fragment1 extends Fragment {
public interface OnTab1Fragment1Listener
{
public void onTab1Fragment1ButtonClick(Tab1Fragment1 tab1Fragment1);
}
private OnTab1Fragment1Listener mOnTab1Fragment1Listener;
public void setOnTab1Fragment1Listener(OnTab1Fragment1Listener onTab1Fragment1Listener)
{
mOnTab1Fragment1Listener = onTab1Fragment1Listener;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Fragment parentFragment = getParentFragment();
if (parentFragment != null && parentFragment instanceof OnTab1Fragment1Listener)
{
mOnTab1Fragment1Listener = (OnTab1Fragment1Listener) parentFragment;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
Button button = new Button(getActivity());
button.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if(mOnTab1Fragment1Listener != null)
{
mOnTab1Fragment1Listener.onTab1Fragment1ButtonClick(Tab1Fragment1.this);
}
}
});
return button; }}
Tab1Fragment2.java. Dummy fragment. This fragment is displayed when onTab1Fragment1ButtonClick is called.
public class Tab1Fragment2 extends Fragment {}
And MainActivity.java
public class MainActivity extends FragmentActivity {
private static final int RES_ID = R.layout.main_activity;
private static final int TAB_CONTENT_ID = android.R.id.tabcontent;
private static final int TABHOST_ID = android.R.id.tabhost;
private static final String TAB1_PRIMARY_FRAGMENT_TAG = "tab1_primary_fragment";
private static final String TAB2_PRIMARY_FRAGMENT_TAG = "tab2_primary_fragment"
private FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle bundle)
{
super.onCreate(bundle);
setContentView(RES_ID);
initializeTabHost();
}
private void initializeTabHost()
{
mTabHost = (FragmentTabHost) findViewById(TABHOST_ID);
mTabHost.setup(this, getSupportFragmentManager(), TAB_CONTENT_ID);
LayoutInflater inflater = LayoutInflater.from(this);
mTabHost.addTab(mTabHost.newTabSpec(TAB1_PRIMARY_FRAGMENT_TAG).setIndicator(inflater.inflate(R.layout.smth1, null)), Tab1PrimaryFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec(TAB2_PRIMARY_FRAGMENT_TAG).setIndicator(inflater.inflate(R.layout.smth2, null)), Tab2PrimaryFragment.class, null);
}
#Override
public void onBackPressed()
{
Fragment fragment = getSupportFragmentManager().findFragmentById(TAB_CONTENT_ID);
if (fragment != null && fragment instanceof AbstractPrimaryFragment)
{
if (((AbstractPrimaryFragment) fragment).onBackPressed())
{
return;
}
}
super.onBackPressed();
}}
I'm new to Android programming and I'm having problems while passing an ArrayList of a Parcelable to a fragment.
This is the Activity that is launched(working well!) where feedlist is an ArrayList of a parcelable Music.
Intent in = new Intent(context, ListMusicsActivity.class);
in.putExtra("arrayMusic", feedList);
activity.startActivity(in);
The fragment Activity onCreate() method:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activitymusiclist);
if(savedInstanceState != null)
{
ListMusicFragment frag = new ListMusicFragment();
frag.setArguments(getIntent().getExtras());
}
}
The Fragment code:
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;
}
}
I think the problem is in the line
listMusics = (ArrayList<Music>) getArguments().getSerializable("arrayMusic");
Finally this is my Music class:
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];
}
};
}
When I run this code the problem I get is a java.lang.NullPointerException in the Fragment onCreateView() method.
I would appreciate a lot if someone pointed me in the right direction to see where I am failing.
EDIT: Problem solved: I just needed to add this line to the fragment Activity onCreate() method(othwewise the getArguments() would return null):
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, frag).commit();
And add this to the fragment code:
#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));
}
}
where, listMusics is an ArrayList of Parcelable Music.
Two things. First I don't think you are adding the data that you want to pass to the fragment correctly. What you need to pass to the fragment is a bundle, not an intent. For example if I wanted send an int value to a fragment I would create a bundle, put the int into that bundle, and then set that bundle as an argument to be used when the fragment was created.
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
Second to retrieve that information you need to get the arguments sent to the fragment. You then extract the value based on the key you identified it with. For example in your fragment:
Bundle bundle = this.getArguments();
if (bundle != null) {
int i = bundle.getInt(key, defaulValue);
}
What you are getting changes depending on what you put. Also the default value is usually null but does not need to be. It depends on if you set a default value for that argument.
Lastly I do not think you can do this in onCreateView. I think you must retrieve this data within your fragment's onActivityCreated method. My reasoning is as follows. onActivityCreated runs after the underlying activity has finished its own onCreate method. If you are placing the information you wish to retrieve within the bundle durring your activity's onCreate method, it will not exist during your fragment's onCreateView. Try using this in onActivityCreated and just update your ListView contents later.
I prefer Serializable = no boilerplate code. For passing data to other Fragments or Activities the speed difference to a Parcelable does not matter.
I would also always provide a helper method for a Fragment or Activity, this way you always know, what data has to be passed. Here an example for your 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);
...
}
There is a simple why that I prefered to the bundle due to the no duplicate data in memory. It consists of a init public method for the fragment
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;
}
}
In two words, you create an instance of the fragment an by the init method (u can call it as u want) you pass the reference of your list without create a copy by serialization to the instance of the fragment. This is very usefull because if you change something in the list u will get it in the other parts of the app and ofcourse, you use less memory.