48、Lifecycle组件:LifecycleOwner、LifecycleObserver、自定义生命周期感知组件

说实话,Android开发里最让人头疼的问题之一,就是生命周期管理。我记得刚入行那会儿,经常在Activity的onDestroy里忘记解注册,结果内存泄漏找上门来。后来Google推出了Lifecycle组件,这玩意儿说白了就是帮我们自动感知生命周期,再也不用手动去写那些又臭又长的回调了。

今天我们就来聊聊Lifecycle组件的核心三件套:LifecycleOwner、LifecycleObserver,以及如何自定义生命周期感知组件。我会结合我自己的踩坑经历,把这块内容讲透。

一、LifecycleOwner:谁拥有生命周期?

LifecycleOwner是一个接口,只有一个方法——getLifecycle()。谁实现了这个接口,谁就拥有了生命周期管理能力。AppCompatActivity和Fragment默认就实现了它,所以我们直接用就行。

但这里有个坑:自定义View如果也想成为LifecycleOwner,需要自己实现。我曾经在一个自定义相机预览View里踩过这个坑,因为没正确处理生命周期,导致相机资源释放不及时,引发了一系列诡异问题。

核心要点:LifecycleOwner负责分发生命周期事件,它内部维护了一个LifecycleRegistry对象。

来看一个自定义LifecycleOwner的例子:

public class MyLifecycleOwner implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;

    public MyLifecycleOwner() {
        lifecycleRegistry = new LifecycleRegistry(this);
    }

    @Override
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }

    // 手动触发生命周期事件
    public void onCreate() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    }

    public void onStart() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
    }

    public void onResume() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
    }

    public void onPause() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
    }

    public void onStop() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
    }

    public void onDestroy() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
    }
}

嗯,这里要注意:LifecycleRegistry是线程安全的,但事件分发顺序必须正确。你不能在ON_CREATE之前就发ON_START,否则会抛异常。

二、LifecycleObserver:如何监听生命周期?

LifecycleObserver是一个标记接口,本身没有方法。真正起作用的是配合注解或者DefaultLifecycleObserver使用。

我个人习惯用DefaultLifecycleObserver,因为它是Java 8+的推荐方式,不用反射,性能更好。

public class MyObserver implements DefaultLifecycleObserver {
    private static final String TAG = "MyObserver";

    @Override
    public void onCreate(LifecycleOwner owner) {
        Log.d(TAG, "onCreate: 组件创建了");
    }

    @Override
    public void onStart(LifecycleOwner owner) {
        Log.d(TAG, "onStart: 组件可见了");
    }

    @Override
    public void onResume(LifecycleOwner owner) {
        Log.d(TAG, "onResume: 组件可交互了");
    }

    @Override
    public void onPause(LifecycleOwner owner) {
        Log.d(TAG, "onPause: 组件暂停了");
    }

    @Override
    public void onStop(LifecycleOwner owner) {
        Log.d(TAG, "onStop: 组件不可见了");
    }

    @Override
    public void onDestroy(LifecycleOwner owner) {
        Log.d(TAG, "onDestroy: 组件销毁了");
    }
}

你想想看,有了这个Observer,我们只需要在Activity里这样注册:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

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

是不是很清爽?再也不用手动在onResume里开启定位、在onPause里关闭定位了。Observer自己就能感知到。

小技巧:如果你用的是Java 7或者需要兼容旧版本,可以用注解方式:@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)。但注意,这种方式基于反射,性能略差。

三、自定义生命周期感知组件

这才是今天的重头戏。什么叫生命周期感知组件?说白了,就是组件自己能感知到宿主的生命周期,自动做该做的事。

我曾经写过一个位置监听组件,需要在Activity可见时开始定位,不可见时停止定位。用传统方式,我得在Activity里写一堆模板代码。用Lifecycle组件后,代码变成了这样:

public class LocationManager implements DefaultLifecycleObserver {
    private Context context;
    private LocationListener listener;

    public LocationManager(Context context, LocationListener listener) {
        this.context = context;
        this.listener = listener;
    }

    @Override
    public void onResume(LifecycleOwner owner) {
        startLocationUpdates();
    }

    @Override
    public void onPause(LifecycleOwner owner) {
        stopLocationUpdates();
    }

