๊ฐœ๋ฐœ/Android

[Android] Live Data

๋„๋ฆฌ ๐ŸŸ 2021. 4. 8. 22:43

์ž‘์„ฑ์ผ: 2017.07.09


LiveData ๋Š” ๊ฐ’์„ ์œ ์ง€ํ•˜๊ณ , ์ด ๊ฐ’์ด observed ์ƒํƒœ๋ฅผ ๊ฐ–๊ฒŒ ํ•ด์ฃผ๋Š” data holder ํด๋ž˜์Šค์ด๋‹ค.
์ผ๋ฐ˜์ ์ธ Observerble๊ณผ ๋‹ฌ๋ฆฌ LiveData๋Š” ์•ฑ ์ปดํฌ๋„ŒํŠธ์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๋”ฐ๋ฅธ๋‹ค.

 

LiveData๋ฅผ ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ์— importํ•˜๋Š” ๋ฐฉ๋ฒ•์€ adding components to your project 
LiveData๋Š” Observer์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด STARTED ๋˜๋Š” RESUMED ์ƒํƒœ์ผ ๋•Œ๋งŒ Observer๋ฅผ ํ™œ์„ฑํ™” ์ƒํƒœ๋กœ ์—ฌ๊ธด๋‹ค.

Location Sample

public class LocationLiveData extends LiveData<Location> {
    private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    public LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}

 

  •  onActive() 
    • LiveData๊ฐ€ active observer๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค. 
      ๋””๋ฐ”์ด์Šค์˜ location ์—…๋ฐ์ดํŠธ ์ •๋ณด observing์„ ์‹œ์ž‘ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
  •  onInactive() 
    • LiveData๊ฐ€ active observer๋ฅผ ๋”์ด์ƒ ๊ฐ€์ง€์ง€ ์•Š์„ ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค. 
      ์–ด๋–ค observer๋„ ์—†์œผ๋‹ˆ LocationManager ์„œ๋น„์Šค์™€ ์—ฐ๊ฒฐ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. 
      ์ด๋Ÿฌํ•œ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ฐฐํ„ฐ๋ฆฌ๋ฅผ ์†Œ๋ชจํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๋‹ค.
  •  setValue() 
    • LiveData์˜ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ  active observer๋“ค์—๊ฒŒ ๋ณ€ํ™”๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.

์œ„์˜ Sample LocationLiveData ์‚ฌ์šฉ ์˜ˆ

public class MyFragment extends LifecycleFragment {
    public void onActivityCreated (Bundle savedInstanceState) {
        LiveData<Location> myLocationListener = ...;
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.addObserver(this, location -> {
                    // update UI
                });
            }
        });
    }
}

addObserver()์˜ ์ฒซ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ LifecycleOwner๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. 
์ด observer๊ฐ€ LifecycleOwner์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๋”ฐ๋ฅธ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

  • ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด active state(STARTED or RESUMED)๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด, ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด๋„ observer๋Š” ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด destoryed ๋˜๋ฉด, observer๋Š” ์ž๋™์œผ๋กœ ์ œ๊ฑฐ๋œ๋‹ค.

๋ผ์ดํ”„ ์‚ฌ์ดํด ๊ธฐ๋ฐ˜์ด๋ผ๋Š” LiveData์˜ ์žฅ์ ์€ LiveData๋ฅผ ์—ฌ๋Ÿฌ ์•กํ‹ฐ๋น„ํ‹ฐ, ํ”„๋ž˜๊ทธ๋จผํŠธ ๋“ฑ ๊ฐ„์— ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. 

LiveData๋ฅผ singleton์œผ๋กœ ๋งŒ๋“œ๋Š” ์˜ˆ

public class LocationLiveData extends LiveData<Location> {
    private static LocationLiveData sInstance;
    private LocationManager locationManager;

    @MainThread
    public static LocationLiveData get(Context context) {
        if (sInstance == null) {
            sInstance = new LocationLiveData(context.getApplicationContext());
        }
        return sInstance;
    }

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    private LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}

ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ ์‚ฌ์šฉํ•  ๋•Œ๋Š” :

public class MyFragment extends LifecycleFragment {
    public void onActivityCreated (Bundle savedInstanceState) {
        Util.checkUserStatus(result -> {
            if (result) {
                LocationLiveData.get(getActivity()).observe(this, location -> {
                   // update UI
                });
            }
        });
  }
}

 

LiveData์˜ ์žฅ์ ๋“ค

  • No memory leaks
    • Observer๋“ค์ด ๊ฐ๊ฐ ์ž์‹ ์˜ Lifecycle์„ ๋”ฐ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— Lifecycle์ด destroyed ๋  ๋•Œ ๊ทธ๋“ค์€ ์ž๋™์œผ๋กœ ์ •๋ฆฌ๋œ๋‹ค.
  • No crashes due to stopped activities 
    • Observer์˜ Lifecycle ์ด ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ์ธ ๊ฒฝ์šฐ(์˜ˆ, ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ back stack์— ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ), ๊ทธ๋“ค์€ ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค.
  • Always up to date data
    • Lifecycle์ด ์žฌ์‹œ์ž‘๋˜๋Š” ๊ฒฝ์šฐ(์˜ˆ, back stack์— ์žˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์‹œ์ž‘๋˜๋Š” ๊ฒฝ์šฐ), ๊ฐ€์žฅ ์ตœ์‹ ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
  • Proper configuration change
    • ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ configuration ๋ณ€๊ฒฝ์œผ๋กœ ๋‹ค์‹œ ๋งŒ๋“ค์–ด์ง€๋Š” ๊ฒฝ์šฐ(์˜ˆ, ๋””๋ฐ”์ด์Šค ํ™”๋ฉด ํšŒ์ „), ์ฆ‰์‹œ ์ตœ๊ทผ์˜ ์œ ํšจํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ฒŒ ๋œ๋‹ค.
  • Sharing Resources
    • LiveData๋ฅผ singleton์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๊ณ , ์‹œ์Šคํ…œ ์„œ๋น„์Šค์— ๋‹จ ํ•œ๋ฒˆ๋งŒ ์—ฐ๊ฒฐํ•˜๋ฉด ๋˜๋ฉฐ, ์•ฑ ๋‚ด์˜ ๋ชจ๋“  observer๋ฅผ ์ง€์›ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • No more manual lifecycle handling
    • ์ด์ œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋“ค์€ ํ•„์š”ํ•  ๋•Œ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ observe ํ•˜๋ฉฐ, ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์ค‘์ง€๋˜์—ˆ์„ ๋•Œ observing์„ ์ค‘์ง€ / ์‹œ์ž‘ํ• ์ง€ ๊ฑฑ์ •ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
    • ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์ž์‹ ์˜ Lifecycle ์„ observing ๋™์•ˆ ์ œ๊ณตํ•˜๋ฏ€๋กœ, LiveData๋Š” ์ž๋™์œผ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

[์ฐธ๊ณ ]
Android developers