programing

조각에 빈 생성자가 정말 필요합니까?

i4 2023. 7. 30. 17:04
반응형

조각에 빈 생성자가 정말 필요합니까?

나는 있습니다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그렇지 않나요?나는 모든 것을 인스턴스화합니다.Fragment나 자신과 그들을 내부의 목록에 저장합니다.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
    //...
}

그런 다음 fragment 매니저로부터 다음과 같이 인스턴스를 생성합니다.

@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(..)의 방법Fragmentclass calls 더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...
}

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

fragment의 익명 하위 클래스를 만들지 마십시오 :-)

예, 지원 패키지는 조각도 인스턴스화합니다(파편이 파괴되었다가 다시 열리면).당신의.Fragment하위 클래스에는 공용 빈 생성자가 필요합니다. 이 생성자는 프레임워크에 의해 호출됩니다.

공식 문서를 확인하십시오.조각: https://developer.android.com/reference/android/app/Fragment

Fragment의 모든 하위 클래스에는 공개 인수 없음 생성자가 포함되어야 합니다.프레임워크는 특히 상태 복원 중에 필요할 때 종종 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

반응형