programing

새 Android 단편을 인스턴스화하는 모범 사례

bestprogram 2023. 6. 1. 23:04

새 Android 단편을 인스턴스화하는 모범 사례

응용 프로그램에서 새 프래그먼트를 인스턴스화하는 두 가지 일반적인 방법을 보았습니다.

Fragment newFragment = new MyFragment();

그리고.

Fragment newFragment = MyFragment.newInstance();

방법을 합니다.newInstance()일반적으로 다음과 같은 방법을 포함합니다.

public static Fragment newInstance() 
{
    MyFragment myFragment = new MyFragment();
    return myFragment;
}

처음에는 fragment의 새 인스턴스를 만들 때 유연성을 주기 위해 newInstance() 메서드를 오버로드할 수 있다는 것이 주요 이점이라고 생각했지만 fragment에 대한 오버로드된 생성자를 생성하여 이를 수행할 수도 있었습니다.

제가 뭔가를 빠뜨렸나요?

하나의 접근 방식이 다른 접근 방식에 비해 어떤 이점이 있습니까?아니면 그냥 좋은 연습인가요?

안드로이드가 나중에 프래그먼트를 재생성하기로 결정하면, 프래그먼트의 무인수 생성자를 호출합니다.따라서 생성자에게 과부하를 주는 것은 해결책이 아닙니다.

후 수을 이와같, 이안드에의수재있당프록도신후의프것다트물먼래니입에그전전번방는하달건을을들은법하달는래생사할용성해그트가먼된이드로▁the▁to▁with▁bundle에 전달하는 것입니다.setArguments방법.

예를 들어, 조각에 정수를 전달하려면 다음과 같은 것을 사용합니다.

public static MyFragment newInstance(int someInt) {
    MyFragment myFragment = new MyFragment();

    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    myFragment.setArguments(args);

    return myFragment;
}

그리고 그 단편의 후반부onCreate()다음을 사용하여 해당 정수에 액세스할 수 있습니다.

getArguments().getInt("someInt", 0);

이 번들은 Android에서 조각을 다시 생성하더라도 사용할 수 있습니다.

참고:setArguments프래그먼트가 활동에 첨부되기 전에만 호출할 수 있습니다.

이 접근 방식은 Android 개발자 참조 자료에도 나와 있습니다. https://developer.android.com/reference/android/app/Fragment.html

용의유이은을 수 newInstance()제가 본 것은 다음과 같습니다.

  1. 프래그먼트에 사용되는 모든 인수가 번들로 구성될 수 있는 단일 위치가 있으며 프래그먼트를 인스턴스화할 때마다 아래에 코드를 작성할 필요가 없습니다.

    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    args.putString("someString", someString);
    // Put any other arguments
    myFragment.setArguments(args);
    
  2. 는 다른 클래스에 어떤 인수가 제대로 작동할 것으로 예상되는지를 알려주는 좋은 방법입니다(단, fragment 인스턴스에 인수가 번들되지 않은 경우 사례를 처리할 수 있어야 함).

그래서, 제 생각에는 정전기를 사용하는 것이newInstance()조각을 인스턴스화하는 것은 좋은 관행입니다.

다른 방법도 있습니다.

Fragment.instantiate(context, MyFragment.class.getName(), myBundle)

@yydl이 왜 그런지에 대한 설득력 있는 이유를 제시하는 동안.newInstance가 더.

안드로이드가 나중에 프래그먼트를 재생성하기로 결정하면, 프래그먼트의 무인수 생성자를 호출합니다.따라서 생성자에게 과부하를 주는 것은 해결책이 아닙니다.

여전히 생성자를 사용하는 것은 꽤 가능합니다.이러한 이유를 확인하려면 먼저 위의 해결 방법이 Android에서 사용되는 이유를 확인해야 합니다.

조각을 사용하려면 먼저 인스턴스가 필요합니다.는 안로이콜드라고 .YourFragment()(no 인수 생성자) fragment의 인스턴스를 생성합니다.여기서 사용자가 작성한 오버로드된 생성자는 무시됩니다. Android는 어떤 생성자를 사용할지 알 수 없기 때문입니다.

