-1

For Learning Purposes I'am making an application .. When I change my orientation before pressing any button on Screen .. it successfully changes orientation and shows respective layout that I've added into "layout-land" folder ...

But when i press the button to show next fragement , and then switch orientation .. I expected the activity to restart but My app Crashes ... Here I need Help ..

Debugger Dose not show the line where any exception is thrown

MainActivity Class

package com.example.prototype;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;

import com.example.prototype.fragments.FragmentOne;



public class MainActivity extends FragmentActivity {

     int fragShowButtonPressed =0;
     boolean FragOneDisplayed=false;
     boolean FragTwoDisplayed=false;


 public void fragment_switch(View v){

     Button showfrag1 = (Button)findViewById(R.id.buttonShowFrag1); 
     Button showfrag2 = (Button)findViewById(R.id.buttonShowFrag2); 
        showfrag1.setVisibility(showfrag1.INVISIBLE);
        showfrag2.setVisibility(showfrag2.INVISIBLE);

     FragmentTransaction ft = getSupportFragmentManager().beginTransaction();


     switch(v.getId()){

     case(R.id.buttonShowFrag1):   ft.replace(R.id.frameLayout1, new FragmentOne("frag_1"), null); fragShowButtonPressed=1;  FragOneDisplayed=true; FragTwoDisplayed=false;  break;

     case(R.id.buttonShowFrag2):   ft.replace(R.id.frameLayout1, new FragmentOne("frag_2"), null); fragShowButtonPressed=1; FragOneDisplayed=false; FragTwoDisplayed=true; break;


     }

     ft.addToBackStack(null);
     ft.commit();


 }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.i("create", "Entered Oncreate");
        setContentView(R.layout.activity_main);


         if(savedInstanceState != null){

             if(savedInstanceState.getInt("frag_button_pressed_stat")==1)
             {  
                Button showfrag1 = (Button)findViewById(R.id.buttonShowFrag1); 
                Button showfrag2 = (Button)findViewById(R.id.buttonShowFrag2); 
                showfrag1.setVisibility(showfrag1.INVISIBLE);
                showfrag2.setVisibility(showfrag2.INVISIBLE);

                FragOneDisplayed=savedInstanceState.getBoolean("frag_one_display_stat"); 
                FragTwoDisplayed=savedInstanceState.getBoolean("frag_two_display_stat");



             }


             else{}





         }



    }


 @Override
protected void onSaveInstanceState(Bundle outState) {

      if(fragShowButtonPressed ==1)
      {   
          outState.putInt("frag_button_pressed_stat", fragShowButtonPressed);
          outState.putBoolean("frag_one_display_stat", FragOneDisplayed);
          outState.putBoolean("frag_two_display_stat", FragTwoDisplayed);
      }
     super.onSaveInstanceState(outState);
}   

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

FragmentOne Class

package com.example.prototype.fragments;


import com.example.prototype.R;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentOne extends Fragment  {

    int id;
    Context context;

    public FragmentOne(String frag_name){

        if(frag_name=="frag_1")
        {
            id=R.layout.frag_1;
        }

        else if(frag_name == "frag_2"){

            id=R.layout.frag_2;

        }

        else{}
    }





    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

        context = inflater.getContext();
        View v=inflater.inflate(id, container, false);
        return v;

    }
}

Please Note when I make different fragment classes each with empty constructor and directly providing the int XML resource to inflate() function problem is solved

Taimoor Ali , Thankyou

LOG CAT

07-09 23:35:45.387: E/AndroidRuntime(948): FATAL EXCEPTION: main
07-09 23:35:45.387: E/AndroidRuntime(948): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.prototype/com.example.prototype.MainActivity}: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.prototype.fragments.FragmentOne: make sure class name exists, is public, and has an empty constructor that is public
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2205)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2240)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3809)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.ActivityThread.access$700(ActivityThread.java:139)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1266)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.os.Handler.dispatchMessage(Handler.java:99)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.os.Looper.loop(Looper.java:156)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.ActivityThread.main(ActivityThread.java:4987)
07-09 23:35:45.387: E/AndroidRuntime(948):  at java.lang.reflect.Method.invokeNative(Native Method)
07-09 23:35:45.387: E/AndroidRuntime(948):  at java.lang.reflect.Method.invoke(Method.java:511)
07-09 23:35:45.387: E/AndroidRuntime(948):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
07-09 23:35:45.387: E/AndroidRuntime(948):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
07-09 23:35:45.387: E/AndroidRuntime(948):  at dalvik.system.NativeStart.main(Native Method)
07-09 23:35:45.387: E/AndroidRuntime(948): Caused by: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.prototype.fragments.FragmentOne: make sure class name exists, is public, and has an empty constructor that is public
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.support.v4.app.Fragment.instantiate(Fragment.java:405)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.support.v4.app.FragmentState.instantiate(Fragment.java:97)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:1767)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:208)
07-09 23:35:45.387: E/AndroidRuntime(948):  at com.example.prototype.MainActivity.onCreate(MainActivity.java:44)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.Activity.performCreate(Activity.java:4538)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1071)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2161)
07-09 23:35:45.387: E/AndroidRuntime(948):  ... 12 more
07-09 23:35:45.387: E/AndroidRuntime(948): Caused by: java.lang.InstantiationException: can't instantiate class com.example.prototype.fragments.FragmentOne; no empty constructor
07-09 23:35:45.387: E/AndroidRuntime(948):  at java.lang.Class.newInstanceImpl(Native Method)
07-09 23:35:45.387: E/AndroidRuntime(948):  at java.lang.Class.newInstance(Class.java:1319)
07-09 23:35:45.387: E/AndroidRuntime(948):  at android.support.v4.app.Fragment.instantiate(Fragment.java:394)
07-09 23:35:45.387: E/AndroidRuntime(948):  ... 19 more
Taimoor Ali
  • 129
  • 8

