web-dev-qa-db-fra.com

Fragment - InstantiationException: pas de constructeur vide -> Google Maps v2?

Je reçois ce message d'erreur lorsque j'ouvre à nouveau une application fermée via le bouton App-Change:

Caused by: Java.lang.InstantiationException: can't instantiate class com.*.FragmentContact$1; no empty constructor

J'ai trouvé plusieurs astuces sur les classes intérieures et les rendre statiques, etc. Mais ce FragmentContact est une classe public dans un fichier * .Java et a un constructeur vide public . J'utilise Google Maps Api v2 dans ce projet et je fais un tour quelque part sur Internet pour configurer mon MapView. Regardez ici:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_contact, null);

    try {
        MapsInitializer.initialize(this.getActivity().getApplicationContext());
    } catch (GooglePlayServicesNotAvailableException e) {
        e.printStackTrace();
    }

    fragment = new SupportMapFragment() {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            mMap = fragment.getMap();
            if (mMap != null) {
                setupMap();
            }
        }
    };

    getFragmentManager().beginTransaction().replace(R.id.fragment_orte_map_parent, fragment).commit();

    return v;
}

Quand je coupe ce MapView-chose tout fonctionne bien. Peut-être que quelqu'un peut expliquer ce que je fais mal.

Mon Stacktrace complet:

FATAL EXCEPTION: main
Java.lang.RuntimeException: Unable to start activity ComponentInfo{com.*/com.*.MainActivity}: Android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.*.FragmentContact$1: make sure class name exists, is public, and has an empty constructor that is public
   at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2307)
   at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2357)
   at Android.app.ActivityThread.access$600(ActivityThread.Java:153)
   at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1247)
   at Android.os.Handler.dispatchMessage(Handler.Java:99)
   at Android.os.Looper.loop(Looper.Java:137)
   at Android.app.ActivityThread.main(ActivityThread.Java:5226)
   at Java.lang.reflect.Method.invokeNative(Native Method)
   at Java.lang.reflect.Method.invoke(Method.Java:511)
   at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:795)
   at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:562)
   at dalvik.system.NativeStart.main(Native Method)
Caused by: Android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.*.FragmentContact$1: make sure class name exists, is public, and has an empty constructor that is public
   at Android.support.v4.app.Fragment.instantiate(Fragment.Java:405)
   at Android.support.v4.app.FragmentState.instantiate(Fragment.Java:97)
   at Android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.Java:1767)
   at Android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.Java:208)
   at com.*.MainActivity.onCreate(MainActivity.Java:20)
   at Android.app.Activity.performCreate(Activity.Java:5104)
   at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.Java:1080)
   at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2261)
   ... 11 more
Caused by: Java.lang.InstantiationException: can't instantiate class com.*.FragmentContact$1; no empty constructor
   at Java.lang.Class.newInstanceImpl(Native Method)
   at Java.lang.Class.newInstance(Class.Java:1319)
   at Android.support.v4.app.Fragment.instantiate(Fragment.Java:394)
   ... 18 more
16
Osiriz

Mais ces FragmentContact sont une classe publique dans un fichier * .Java et ont un constructeur public vide.

L'erreur ne se plaint pas à propos de FragmentContact. Il se plaint de la première classe interne de FragmentContact (FragmentContact$1). Vous ne pouvez pas implémenter une Fragment en tant que classe interne, car elle ne peut pas être instanciée de l'extérieur Une classe intérieure static convient.

29
CommonsWare

J'ai ce problème depuis des lustres et, finalement, les commentaires que j'ai lus ici l'ont résolu. Informations intéressantes sur le $1, qui signifie classe interne anonyme.

Déplacez l'initialisation de votre carte vers une nouvelle classe publique, par exemple. MyMapFragment.Java. Cela permettra au fragment d’être instancié sans l’instance de 

Pour ceux qui ne savent toujours pas comment y remédier. Écrivez le code comme suit (en utilisant l'exemple de code de la question initiale):

//Existing code to instantiate map
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.fragment_contact, null);

    try {
        MapsInitializer.initialize(this.getActivity().getApplicationContext());
    } catch (GooglePlayServicesNotAvailableException e) {
        e.printStackTrace();
    }

    fragment = new MyMapFragment();

    //added callback for catching when the map has finished loading
    mapFragment.setLoadedCallback(new MapLoadedCallback() {
        @Override
        public void onLoaded(GoogleMap map) {
            mMap = map;
        }
    });

    getFragmentManager().beginTransaction().replace(R.id.fragment_orte_map_parent, fragment).commit();

    return v;
}
....

Créez un nouveau MyMapFragment.Java afin qu'il ne soit plus une classe interne. Cela permettra au fragment d'être créé sans sa classe externe.

public class MyMapFragment extends SupportMapFragment 
{
    GoogleMap mMap;
    public MyMapFragment() {
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
         mMap = fragment.getMap();
         if (mMap != null) {
             mCallback.onLoaded(mMap);
        }
    }
}    

Créez MapLoadedCallback.Java pour vous permettre de gérer le chargement de la carte et de récupérer une instance de l'objet de carte chargé.

public interface MapLoadedCallback {
    void onLoaded(GoogleMap map);
}
0
Matthew Cawley