활동 기간 동안 위와 같이 단편이 생성되고 Android에 의해 여러 번 파괴됩니다.즉, fragment 객체 자체에 데이터를 넣으면 fragment가 파괴되면 데이터가 손실됩니다.

방법을 찾기 위해 는 문제해는위 Android다음을 사용하여 합니다.Bundle)로 표시됩니다.setArguments() 수 .YourFragment.논쟁bundles는 Android에 의해 보호되므로 영구적으로 유지됩니다.

이 번들을 설정하는 한 가지 방법은 정적을 사용하는 것입니다.newInstance방법:

public static YourFragment newInstance (int data) {
    YourFragment yf = new YourFragment()
    /* See this code gets executed immediately on your object construction */
    Bundle args = new Bundle();
    args.putInt("data", data);
    yf.setArguments(args);
    return yf;
}

그러나 생성자:

public YourFragment(int data) {
    Bundle args = new Bundle();
    args.putInt("data", data);
    setArguments(args);
}

정확히 같은 일을 할 수 있습니다.newInstance방법.

당연히, 이것은 실패할 것이고, 이것이 안드로이드가 당신이 사용하기를 원하는 이유 중 하나입니다.newInstance방법:

public YourFragment(int data) {
    this.data = data; // Don't do this
}

다음은 Android의 Fragment Class입니다.

/**
 * Supply the construction arguments for this fragment.  This can only
 * be called before the fragment has been attached to its activity; that
 * is, you should call it immediately after constructing the fragment.  The
 * arguments supplied here will be retained across fragment destroy and
 * creation.
 */
public void setArguments(Bundle args) {
    if (mIndex >= 0) {
        throw new IllegalStateException("Fragment already active");
    }
    mArguments = args;
}

Android는 구성 시에만 인수를 설정할 것을 요청하고 이러한 인수가 유지될 것을 보장합니다.

편집: @JHH의 코멘트에서 지적한 것처럼, 만약 당신이 몇몇 인수를 필요로 하는 사용자 정의 생성자를 제공한다면, 자바는 당신의 fragment에 no arg 기본 생성자를 제공하지 않을 입니다.따라서 이를 위해서는 noarg 생성자를 정의해야 합니다. 이는 다음을 사용하여 피할 수 있는 코드입니다.newInstance공장법

편집: Android는 더 이상 fragment에 과부하 생성자를 사용하는 것을 허용하지 않습니다.다음을 사용해야 합니다.newInstance방법.

일부 코틀린 코드:

companion object {
    fun newInstance(first: String, second: String) : SampleFragment {
        return SampleFragment().apply {
            arguments = Bundle().apply {
                putString("firstString", first)
                putString("secondString", second)
            }
        }
    }
}

이를 통해 다음과 같은 주장을 제기할 수 있습니다.

val first: String by lazy { arguments?.getString("firstString") ?: "default"}
val second: String by lazy { arguments?.getString("secondString") ?: "default"}

저는 Yydi의 대답에 동의하지 않습니다.

안드로이드가 나중에 프래그먼트를 재생성하기로 결정하면, 프래그먼트의 무인수 생성자를 호출합니다.따라서 생성자에게 과부하를 주는 것은 해결책이 아닙니다.

저는 이것이 해결책이고 좋은 해결책이라고 생각합니다, 이것이 바로 자바 핵심 언어에 의해 개발된 이유입니다.

이 Android를 하고 재생성할 수 있다는 것은 사실입니다.Fragment이렇게 할 수 있습니다.

public MyFragment() {
//  An empty constructor for Android System to use, otherwise exception may occur.
}

public MyFragment(int someInt) {
    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    setArguments(args);
}

그것은 당신이 당길 수 있게 해줄 것입니다.someInt부터getArguments()나중에, 설령 그렇다 하더라도.Fragment시스템에 의해 다시 생성되었습니다.이것은 보다 우아한 해결책입니다.static시공자

