[Android] FragmentFactory

๐Ÿ’กFragmentFactory์— ๋Œ€ํ•˜์—ฌ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ๊ธฐ๋กํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

FragmentFactory

  • Android์—์„œ Fragment ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ์ ์œผ๋กœ Android Fragment๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ ์—†๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋กœ ์ƒ์„ฑํ•˜์ง€๋งŒ, ๊ฒฝ์šฐ์— ๋”ฐ๋ผ Fragment๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์˜์กด์„ฑ์ด๋‚˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ฃผ์ž…ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • FragmentFactory๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Fragment์˜ ์ƒ์„ฑ ๋ฐฉ์‹์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ViewModel ๋˜๋Š” Repository์™€ ๊ฐ™์€ ์˜์กด์„ฑ์„ Fragment์— ์ฃผ์ž…ํ•ด์•ผ ํ•  ๋•Œ FragmentFactory๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ์ž์— ํ•„์š”ํ•œ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Fragment ์ƒ์„ฑ์ž

  • ์•„๋ž˜์™€ ๊ฐ™์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š” Fragment๋ฅผ ์ œ์ž‘ํ•  ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
class MainFragment constructor(
    private val tag: String,
): Fragment()

RuntimeException

  • Fragment ์ƒ์„ฑ์ž๋ฅผ ์ฐพ์ง€ ๋ชปํ•œ๋‹ค๋Š” ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
java.lang.InstantiationException: Unable to instantiate fragment
  • ๊ณต์‹๋ฌธ์„œ์—์„œ๋Š” Fragment๋Š” ์ธ์ž๊ฐ€ ํ•˜๋‚˜๋„ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ํ•„์ˆ˜๋กœ ํฌํ•จ๋˜์–ด์•ผํ•œ๋‹ค๊ณ  ๋ช…์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

Fragment  |  Android Developers

 

Fragment  |  Android Developers

 

developer.android.com

All subclasses of Fragment must include a public no-argument constructor. The framework will often re-instantiate a fragment class when needed, in particular during state restore, and needs to be able to find this constructor to instantiate it. If the no-argument constructor is not available, a runtime exception will occur in some cases during state restore.

๋ฐœ์ƒ ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ?

  • Fragment๋Š” ์ƒ๋ช…์ฃผ๊ธฐ์— ๋”ฐ๋ผ์„œ ์•ˆ๋“œ๋กœ์ด๋“œ ๋‚ด๋ถ€์—์„œ ํŒŒ๊ดด์™€ ์ƒ์„ฑ์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.
    • ํ™”๋ฉด ํšŒ์ „, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒํƒœ์™€๋„ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ณต์› ๊ณผ์ •์—์„œ FragmentManager์— ์˜ํ•ด์„œ Fragment๋ฅผ ๋ณต์›ํ•˜๊ฑฐ๋‚˜ Bundle์„ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ๋ณต์›ํ•  ๋•Œ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ๋•Œ ํŒŒ๊ดด ํ›„ ์žฌ์ƒ์„ฑ๋˜๋Š” ๋‹จ๊ณ„์—์„œ ๋นˆ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋ฉฐ, ๋นˆ ์ƒ์„ฑ์ž๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๊ฒŒ ๋˜์–ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Instantiate

public static Fragment instantiate(@NonNull Context context, @NonNull String fname,
            @Nullable Bundle args) {
        try {
            Class<? extends Fragment> clazz = FragmentFactory.loadFragmentClass(
                    context.getClassLoader(), fname);
            Fragment f = clazz.getConstructor().newInstance();
            if (args != null) {
                args.setClassLoader(f.getClass().getClassLoader());
                f.setArguments(args);
            }
            return f;
        } 
        ...
    }
  • FragmnetFactory.loadFragmentClass()๋Š” getConstructor()๋กœ ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ ธ์™€ newInstance()๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ์ƒ์„ฑ ๋œ Fragment ์ธ์Šคํ„ด์Šค์— ์ „๋‹ฌํ•  Argument๋ฅผ ์„ค๋ช…ํ•˜๊ณ  ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ๋•Œ getConstructor() ๊ณผ์ •์—์„œ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†์œผ๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ง‘๋‹ˆ๋‹ค.

FragmentFactory๋ฅผ ํ™œ์šฉํ•œ ์˜์กด์„ฑ ์ฃผ์ž…

  • ์˜์กด์„ฑ ์ฃผ์ž…์ด๋‚˜ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ FragmentFactory๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Fragment๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ด ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด์„œ Fragment์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†๋”๋ผ๋„ ์ปค์Šคํ…€ ํŒฉํ† ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ ๊ณผ์ •์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
class MyFragment(private val myDependency: MyDependency) : Fragment() {
    // Fragment logic
}

class MyFragmentFactory(private val myDependency: MyDependency) : FragmentFactory() {
    override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
        return when (className) {
            MyFragment::class.java.name -> MyFragment(myDependency)
            else -> super.instantiate(classLoader, className)
        }
    }
}
  • ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๋”๋ผ๋„ FragmentFactory๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ ์ฃผ์ž…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Activity์—์„œ FragmentFactory ์ƒ์„ฑ

  • ์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ FragmentFactory๋ฅผ ์„ค์ •ํ•˜์—ฌ FragmentManager๊ฐ€ Fragment๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ปค์Šคํ…€ ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // FragmentFactory๋ฅผ ์„ค์ •
        val myDependency = MyDependency()
        supportFragmentManager.fragmentFactory = MyFragmentFactory(myDependency)

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Fragment ์ถ”๊ฐ€
        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .replace(R.id.fragment_container, MyFragment::class.java, null)
                .commitNow()
        }
    }
}

์ •๋ฆฌ

  • ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†๋Š” Fragment๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์•ˆ๋“œ๋กœ์ด๋“œ ์‹œ์Šคํ…œ์ด Fragment๋ฅผ ์žฌ์ƒ์„ฑํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • FragmentFactory๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ†ตํ•ด Fragment๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์‹œ์Šคํ…œ์—์„œ ์žฌ์ƒ์„ฑํ•  ๋•Œ๋„ ๋ฌธ์ œ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ 

https://developer.android.com/reference/kotlin/androidx/fragment/app/FragmentFactory

https://sonseungha.tistory.com/657