Strange fragment lifecycle behavior: onCreate called twice - java

I've created simple fragment.
FRAGMENT CLASS
public class MyFragment extends Fragment {
static int count = 0;
static TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("TEST", "oncreate");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag, container, false);
tv = (TextView) view.findViewById(R.id.tv);
return view;
}
public static TextView setMyText(String text) {
tv.setText(text);
return tv;
}
}
But the thing is that onCreate fragment is called twice (when activity is first launched). Anyone has an idea why? In fact every lifecycle method is called twice ( onAttach, onResume..). I'm not rotating screen or anything, if someone might wonder. Is this common case or I'm doing something wrong here?
ACTIVITY CLASS
public class MainActivity extends FragmentActivity {
private static int COUNT = 0;
private static int COUNT2 = 5;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_pager);
ViewPager vp = (ViewPager) findViewById(R.id.vp);
vp.setAdapter(new MyAdapter(getSupportFragmentManager()));
vp.setOnPageChangeListener(new CustomPageListener());
}
private static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
MyFragment mf = new MyFragment();
return mf;
}
#Override
public int getCount() {
return 5;
}
}
private class CustomPageListener extends ViewPager.SimpleOnPageChangeListener {
#Override
public void onPageSelected(int position) {
MyFragment.setMyText("This is page "+position);
}
}
}

By default FragmentStatePagerAdapter will instantiate two pages for ViewPager. The onCreate it is called twice, once for each fragment returned by public Fragment getItem(int position)

Related

How to use viewPager and Fragments for passing multiple data

Im trying to pass string data together with images.
Why when running this code I get only image 'nature4' shown but there is no 'nature2' image and strings 'Fragment1' etc..
public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
private ArrayList<String> strs;
private FragmentPagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("x","onCreateActivity");
strs = new ArrayList<String>();
strs.add("Fragment 1");
strs.add("Fragment 2");
strs.add("Fragment 3");
strs.add("Fragment 4");
strs.add("Fragment 5");
viewPager = (ViewPager) findViewById(R.id.pager);
adapter = new FragmentPagerAdapter(getSupportFragmentManager(), strs);
viewPager.setAdapter(adapter);
}
public class FragmentPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<String> itemData;
public FragmentPagerAdapter(FragmentManager fm, ArrayList<String> itemData) {
super(fm);
this.itemData = itemData;
}
#Override
public int getCount()
{
return itemData.size();
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
Log.i("x","destroyItem");
}
#Override
public Fragment getItem(int position){
Log.i("x","getItem");
// pass data to fragment
Fragment1 f = Fragment1.newInstance(itemData.get(position));
return f;
}
}
}
And Fragment.class
public class Fragment1 extends Fragment {
public Fragment1(){}
String stringValue;
private int [] images = {R.drawable.nature2,R.drawable.nature4};
public static Fragment1 newInstance(String str)
{
Fragment1 slider=new Fragment1();
Bundle b=new Bundle();
b.putString("stringValue", str);
slider.setArguments(b);
return slider;
}
TextView textView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i("x","onCreateViewFragment");
View view = inflater.inflate(R.layout.fragment1, container, false);
textView = (TextView) view.findViewById(R.id.textView);
ImageView photo = (ImageView) view.findViewById(image);
photo.setImageResource(images[1]);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i("x","onActivityCreatedFragment");
super.onActivityCreated(savedInstanceState);
stringValue = getArguments().getString("stringValue");
textView.setText(stringValue);
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i("x","onCreateFragment");
super.onCreate(savedInstanceState);
}
}
I think you need to make your question clear. If you want to pass String stringValue and in imageResId from Activity to Fragment, try the following codes.
public static Fragment1 newInstance(String str, int imageResId) {
Fragment1 slider = new Fragment1();
Bundle b=new Bundle();
b.putString("stringValue", str);
b.putInt("image_resid", imageResId);
slider.setArguments(b);
return slider;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
stringValue = getArguments().getString("stringValue");
imageResId = getArguments().getIn("image_resid");
}
FragmentPagerAdapter:
public class FragmentPagerAdapter extends FragmentStatePagerAdapter {
...
#Override
public Fragment getItem(int position){
Fragment fragment;
String str = itemData.get(position);
int resId;
if (position == 0) {
resId = R.drawable.nature2;
} else if (position == 1) {
resId = R.drawable.nature4;
}
fragment = Fragment1.newInstance(str, resId);
...
return fragment;
}
}

Add fragment into viewPager's fragment