    private void startLocationUpdates() {
        // 实际的位置请求代码
        Log.d("LocationManager", "开始定位...");
    }

    private void stopLocationUpdates() {
        // 停止定位
        Log.d("LocationManager", "停止定位...");
    }

    public interface LocationListener {
        void onLocationChanged(double latitude, double longitude);
    }
}

然后在Activity里:

public class MapActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);

        LocationManager locationManager = new LocationManager(this, 
            (lat, lng) -> {
                // 更新地图位置
            });
        getLifecycle().addObserver(locationManager);
    }
}

看到了吗?Activity里一行生命周期代码都没写,但定位组件却能在正确的时机开启和关闭。这就是生命周期感知的魅力。

避坑指南:我曾经在自定义组件里直接持有Activity的引用,结果导致内存泄漏。正确的做法是:组件只依赖LifecycleOwner接口,不要依赖具体的Activity或Fragment。这样既解耦,又安全。

四、生命周期状态与事件的关系

为了让你更清楚地理解Lifecycle的工作机制,我画了一张图:

Lifecycle 状态与事件转换图 INITIALIZED CREATED STARTED RESUMED DESTROYED ON_CREATE ON_START ON_DESTROY ON_RESUME ON_PAUSE ON_STOP 事件(前进) 事件(后退)

这张图展示了Lifecycle的五个状态和六个事件。状态是当前所处的生命周期阶段,事件则是触发状态转换的动作。举个例子:当Activity执行onCreate时,Lifecycle会发出ON_CREATE事件,状态从INITIALIZED变为CREATED。

这里有个关键点:状态是当前所处的阶段,事件是正在发生的动作。Observer监听的是事件,而Owner管理的是状态。

五、实战:封装一个生命周期感知的倒计时组件

最后,我分享一个我自己项目里用过的倒计时组件。它能在Activity可见时倒计时,不可见时暂停,再次可见时继续。完全不用在Activity里写任何生命周期代码。

public class LifecycleCountDown implements DefaultLifecycleObserver {
    private CountDownTimer timer;
    private long totalMillis;
    private long remainingMillis;
    private OnTickListener listener;
    private boolean isPaused = false;

    public LifecycleCountDown(long totalMillis, OnTickListener listener) {
        this.totalMillis = totalMillis;
        this.remainingMillis = totalMillis;
        this.listener = listener;
    }

    @Override
    public void onResume(LifecycleOwner owner) {
        if (isPaused && remainingMillis > 0) {
            startTimer();
        }
    }

    @Override
    public void onPause(LifecycleOwner owner) {
        if (timer != null) {
            timer.cancel();
            isPaused = true;
        }
    }

    @Override
    public void onDestroy(LifecycleOwner owner) {
        if (timer != null) {
            timer.cancel();
        }
    }

    public void start() {
        startTimer();
    }

    private void startTimer() {
        timer = new CountDownTimer(remainingMillis, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                remainingMillis = millisUntilFinished;
                if (listener != null) {
                    listener.onTick(millisUntilFinished);
                }
            }

            @Override
            public void onFinish() {
                remainingMillis = 0;
                if (listener != null) {
                    listener.onFinish();
                }
            }
        }.start();
        isPaused = false;
    }

    public interface OnTickListener {
        void onTick(long millisUntilFinished);
        void onFinish();
    }
}

使用方式:

LifecycleCountDown countDown = new LifecycleCountDown(60000, 
    new LifecycleCountDown.OnTickListener() {
        @Override
        public void onTick(long millisUntilFinished) {
            textView.setText("剩余:" + millisUntilFinished / 1000 + "秒");
        }

        @Override
        public void onFinish() {
            textView.setText("倒计时结束");
        }
    });
getLifecycle().addObserver(countDown);
countDown.start();

这个组件我用了好几年,从来没出过内存泄漏的问题。核心思想就一句话:让组件自己管理自己的生命周期行为,宿主只负责注册

总结一下:Lifecycle组件把我们从繁琐的生命周期管理中解放了出来。LifecycleOwner提供生命周期源,LifecycleObserver监听生命周期事件,两者结合就能做出各种优雅的自定义组件。记住,好的架构设计,就是让代码自己管好自己。


公众号:蓝海资料掘金营,微信deep3321