내 의견으로는static생성자는 쓸모가 없으므로 사용해서는 안 됩니다.또한 나중에 이것을 연장하고 싶다면 그들은 당신을 제한할 것입니다.Fragment생성자에 더 많은 기능을 추가할 수 있습니다.와 함께static생성자 당신은 이것을 할 수 없습니다.

업데이트:

Android는 기본값이 아닌 모든 생성자에 오류 플래그를 표시하는 검사를 추가했습니다.
위에서 언급한 이유로 인해 사용하지 않도록 설정하는 것이 좋습니다.

최근에 왔습니다.하지만 제가 방금 알고 있는 것들이 당신에게 조금 도움이 될 수도 있습니다.

만약 당신이 자바를 사용하고 있다면, 크게 변경할 것이 없습니다.그러나 코틀린 개발자들을 위해, 다음과 같은 몇 가지 정보가 있습니다. 실행할 수 있는 기반이 될 수 있습니다.

  • 상위 조각:
inline fun <reified T : SampleFragment> newInstance(text: String): T {
    return T::class.java.newInstance().apply {
        arguments = Bundle().also { it.putString("key_text_arg", text) }
    }
}
  • 정상 통화
val f: SampleFragment = SampleFragment.newInstance("ABC")
// or val f = SampleFragment.newInstance<SampleFragment>("ABC")
  • 하위 조각 클래스에서 상위 init 작업을 다음과 같이 확장할 수 있습니다.
fun newInstance(): ChildSampleFragment {
    val child = UserProfileFragment.newInstance<ChildSampleFragment>("XYZ")
    // Do anything with the current initialized args bundle here
    // with child.arguments = ....
    return child
}

해피 코딩.

Android에서 인수가 있는 fragment를 인스턴스화하는 가장 좋은 방법은 fragment에 정적 팩토리 메서드를 포함하는 것입니다.

public static MyFragment newInstance(String name, int age) {
    Bundle bundle = new Bundle();
    bundle.putString("name", name);
    bundle.putInt("age", age);

    MyFragment fragment = new MyFragment();
    fragment.setArguments(bundle);

    return fragment;
}

fragment의 인스턴스로 필드를 설정하지 않아야 합니다.왜냐하면 안드로이드 시스템이 당신의 단편을 재생성할 때마다, 만약 시스템이 더 많은 메모리를 필요로 한다고 느낀다면, 그것은 어떠한 인수도 없이 생성자를 사용하여 당신의 단편을 재생성할 것이기 때문입니다.

인수를 사용하여 조각을 인스턴스화하는 모범 사례에 대한 자세한 내용은 여기에서 확인할 수 있습니다.

베스트 프랙티스에 대한 질문 이후로, 일부 REST 웹 서비스로 작업할 때 fragment를 생성하기 위해 하이브리드 접근 방식을 사용하는 것이 매우 좋은 아이디어라고 덧붙이고 싶습니다.

사용자 조각을 표시하는 경우와 같은 복잡한 개체, 예를 들어 일부 사용자 모델을 전달할 수 없습니다.

하지만 우리가 할 수 있는 것은, 우리가 할 수 있는 것은,onCreate그 사용자!=을(를) 선택한 다음, 그렇지 않으면 데이터 계층에서 가져와 기존을 사용합니다.

이러한 방식으로 Android에 의한 조각 재생성의 경우 userId로 재생성하는 기능과 사용자 작업을 위한 스냅성을 모두 얻을 수 있을 뿐만 아니라 개체 자체 또는 개체 ID만 보유하여 조각을 생성하는 기능도 얻을 수 있습니다.

이와 같은 것:

public class UserFragment extends Fragment {
    public final static String USER_ID="user_id";
    private User user;
    private long userId;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        userId = getArguments().getLong(USER_ID);
        if(user==null){
            //
            // Recreating here user from user id(i.e requesting from your data model,
            // which could be services, direct request to rest, or data layer sitting
            // on application model
            //
             user = bringUser();
        }
    }

    public static UserFragment newInstance(User user, long user_id){
        UserFragment userFragment = new UserFragment();
        Bundle args = new Bundle();
        args.putLong(USER_ID,user_id);
        if(user!=null){
            userFragment.user=user;
        }
        userFragment.setArguments(args);
        return userFragment;

    }

    public static UserFragment newInstance(long user_id){
        return newInstance(null,user_id);
    }

    public static UserFragment newInstance(User user){
        return newInstance(user,user.id);
    }
}

