Фрагмент - InstantiationException: нет пустого Конструктора -> Google Maps v2?

Я получаю это сообщение об ошибке, когда снова открываю закрытое приложение с помощью кнопки "Изменить приложение":

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

Я нашел несколько советов о внутренних классах и о том, как сделать их статическими и т. Д. Но этот FragmentContact является открытым классом в *.java-файле и имеет открытый пустой конструктор. Я использую Google Maps Api v2 в этом проекте и делаю трюк где-то в интернете для настройки моего MapView. Смотри сюда:

@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;
}

Когда я вырезал эту вещь MapView, все работало нормально. Может быть, кто-то может объяснить, что я делаю не так.

Моя полная Stacktrace:

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

4 ответа

Решение

Но эти FragmentContact является открытым классом в *.java-файле и имеет открытый пустой конструктор.

На ошибку не жалуюсь FragmentContact, Жалуется на первый внутренний класс FragmentContact (FragmentContact$1). Вы не можете иметь Fragment реализуется как внутренний класс чего-либо, поскольку его нельзя создать вне внешнего класса. static внутренний класс в порядке.

У меня была эта проблема целую вечность, и, наконец, комментарии здесь решили ее для меня. Хорошая информация о $1 имеется в виду анонимный внутренний класс.

Переместите инициализацию вашей карты в новый Public Class, например MyMapFragment.java, Это позволит создать экземпляр фрагмента без экземпляра

Для тех, кто до сих пор не уверен, как это исправить. Напишите код следующим образом (используя пример кода из исходного вопроса):

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

Создать новый MyMapFragment.java так что это больше не внутренний класс. Это позволит создать фрагмент без его внешнего класса.

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

Создайте MapLoadedCallback.java чтобы вы могли обрабатывать, когда карта закончила загрузку, и получить экземпляр загруженного объекта карты.

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

1. В идеале мы не должны ничего передавать в конструктор фрагмента, конструктор фрагмента должен быть пустым или заданным по умолчанию. 2. Теперь второй вопрос: что, если мы хотим передать интерфейсную переменную или параметры - a. мы должны использовать Bundle для передачи данных. б. Для интерфейса мы можем поместить Parceble в bundle и сделать этот интерфейс реализуемым parceblec. Если возможно, мы можем реализовать этот интерфейс в действии, а во фрагменте мы можем инициализировать слушателя в OnAttach, где у нас есть context[(context) Listener].

Чтобы при изменении конфигурации напр. Смена шрифта, прослушиватель восстановления активности не будет деинициализирован, и мы можем избежать исключения нулевого указателя.

  private Entity mEntity;
  public YourFragment() {}
  public static YourFragment getInstance(Entity mEntity) {
    YourFragment fragment = new YourFragment();
    fragment.mEntity = mEntity;
    return fragment;
  }

когда вы используете этот фрагмент, просто вызовите статический метод getInstance,

Другие вопросы по тегам