code

2018年6月21日 星期四

Android Architecture Components - Life Cycle Aware Components

簡介

這是Android官方推薦“正確寫一個Android App"的方法,這個官方推薦的方法由一些非常基本library以及pattern組成,稱為Architecture components,包括以下:

Lifecycles: 每個app必考慮的東西
Lifecycle-aware observables: 觀察lifecycles的方法
Lightweight ViewModel: 這是獨立於Activity和Fragment之外,可以單獨測試邏輯之處
Object mapping for sqlite


要解決什麼問題?

通常programmer把所有的邏輯(商業/UI/Data/與OS互動等)都寫在activity或是fragment中,不過activity事實上是設計來操縱UI與OS互動,越簡單越能避免life cycle造成的問題,主要是因為activity / fragment 這類型的class,programmer並沒有絕對掌控權,從instance creation到destruction都是OS決定,所以要盡量減少對這些class的dependency。

此外model應該永遠獨立於view之外,永遠不受到OS相關決定(回收記憶體之類)的影響。


Life-cycle Aware Components

我們通常會把某些邏輯或是object寫在一個activity或是fragment裡面,應且在life cycle callback中作出對應的動作。例如以下MyLocationListener instance會在MyActivity的onStart()和onStop() 時也去做start() / stop() 動作:

class MyLocationListener {
    public MyLocationListener(Context context, Callback callback) {
        // ...
    }

    void start() {
        // connect to system location service
    }

    void stop() {
        // disconnect from system location service
    }
}

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    @Override
    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, (location) -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        myLocationListener.start();
        // manage other components that need to respond
        // to the activity lifecycle
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

但是如果有很多類似的component在這個activity裡面,那他的life cycle callbacks就會充滿這類code,變得複雜難maintain。

此外我們不能保證async operations會在我們要的life cycle callbacks回來:

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, location -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start();
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
    }
}
可以看到在onStart()中,此myLocationListener要等待某個operation result回來為true才會啟動,但是有可能此Activity onStop()先發生了,然後此operation result才回來,所以又啟動了這個myLocationListener。這有可能造成了這個listener在我們未預期的狀況下活動。

android.arch.lifecycle提供了一些design pattern來幫助我們免於煩這些(鳥)事。


Life Cycle

LifeCycle這個class把某個有life cycle概念的component (e.g. Activity / Fragment / Service) 的life cycle給抽象化了,它有states和events:



所以對這個component life cycle有興趣的人,就可以implement LifeCycleObserver:

public class MyObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void connectListener() {
        ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void disconnectListener() {
        ...
    }
}

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());


Life Cycle Owner

擁有LifeCycle的components必須implement LifeCycleOwner interface (AppCompatActivity的某個super class是implement這個interface的),所以最快的讓自己的activity或是fragment變成life cycle owner就是去繼承有implement這個interface的base class:
class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
            // update UI
        });
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.enable();
            }
        });
  }
}
剛剛的MyLocationListener就可以implement LifeCycleObserver:

class MyLocationListener implements LifecycleObserver {
    private boolean enabled = false;
    public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
       ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void start() {
        if (enabled) {
           // connect
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
            // connect if not connected
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void stop() {
        // disconnect if connected
    }
}

可以看到MyLocationListener並沒有override什麼interface method,而是依賴於annotations。我們說MyLocationListener是一個life cycle aware object


如果不繼承已知的life cycle owner class的話,也可以自己去implement LifeCycleOwner interface,但是要透過以下的templates:

public class MyActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry mLifecycleRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mLifecycleRegistry = new LifecycleRegistry(this);
        mLifecycleRegistry.markState(Lifecycle.State.CREATED);
    }

    @Override
    public void onStart() {
        super.onStart();
        mLifecycleRegistry.markState(Lifecycle.State.STARTED);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
}


沒有留言:

張貼留言