I have viewpager with 3 fragments (same layout - some EditText and Buttons) and I want to dynamically add small fragment above the viewpager fragment, write something in and then hide it.
This is what I tried:
MainActivity.java:
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager pager = (ViewPager) findViewById(R.id.viewPager);
pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return MainFragment.newInstance("1");
case 1: return MainFragment.newInstance("2");
case 2: return MainFragment.newInstance("3");
default: return MainFragment.newInstance("");
}
}
#Override
public int getCount() {
return 3;
}
}
}
MainFragment.java:
public class MainFragment extends android.support.v4.app.Fragment {
EditText contentEdit;
String content, ID;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ID = getArguments().getString("msg");
}
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
contentEdit = (EditText) view.findViewById(R.id.editText);
contentEdit.setOnTouchListener(new OnSwipeTouchListener(getActivity()) {
public void onSwipeBottom() {
final ViewGroup newView = (ViewGroup) LayoutInflater.from(getActivity()).inflate(R.layout.fragment_title, container, false);
newView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
container.removeView(newView);
}
});
container.addView(newView, 0);
}
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
return view;
}
}
Try to put a frame layout above that viewPager layout BUT set it's visibility to GONE therefore it won't "exist". Now in your pager onItemClick listener for that small fragment you want to show call findViewByID(R.id.YourFrameLayout).setVisibility(View.VISIBLE); and when you want to hide it, well you get the idea. Don't forget to add your fragment to that container, e.g. YourFrameLayout

Android my own listener

I have an ActionBar and it has Tabs.
In the MainActivity there is a String variable.
In one Tab there is a TextView and a method setTv(String string) what can change the text in it.
I would like to make a Listener interface what can call the setTv(String string) method, when the str String is changes in the MainActivity.
Could anybody help me and fill in this code with the implementation?
This is the MainActivity code:
public class MainActivity extends FragmentActivity implements ActionBar.TabListener, LocationListener{
ActionBar actionbar;
ViewPager viewpager;
FragmentPageAdapter ft;
String str;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewpager = (ViewPager) findViewById(R.id.pager);
ft = new FragmentPageAdapter(getSupportFragmentManager());
actionbar = getActionBar();
viewpager.setAdapter(ft);
actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionbar.addTab(actionbar.newTab().setText("Run").setTabListener(this));
actionbar.addTab(actionbar.newTab().setText("Map").setTabListener(this));
actionbar.addTab(actionbar.newTab().setText("Statistics").setTabListener(this));
viewpager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
});
}
This is the Fragment code:
public class RunFragment extends Fragment {
TextView tv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.run_layout, container, false);
tv =(TextView)view.findViewById(R.id.textView1);
return view;
}
public void setTv(String string){
tv.setText(string);
}
}
Get your current fragment in your viewpager:
RunFragment fragment = (RunFragment) ft.getItem(viewPager.getCurrentItem());
Call your method where you want(after change str):
fragment.setTv("string");
For the best way i recommend to you make a class that extends Application
from the docs :
Base class for those who need to maintain global application state
So you can store your str variable in this class and notify any launched Activities of variable state change. Actually i recommend to use Observer pattern
MyApplication :
public class MyApplication extends Application {
private static MyApplication singleton;
private String str;
private ArrayList<StringObserver> observerList = new ArrayList<StringObserver>();
public MyApplication getInstance(){
return singleton;
}
#Override
public void onCreate() {
super.onCreate();
singleton = this;
}
public void setString(String str) {
this.str = str;
notifyObservers();
}
public void addObserver(StringObserver obs) {
observerList.add(obs);
}
public void removeObserver(StringObserver obs) {
observerList.remove(obs);
}
private void notifyObservers() {
for(StringObserver obs : observableList) {
obs.notifyAboutStringChanged(str);
}
}
}
StringObserver :
public interface StringObserver {
void notifyAboutStringChanged(String str);
}
And usage :
public class MainActivity extends FragmentActivity/*or Activity*/ implements StringObserver {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
MyApplication appState = ((MyApplication )this.getApplication());
appState.addObserver(this);
appState.setString("This string was changed");
}
#Override
public void notifyAboutStringChanged(String str) {
// do something
}
}
In other Activity/Fragment :
public class RunFragment extends Fragment {
TextView tv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.run_layout, container, false);
tv =(TextView)view.findViewById(R.id.textView1);
return view;
}
public void setTv(String string){
tv.setText(string);
(MyApplication) getActivity().getApplication().setString(string); // this string notify your activity about value change.
}
}

How to AsyncTask to Fragments from onPageSelected of ViewPager?