2 Answers2

1

You error suggests that you don't have an empty constructor for your fragment:

07-09 23:35:45.387: E/AndroidRuntime(948): Caused by: java.lang.InstantiationException: can't instantiate class com.example.prototype.fragments.FragmentOne; no empty constructor

And you would need one on configuration changes because your fragment is being rebuild.

You need to instantiate the data in your fragment in a different way, for example:

    public static final GridFragment newInstance(String tabId)
{
    GridFragment f = new GridFragment();
    Bundle bdl = new Bundle(2);
    bdl.putString(TAB_ID, tabId);
    f.setArguments(bdl);
    return f;
}


@Override
public void onCreate(Bundle savedInstanceState) 
{
    String tabId = getArguments().getString(TAB_ID);
    if (application.currentReport != null)
    {
        this.odTab = application.currentReport.getODTabByTabId(tabId);
    }
    else
    {
        startActivity(new Intent(getActivity(), LoginScrActivity.class));
    }
    super.onCreate(savedInstanceState);
}

That way the constructor still empty but you are passing your needed string, see also this question:

Do fragments really need an empty constructor?

Community
  • 1
  • 1
Emil Adz
  • 40,709
  • 36
  • 140
  • 187
  • any alternatives becuase ive 5 xml layouts and i cant make 5 different fragment classes there has to be a way to combine them together in one class @Emil Adz – Taimoor Ali Jul 09 '13 at 19:02
  • @TaimoorAli, I posted the same exact code only earlier. It didn't helped you? – Emil Adz Jul 09 '13 at 19:10
  • Ive added this View v=inflater.inflate(getArguments().getInt("id"), container, false); ... in my activityclass method ive written FragmentOne frt = new FragmentOne(); frt.newinstance(R.layout.frag_1); Now what should I write as second argument of replace function .. This is what I wrote ft.replace(R.id.frameLayout1, frt, null) – Taimoor Ali Jul 09 '13 at 19:35
1

You must have an empty constructor (with no arguments) or none (default) for fragments. If you want to pass arguments create a Bundle with the arguments and use setArguments.

This is commonly accomplished with static create methods:

class MyFragment extends Fragment {

 public static MyFragment newInstance(String name) {
    MyFragment f = new MyFragment();
    Bundle args = new Bundle();
    args.putString("name", name);
    f.setArguments(bundle);
    return f;
 }
 ...
}

But in your case just send the id of the layout?

Mattias Isegran Bergander
  • 11,811
  • 2
  • 41
  • 49
  • any link to where to start and can you tell me how to do it because iI have 5 different XML layouts and i want to use a similar approach in question to change fragments .... Can you show me the code .. and thanks for showing alternative – Taimoor Ali Jul 09 '13 at 19:07
  • The official android developer documentation is pretty good. Here is an example in the Fragment section: http://developer.android.com/guide/components/fragments.html#Example Notice how they in the DetailsFragment create it with the id of the item as an argument. Generally you should probably use different fragments for different layouts though, but hard to say. Depends on how they differ (or the purpose for them). Good luck! – Mattias Isegran Bergander Jul 09 '13 at 19:30
  • Ive added this View v=inflater.inflate(getArguments().getInt("id"), container, false); ... in my activityclass method ive written FragmentOne frt = new FragmentOne(); frt.newinstance(R.layout.frag_1); Now what should I write as second argument of replace function .. This is what I wrote ft.replace(R.id.frameLayout1, frt, null); @Mattias – Taimoor Ali Jul 09 '13 at 19:35