이 코드를 사용하여 문제를 100% 해결합니다.

firstFragment에 이 코드를 입력합니다.

public static yourNameParentFragment newInstance() {

    Bundle args = new Bundle();
    args.putBoolean("yourKey",yourValue);
    YourFragment fragment = new YourFragment();
    fragment.setArguments(args);
    return fragment;
}

이 샘플은 부울 데이터를 보냅니다.

그리고 Second Fragment에서.

yourNameParentFragment name =yourNameParentFragment.newInstance();
   Bundle bundle;
   bundle=sellDiamondFragments2.getArguments();
  boolean a= bundle.getBoolean("yourKey");

첫 번째 조각의 값은 정적이어야 합니다.

행복 코드

  1. 이상적으로 fragment 생성자에서 아무것도 전달하지 않아야 하며, fragment 생성자는 비어 있거나 기본값이어야 합니다.
  2. 이제 두 번째 질문은 인터페이스 변수나 매개 변수를 전달하려면 어떻게 해야 할까요?
    1. 데이터를 전달하려면 번들을 사용해야 합니다.
    2. 인터페이스의 경우 다음과 같은 이점이 있습니다.putParceble를 구현하도록 .parceble
    3. 할 수 .OnAttach여기에는 맥락[(context) 청취자]가 있습니다.

변경 글꼴 변경)에 Activity 가 이동하지.uninitialize널 포인터 예외를 피할 수 있습니다.

fragment를 인스턴스화하는 가장 좋은 방법은 defaultFragment.instantiate 메서드를 사용하거나 fragment를 인스턴스화하는 팩토리 메서드를 만드는 것입니다.
주의: fragment 메모리를 복원하면 런타임 예외가 발생하지만 fragment 메모리는 항상 fragment에 빈 생성자를 만듭니다.

smth는 다음과 같이 사용할 수 있습니다.

val fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, YourFragment::class.java.name)

지금 이 대답은 더 이상 사용되지 않기 때문입니다.

코틀린 코드를 사용하여 조각의 인스턴스를 만듭니다.

활동 중 쓰기

val fragment = YourFragment.newInstance(str = "Hello",list = yourList)

조각으로 쓰기

fun newInstance(str: String, list: ArrayList<String>): Fragment {
        val fragment = YourFragment()
        fragment.arguments = Bundle().apply {
            putSerializable("KEY_STR", str)
            putSerializable("KEY_LIST", list)
        }
        return fragment
    }

동일한 조각을 사용하여 번들에서 데이터 검색

val str = arguments?.getString("KEY_STR") as? String
val list = arguments?.getSerializable("KEY_LIST") as? ArrayList<String>

setArguments()쓸모가 없습니다.엉망진창으로 만들 뿐입니다.

public class MyFragment extends Fragment {

    public String mTitle;
    public String mInitialTitle;

    public static MyFragment newInstance(String param1) {
        MyFragment f = new MyFragment();
        f.mInitialTitle = param1;
        f.mTitle = param1;
        return f;
    }

    @Override
    public void onSaveInstanceState(Bundle state) {
        state.putString("mInitialTitle", mInitialTitle);
        state.putString("mTitle", mTitle);
        super.onSaveInstanceState(state);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
        if (state != null) {
            mInitialTitle = state.getString("mInitialTitle");
            mTitle = state.getString("mTitle");
        } 
        ...
    }
}

저는 이것에 대한 훨씬 더 간단한 해결책이 있다고 믿습니다.

public class MyFragment extends Fragment{

   private String mTitle;
   private List<MyObject> mObjects;

   public static MyFragment newInstance(String title, List<MyObject> objects)
   MyFragment myFrag = new MyFragment();
   myFrag.mTitle = title;
   myFrag.mObjects = objects;
   return myFrag;
   }

언급URL : https://stackoverflow.com/questions/9245408/best-practice-for-instantiating-a-new-android-fragment