Trouble refreshing android array adapter in fragment - android

I'm having trouble refreshing an array adapter. When I'm testing the program on a phone it works well and refreshes perfectly when switching through fragments. The problem comes when I'm using a tablet and both fragments are up at once.
Here's my fragment code:
public class HistoryFragment extends Fragment {
private ArrayList<String> history = new ArrayList<String>();
private ArrayAdapter<String> arrayAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle data = getArguments();
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.history, container, false);
ListView view = (ListView) v.findViewById(R.id.list);
if(data != null){
history = data.getStringArrayList("history");
}
arrayAdapter = new ArrayAdapter<String>(
getActivity(),
android.R.layout.simple_list_item_1, history);
view.setAdapter(arrayAdapter);
return v;
}
public void setHistory(ArrayList<String> history) {
history.addAll(history);
arrayAdapter.notifyDataSetChanged();
}
}
Here's my activity code:
public class MainActivity extends Activity implements historyClickListener{
public static ArrayList<String> history = new ArrayList<String>();
CalcFragment mCalcFragment = new CalcFragment();
HistoryFragment mHistFragment = new HistoryFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.container) != null) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, mCalcFragment);
fragmentTransaction.commit();
}
}
#Override
public void sendHistory(ArrayList<String> history){
Fragment hf = getFragmentManager().findFragmentById(R.id.historyfrag);
if(hf != null){
mHistFragment.setHistory(history);
}else{
Bundle data = new Bundle();
data.putStringArrayList("history", history);
mHistFragment.setArguments(data);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container, mHistFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
The sendHistory is an interface method in a calculator that help the calculator send the list of equations that have been done. Then in main activity if I'm using a tablet then all it does is setHistory which is a method in the history fragment. I believe the problem is that I'm not using arrayAdapter.notifyDataSetChanged() in the history fragment correctly. Can someone please help. Thanks!

You are setting the new data to a variable of the fragment not to the adapter who is the one who shows the data.
So you can:
Create a new ArrayAdapter with the new data and set it to the listview.
Extend ArrayAdapter, create a method that pass the new Data to the Adapter and then call notifyDataSetChanged().

this.history.addAll(history)? I see the same variable name for parameter and member variable.

Related

android - passing array between fragments is not working

On my fragment named locate_map I declared a string array and converted it as a String ArrayList. I would like that ArrayList be pass on my another fragment named locate_updatedstatus. I have a button on my locate_map fragment that has id to_update_status that would switch from locate_map to locate_updatedstatusat the same time would pass my ArrayList and display it as a listview on my locate_updatedstatus
There is no error upon bulding. However whenever I navigate to my locate_updatedstatus the app crashes.
Main activity. This is how I switch between fragments. I am using navigation drawer activity with container fragment
public void onSelectFragment(View v){
Fragment newFragment;
if(v == findViewById(R.id.to_update_status)){
newFragment = new locate_updatedstatus();
}
else{
newFragment = new locate_login();
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
locate_map fragment
public class locate_map extends Fragment implements Serializable{
public locate_map () {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_locate_map, container, false);
String[] updatedArr = {"display this", "also this"};
List<String> stringList = new ArrayList<String>(Arrays.asList(updatedArr));
Bundle bundle = new Bundle();
bundle.putSerializable("key", (Serializable) stringList);
return rootView;
}
}
locate_map xml button
<Button
android:id="#+id/to_update_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="#+id/check_images"
android:layout_marginTop="15dp"
android:text="Update Status"
android:width="340dp"
android:height="70dp"
android:onClick="onSelectFragment"
/>
locate_updatedstatus fragment
public class locate_updatedstatus extends Fragment implements Serializable {
public locate_updatedstatus() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_locate_updatedstatus, container, false);
ArrayList<String> stringList = (ArrayList<String>)getArguments().getSerializable("key");
ListView listSource = (ListView) rootView.findViewById(R.id.updates);
ArrayAdapter<String> listViewAdapter = new ArrayAdapter<String>(
getActivity(),
android.R.layout.simple_list_item_1,
stringList
);
listSource.setAdapter(listViewAdapter);
return rootView; // Inflate the layout for this fragment
}
}
locate_updatedstatus xml listview
<ListView
android:layout_width="match_parent"
android:layout_height="350dp"
android:layout_marginTop="60dp"
android:id="#+id/updates"
android:listSelector="#android:color/transparent"
/>
I would appreciate if the answers are in detail. I am beginner on android programming please bear with me.
logcat error
java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.Serializable android.os.Bundle.getSerializable(java.lang.String)' on a null object reference at com.example.makati.sidebar.locate_updatedstatus.onCreateView(locate_updatedstatus.java:31)
All you need is bundle.putStringArray
String[] updatedArr = {"display this", "also this"};
bundle.putStringArray(KEY, updatedArr)
and
bundle.getStringArray(KEY)
In your's code you are not adding Bundle as argument to Fragment
Please use link to fix class constructor
below lines code just creating the bundle and adding arraylist to it. But there is nothing specified where it will be get used.
List<String> stringList = new ArrayList<String>(Arrays.asList(updatedArr));
Bundle bundle = new Bundle();
bundle.putSerializable("key", (Serializable) stringList);
Solution : hoping the first locate_login and then locate_updatedstatus fragments will be created in sequence.
locate_login fragment : trying to put content activity intent
List<String> stringList = new ArrayList<String>(Arrays.asList(updatedArr));
Bundle bundle = new Bundle();
bundle.putSerializable("key", (Serializable) stringList);
getActivity().getIntent().putExtras("key",bundle);
locate_upadtestatus fragment : get data from the activity intent
ArrayList<String> stringList = (ArrayList<String>)getActivity().getIntent().getExtras("key");

Pass String Array from one fragment to another

I am Using one String [] to display in ListView of fragmentone and pass String[] to fragmentTwo which has listView. my tried Codes below,
MainActivity:
public class MainActivity extends FragmentActivity implements ListInterface {
private FragmentOne fragmentOne;
private FragmentTwo fragmentTwo;
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
fragmentOne = new FragmentOne ();
fragmentTwo = new FragmentTwo ();
FragmentManager fragmentManager = getSupportFragmentManager ();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction ();
fragmentTransaction.add (R.id.frame_one,fragmentOne);
fragmentTransaction.add (R.id.frame_two , fragmentTwo);
fragmentTransaction.commit ();
}
#Override
public void getValue (String[] s) {
fragmentTwo.setValue (s);
}}
FragmentOne:
public class FragmentOne extends Fragment {
private ListView listView;
private ListInterface listInterface;
String [] listData = {"Dhana","Rahul","Strobs","Uday","Selvi"};
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate (R.layout.fragment_one,container,false);
listView = (ListView)view.findViewById (R.id.lst_view);
ArrayAdapter adapter = new ArrayAdapter (getActivity (),R.layout.fragment_one,listData);
listView.setAdapter (adapter);
return view;
}
#Override
public void onAttach (Context context) {
super.onAttach (context);
if(context instanceof ListInterface){
listInterface =(ListInterface)context;
listInterface.getValue (listData);
}else{
throw new ClassCastException (context.toString ()+"mess ");
}
}}
FragmentTwo:
public class FragmentTwo extends Fragment {
private ListView listView;
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate (R.layout.fragment_two,container,false);
listView = (ListView)view.findViewById (R.id.lst_view_two);
return view;
}
public void setValue (String [] value){
ArrayAdapter adapter = new ArrayAdapter (getActivity (),R.layout.fragment_two,value);
listView.setAdapter (adapter);
}}
ListInterface:
public interface ListInterface {
public void getValue (String [] s);}
i tried my codes it show
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
FragmentTwo.setValue(FragmentTwo.java:27)
MainActivity.getValue(MainActivity.java:31)
FragmentOne.onAttach(FragmentOne.java:37)
You can set the data in this way.
public static BuyerToyFragment newInstance(String yourText) {
FragmentOne fragment = new FragmentOne ();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, yourText);
fragment.setArguments(args);
return fragment;
}
NOw in fragmentOne you need to get data like this.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
String myStringData = getArguments().getString(ARG_PARAM1);
}
}
and in your MainActivity you can set data like this.
// you can add string array as well. i dont remember the tag exactely. i its
//like putStingArray() but you need to check it yourself
fragmentOne = new FragmentOne ().newInstance("Your data goes here");
you need to do the same for fragment 2
I don't really understand the role of your list interface.
I don't really understand neither why you make your setValue and getValue call statically...
1/The easiest way is to store your list in your activity and then access it from the fragment, for exemple in onViewCreated.
Activity:
public String[] getMyList() {
return mMyList;
}
You will also need to do the setter to set the list from another fragment.
Access your list from the fragment:
String[] listFromActivity = ((MainActivity) getActivity()).getMyList();
2/A cleaner way could be to pass your list as an argument to your fragment.
In activity :
FragmentOne frO = new FragmentOne();
Bundle bundle = new Bundle();
bundle.putStringArray(mMyList, "my_list_key");
frO.setArguments(bundle);
In fragment :
String[] listFromActivity = getArguments().getStringArray("my_list_key");
The solution 1 is more easy if you want to update your list, if your list won't change the solution 2 is cleaner.

