Действительно ли фрагментам нужен пустой конструктор?

У меня есть фрагмент с конструктором с несколькими аргументами, все отлично работало во время testphase, но теперь, после того, как около 300 пользователей загрузили приложение, у меня есть ОДИН случай этого исключения:

android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment make sure class name exists, is public, and has an empty constructor that is public 

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

Мне любопытно, почему это происходит спорадически, а не всегда и, возможно, я использую Fragmented Viewpager просто неправильно, потому что я сам создаю все фрагменты и сохраняю их в списке внутри действия. Я не использую материал транзакции FragmentManager , так как пример о Fragmented Viewpager был не очень понятен в этом, и в итоге все работало нормально.

Solutions Collecting From Web of "Действительно ли фрагментам нужен пустой конструктор?"

Да, да.

В любом случае вы не должны переопределять конструктор. У вас должен быть установлен статический метод newInstance() и передавать любые параметры через аргументы (bundle)

Например:

 public static final AlertFragment newInstance(int title, String message) { AlertFragment f = new AlertFragment(); Bundle bdl = new Bundle(2); bdl.putInt(EXTRA_TITLE, title); bdl.putString(EXTRA_MESSAGE, message); f.setArguments(bdl); return f; } 

И, конечно же, хватайте аргументы таким образом:

 @Override public void onCreate(Bundle savedInstanceState) { title = getArguments().getInt(EXTRA_TITLE); message = getArguments().getString(EXTRA_MESSAGE); //... //etc //... } 

Затем вы создадите экземпляр из вашего менеджера фрагментов следующим образом:

 public onCreate(Bundle savedInstanceState) { if(savedInstanceState == null){ getSupportFragmentManager() .beginTransaction() .replace(R.id.content,AlertFragment.newInstance( R.string.alert_title, "Oh noes an error occured!") ) .commit(); } } 

Таким образом, если отсоединение и повторное присоединение состояния объекта можно сохранить через аргументы. Очень похоже на пучки, привязанные к намерениям.

Причина – дополнительное чтение

Я думал, что объясню, почему люди задаются вопросом, почему.

Если вы отметили: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Fragment.java

Вы увидите, что метод instantiate(..) в классе Fragment вызывает метод newInstance .

В случае неработающей ссылки вы также можете увидеть ее здесь: Введите описание изображения здесь

http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#newInstance () Объясняет, почему после создания экземпляра он проверяет, что аксессор является public и что этот загрузчик классов разрешает доступ к нему ,

Это довольно неприятный метод в целом, но он позволяет FragmentManger убивать и воссоздавать Fragments с состояниями. (Подсистема Android выполняет аналогичные действия с Activities ).

Пример класса

Меня много спрашивают о вызове newInstance (не путайте это с методом класса. Этот пример всего класса должен показывать использование.

 /** * Created by chris on 21/11/2013 */ public class StationInfoAccessibilityFragment extends BaseFragment implements JourneyProviderListener { public static final StationInfoAccessibilityFragment newInstance(String crsCode) { StationInfoAccessibilityFragment fragment = new StationInfoAccessibilityFragment(); final Bundle args = new Bundle(1); args.putString(EXTRA_CRS_CODE, crsCode); fragment.setArguments(args); return fragment; } // Views LinearLayout mLinearLayout; /** * Layout Inflater */ private LayoutInflater mInflater; /** * Station Crs Code */ private String mCrsCode; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCrsCode = getArguments().getString(EXTRA_CRS_CODE); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mInflater = inflater; return inflater.inflate(R.layout.fragment_station_accessibility, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mLinearLayout = (LinearLayout)view.findViewBy(R.id.station_info_accessibility_linear); //Do stuff } @Override public void onResume() { super.onResume(); getActivity().getSupportActionBar().setTitle(R.string.station_info_access_mobility_title); } // Other methods etc... } 

Как отмечалось в CommonsWare в этом вопросе https://stackoverflow.com/a/16064418/1319061 , эта ошибка также может возникать, если вы создаете анонимный подкласс фрагмента, поскольку анонимные классы не могут иметь конструкторы.

Не делайте анонимных подклассов Фрагмента 🙂

Да, поскольку вы можете увидеть, что пакет поддержки также создает фрагменты (когда они уничтожаются и снова открываются). Подклассам Fragemnt нужен публичный пустой конструктор, так как это то, что вызывается инфраструктурой.

Вот мое простое решение:

1 – Определить фрагмент

 public class MyFragment extends Fragment { private String parameter; public MyFragment() { } public void setParameter(String parameter) { this.parameter = parameter; } } 

2 – Создайте новый фрагмент и запишите параметр

  myfragment = new MyFragment(); myfragment.setParameter("here the value of my parameter"); 

3 – Наслаждайтесь!

Очевидно, вы можете изменить тип и количество параметров. Быстро и просто.