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
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.
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);
}