Application crashes when starting a new fragment

I'm new to Android dev, and my app crashes when I try to create a new fragment upon clicking my button that has an "onClick" that is called "EnterNameOnClick()"
I suspect that the following code from MainActivity might be the problem...
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void EnterNameOnClick(){
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
EnterName_Fragment enterName_fragment = new EnterName_Fragment();
fragmentTransaction.add(android.R.id.content, enterName_fragment);
fragmentTransaction.commit();
}
}
public class EnterName_Fragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.new_user_fragment, container, false);
Spinner spinner = (Spinner) view.findViewById(R.id.movie_spinner);
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getActivity(), R.array.planets_array, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);
return view;
}
}
When I am writing the fragmentTransaction.add(android.R.id.content, enterName_fragment), I wonder if the "android.R.id.content" is erroneous? What am I supposed to fill this field with?
Maybe this is caused because using android:onclick in xml. Try onClick in Java using onClickListener
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void EnterNameOnClick(View v) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
EnterName_Fragment enterName_fragment = new EnterName_Fragment();
fragmentTransaction.add(android.R.id.content, enterName_fragment);
fragmentTransaction.commit();
}
});
Posting your logcat would help us to provide better solution. Try it and let me know.

Android, empty listview afrer back from other fragment

Hy, i've got list view in my fragment. I am replacing this listview fragment with my other fragment but when i want back to my list, it's empty. I thought i could restore my list items but i don't know how. I Assumed that accord with Fragment lifecycle my adapter will be reusable but looks it's not. Here is my code:
public class ThreadListFragment extends Fragment implements FragmentConnectionStatus, ListFragment, OnClickListener, OnItemClickListener{
private ListView ListView;
private PilotController Activity;
private Button ButtonStartNewThread;
private boolean Paused;
private ThreadInfoAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
/**
* Inflate the layout for this fragment
*/
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.threads_list_fragment, container, false);
System.out.println(this.Paused);
if(this.Paused == false){
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
this.ListView.setAdapter(adapter);
this.ListView.setItemsCanFocus(true);
this.ListView.setOnItemClickListener(this);
this.Activity = (PilotController) getActivity();
this.ButtonStartNewThread = (Button) view.findViewById(R.id.buttonStartThread);
this.ButtonStartNewThread.setOnClickListener(this);
return view;
}
#Override
public void onPause()
{
super.onPause();
this.Paused = true;
}
but when i return to my old list, it's empty. Could you give me some advice?
SOLUTION
I found a solution. ListView is probably removing from 'draw stack' so when calling OnDeleteView your old list is unusable next time although reference to this object is still set. The solution is to recreate ListView and set old adapter. This adapter due to this tutorial http://developer.android.com/guide/components/fragments.html will survive but view is recreated (so old listview doesn't exist anymore (it exist but it's not drawable). I had to change this lines:
if(this.Paused == false){
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
to:
this.ListView = (ListView) view.findViewById(R.id.listViewActiveThreads);
if(this.Paused == false){
ArrayList<Guid> strs = new ArrayList<Guid>();
adapter = new ThreadInfoAdapter(view.getContext(), strs, this);
}
In "onActivityCreated" you can just check if your dataList (in your case "strs) is empty. If it is not then just use it, otherwise create a new one. In code it would look like this:
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (strs == null)
strs = new ArrayList<Guid>();
mListView = (ListView)getActivity().findViewById(R.id.listViewActiveThreads);
mPersonAdapter = new ArrayAdapterPerson(getActivity(),mPersonList,this);
mListView.setAdapter(mPersonAdapter);
}
I found my solution here: ListFragment is empty after going back
use transaction.hide(this):
ft.addToBackStack(null);
ft.hide(this);
ft.add(R.id.frag_frame, lyrics);
ft.commit();

Fool-proof way to handle Fragment on orientation change

public class MainActivity extends Activity implements MainMenuFragment.OnMainMenuItemSelectedListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
// add menu fragment
MainMenuFragment myFragment = new MainMenuFragment();
fragmentTransaction.add(R.id.menu_fragment, myFragment);
//add content
DetailPart1 content1= new DetailPart1 ();
fragmentTransaction.add(R.id.content_fragment, content1);
fragmentTransaction.commit();
}
public void onMainMenuSelected(String tag) {
//next menu is selected replace existing fragment
}
I have a need to display two list views side by side, menu on left and its content on right side. By default, the first menu is selected and its content is displayed on right side. The Fragment that displays content is as below:
public class DetailPart1 extends Fragment {
ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String, String>>();
ListAdapter adap;
ListView listview;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState!=null){
myList = (ArrayList)savedInstanceState.getSerializable("MYLIST_obj");
adap = new LoadImageFromArrayListAdapter(getActivity(),myList );
listview.setAdapter(adap);
}else{
//get list and load in list view
getlistTask = new GetALLListTasks().execute();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.skyview_fragment, container,false);
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("MYLIST_obj", myList );
}
}
The onActivityCreated and onCreateView are called twice. There are many examples out there using fragments. Since I am beginner in this subject, I am unable relate the example with my problem. I need a fool proof way to handle orientation change. I have NOT declared android:configChanges in manifest file. I need the activity destroy and recreate so that I can use different layout in landscape mode.
You are creating a new fragment every time you turn the screen in your activity onCreate(); But you are also maintaining the old ones with super.onCreate(savedInstanceState);. So maybe set tag and find the fragment if it exists, or pass null bundle to super.
This took me a while to learn and it can really be a pain when you are working with stuff like viewpager.
I'd recommend you to read about fragments an extra time as this exact topic is covered.
Here is an example of how to handle fragments on a regular orientation change:
Activity:
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
TestFragment test = new TestFragment();
test.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, test, "your_fragment_tag").commit();
} else {
TestFragment test = (TestFragment) getSupportFragmentManager().findFragmentByTag("your_fragment_tag");
}
}
}
Fragment:
public class TestFragment extends Fragment {
public static final String KEY_ITEM = "unique_key";
public static final String KEY_INDEX = "index_key";
private String mTime;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout, container, false);
if (savedInstanceState != null) {
// Restore last state
mTime = savedInstanceState.getString("time_key");
} else {
mTime = "" + Calendar.getInstance().getTimeInMillis();
}
TextView title = (TextView) view.findViewById(R.id.fragment_test);
title.setText(mTime);
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("time_key", mTime);
}
}
A good guideline about how to retain data between orientation changes and activity recreation can be found in android guidelines.
Summary:
make your fragment retainable:
setRetainInstance(true);
Create a new fragment only if necessary (or at least take data from it)
dataFragment = (DataFragment) fm.findFragmentByTag("data");
// create the fragment and data the first time
if (dataFragment == null) {

Categories

Resources