IT story

조각에는 실제로 빈 생성자가 필요합니까?

hot-time 2020. 4. 5. 20:35
반응형

조각에는 실제로 빈 생성자가 필요합니까?


나는이 Fragment여러 인수를 취하는 생성자. 내 앱은 개발 중에는 잘 작동했지만 프로덕션 환경에서는 때때로 사용자가 다음과 같은 충돌을 보게됩니다.

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

이 오류 메시지에서 알 수 있듯이 빈 생성자를 만들 수는 있지만 이후에는 별도의 메서드를 호출하여을 설정해야합니다 Fragment.

이 충돌이 왜 가끔 발생하는지 궁금합니다. 어쩌면 내가 ViewPager잘못 사용하고 있습니까? 모든 Fragments를 인스턴스화하고 내부의 목록에 저장합니다 Activity. 내가 본 예제에서 요구하지 않았고 개발 중에 모든 것이 작동하는 것처럼 보였으 FragmentManager므로 트랜잭션을 사용 ViewPager하지 않습니다.


그렇습니다.

어쨌든 생성자를 재정의해서는 안됩니다. 당신은이 있어야 newInstance()정의 된 정적 방법과 (번들) 인수를 통해 전달하는 매개 변수

예를 들면 다음과 같습니다.

public static final MyFragment newInstance(int title, String message) {
    MyFragment f = new MyFragment();
    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
    //...
}

그런 다음 조각 관리자에서 다음과 같이 인스턴스화하십시오.

@Override
public void onCreate(Bundle savedInstanceState) {
    if (savedInstanceState == null){
        getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.content, MyFragment.newInstance(
                R.string.alert_title,
                "Oh no, an error occurred!")
            )
            .commit();
    }
}

이런 식으로 분리하고 다시 연결하면 객체 상태를 인수를 통해 저장할 수 있습니다. 인 텐트에 첨부 된 번들과 매우 유사합니다.

이유-추가 자료

나는 사람들이 왜 궁금해하는지 설명 할 것이라고 생각했습니다.

확인하면 https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Fragment.java

당신은 볼 수 instantiate(..)의 방법 Fragment클래스가 호출 newInstance방법 :

public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
    try {
        Class<?> clazz = sClassMap.get(fname);
        if (clazz == null) {
            // Class not found in the cache, see if it's real, and try to add it
            clazz = context.getClassLoader().loadClass(fname);
            if (!Fragment.class.isAssignableFrom(clazz)) {
                throw new InstantiationException("Trying to instantiate a class " + fname
                        + " that is not a Fragment", new ClassCastException());
            }
            sClassMap.put(fname, clazz);
        }
        Fragment f = (Fragment) clazz.getConstructor().newInstance();
        if (args != null) {
            args.setClassLoader(f.getClass().getClassLoader());
            f.setArguments(args);
        }
        return f;
    } catch (ClassNotFoundException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": make sure class name exists, is public, and has an"
                + " empty constructor that is public", e);
    } catch (java.lang.InstantiationException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": make sure class name exists, is public, and has an"
                + " empty constructor that is public", e);
    } catch (IllegalAccessException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": make sure class name exists, is public, and has an"
                + " empty constructor that is public", e);
    } catch (NoSuchMethodException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": could not find Fragment constructor", e);
    } catch (InvocationTargetException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": calling Fragment constructor caused an exception", e);
    }
}

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

이 질문 https://stackoverflow.com/a/16064418/1319061 에서 CommonsWare가 지적한 것처럼 익명 클래스에는 생성자를 가질 수 없으므로 Fragment의 익명 서브 클래스를 작성하는 경우 에도이 오류가 발생할 수 있습니다.

Fragment의 익명 서브 클래스를 만들지 마십시오 :-)


예, support-package는 프래그먼트도 인스턴스화합니다 (파손되고 다시 열릴 때). 당신 Fragment이 프레임 워크에 의해 호출되는 무슨이기 때문에 서브 클래스는 공개 비어있는 생성자가 필요합니다.


간단한 해결책은 다음과 같습니다.

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-즐기세요!

분명히 유형과 매개 변수 수를 변경할 수 있습니다. 빠르고 쉽습니다.

참고 URL : https://stackoverflow.com/questions/10450348/do-fragments-really-need-an-empty-constructor

반응형