I'm new to Android programming.
I googled & stackoverflowed, read android docs but nothing helped me or maybe I didn't understand well.
I'm trying to AsyncTask UI to fragment via onPageSelected from ViewPager.
Like AndroMoney app ViewPager(Before onPageSelected, it shows "loading...", when onPageSelected, it AsyncTasked and loaded.):
AndroMoney ViewPager Fragment Screenshoot
but my code is: it asynctasked while swipping and sometimes it stops between two fragments like this:
my code viewpager screenshot
unlike AndroMoney app, my code doesn't asynctask onPageSelected.
here is MyFragment.java:
public class MyFragment extends Fragment {
public static final String EXTRA_MESSAGE = "EXTRA_MESSAGE";
final StringBuilder buffer=new StringBuilder();
View v;
public static final MyFragment newInstance(int message) {
MyFragment f = new MyFragment();
Bundle bdl = new Bundle(1);
bdl.putInt(EXTRA_MESSAGE, message);
f.setArguments(bdl);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.myfragment_layout, container, false);
new AsyncDatabase().execute();
return v;
}
public class AsyncDatabase extends AsyncTask<Void,Void,Void>{
#Override
protected Void doInBackground(Void... params){
int message = getArguments().getInt(EXTRA_MESSAGE);
BibleService bService=new BibleServiceImpl(getActivity().getApplication());
List<Bible> bible=bService.getBibleByChapterNumber("Salm", message);
for(Bible b: bible){
for(int i=0;i<10;i++){
buffer.append(b);
}
}
return null;
}
#Override
protected void onPostExecute(Void result){
TextView txt1=(TextView)v.findViewById(R.id.textView1);
TextView txt2=(TextView)v.findViewById(R.id.textView2);
txt1.setText("Done");
txt2.setText(buffer.toString());
}
#Override
protected void onPreExecute(){
TextView txt1=(TextView)v.findViewById(R.id.textView1);
txt1.setText("Loading...");
}
#Override
protected void onProgressUpdate(Void... values){
}
}
}
here is PageViewActivity.java:
public class PageViewActivity extends FragmentActivity{
MyPageAdapter pageAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_page_view);
List<Fragment> fragments = getFragments();
pageAdapter = new MyPageAdapter(getSupportFragmentManager(), fragments);
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setOffscreenPageLimit(1);
pager.setAdapter(pageAdapter);
pager.setCurrentItem(11);
pager.setOnPageChangeListener(new OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {
}
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
public void onPageSelected(int position) {
}
});
}
private List<Fragment> getFragments() {
List<Fragment> fList = new ArrayList<Fragment>();
for (int j = 2; j < 150; j++) {
fList.add(MyFragment.newInstance(j));
}
return fList;
}
private class MyPageAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragments;
public MyPageAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
}
I tested stupidly by adding the following code:
public void onPageSelected(int position) {
new MyFragment().new AsyncDatabase().execute();
}
It didn't work.:-P
So, how to asynctask to fragment from onPageSelected of PageViewActivity like AndroMoney app.
Expose a new method in your fragment:
public void executeAsyncTask() {
new AsyncDatabase().execute();
}
In the activity, make your list of fragments final, so you can access it in the Adapter:
final List<MyFragment> fragments = getFragments();
Then change your onPageSelected() method to be:
public void onPageSelected(int position) {
fragments.get(position).executeAsyncTask();
}
You'll also need to update the MyPagerAdapter to use MyFragment instead of Fragment:
private class MyPageAdapter extends FragmentStatePagerAdapter {
private List<MyFragment> fragments;
public MyPageAdapter(FragmentManager fm, List<MyFragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
}
private List<MyFragment> getFragments() {
List<MyFragment> fList = new ArrayList<MyFragment>();
for (int j = 2; j < 150; j++) {
fList.add(MyFragment.newInstance(j));
}
return fList;
}

Passing Assigned Value of a Spinner from Fragment to Fragment within Viewpager NullPointerException

I've make it more simple and updated it based on the answers in my previous post: Adding Assigned Values in Spinner NullPointerException
I have a MainAcitivty that uses a ViewPager. I have 2 Fragments in my MainActivity (FragA and FragB)
In my FragA I have a spinner. While in FragB, I have a TextView and a Button.
Now what am I trying to do is, when I select "Hello" in my spinner, my int a will have a value of 5. And when I click the Button, 5 will display in the TextView.
Here's my code:
FragA
public class FragA extends Fragment {
Spinner spinner1;
String s1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fraga, container, false);
spinner1 = (Spinner) view.findViewById(R.id.spinner1);
ArrayAdapter<CharSequence> adapter_a = ArrayAdapter.createFromResource(getActivity(), R.array.spinner1,android.R.layout.simple_spinner_item );
spinner1.setAdapter(adapter_a);
s1 = spinner1.getSelectedItem().toString();
return view;
}
public int getInt() {
int a = 0;
if(s1.equals("Hello")) {
a = 5;
}
return a;
}
}
MainActivity
public class MainActivity extends FragmentActivity {
ViewPager viewPager = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager)findViewById(R.id.pager);
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager.setAdapter(new MyAdapter(fragmentManager));
}
public class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter (FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = null;
if (i == 0)
{
fragment = new FragA();
}
if (i == 1)
{
fragment = new FragB();
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
}
public String get() {
FragA FragA = new FragA();
return Integer.toString(FragA.getInt());
}
}
FragB
public class FragB extends Fragment{
TextView textView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragb, container, false);
textView = (TextView) view.findViewById(R.id.textview);
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(Click);
return view;
}
OnClickListener Click = new OnClickListener() {
#Override
public void onClick(View v) {
textView.setText(((MainActivity)getActivity()).get());
}
};
}
By the way, I have no problem passing the value of a from FragA to FragB when this is my code:
public int getInt() {
int a = 5;
return a;
}
But, it doesn't involve my spinner and that's not I want to do.
Here is a simple way to communicate between fragments.
In MainActivity, keep static instances of the fragments.
public static FragA fragmentA;
public static FragB fragmentB;
Now if you want to access FragB from FragA, write something similar:
((MainActivity) getActivity()).fragmentB.setSomething();
And Here is a better/proper way to communicate between fragments:
http://developer.android.com/training/basics/fragments/communicating.html

Categories