Lifecycle, LifecycleOwner, LifecycleObserver类讲解

最近谷歌安卓团队推出一堆的组件开发架构,方便程序开发者编写更健壮,更安全,更简洁的代码,但是想要熟练地应用它们还是需要学习框架的原理。

Lifecycles的目的就是安卓组件(activities, fragments)在发生状态变化(onStart, onResume)的时候,其它的部分能够相应组件的变化。一个很常见的例子就是位置传感器要把位置实时传递到UI界面上,那么需要在activities onCreate()的状态的时候创建位置传感器,在onStart()的时候开启位置传感器,在onStop的时候停止位置传感器。

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
    }
}

代码看上去没有什么问题,但是在真实的例子中,很有很多的监听需要根据状态去更新UI界面,而且有时候onStop可能出现出现在onStart完成之前,导致有些监听的不正确执行。

所以想出来Lifecycle这个框架,它会保存组件的状态信息,允许其它的对象观察这些状态。要理解这个Lifecycle框架,最好知道观察者模式是怎么回事,可以在网上找相关的例子进行查看。

比如有两个人需要知道天气预报的情况,这两个人可以用Observer表示,监听的的天气预报就是State, Owner就是管理这些State变化的。那么在activity中,owener是activity实体,state就是activity的状态,observer就是想要知道变化的对象。

从上图可以看到有五种状态,INITIALIZED, DESTROYED, CREATED, STARTED, RESUME,对象owner只需要被owner加入到观察对象就能感知这些变化,具体原理查看观察者模型。

因此,三者Owner, State, Observer只需要一一对应就可。

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;
    }
}

Owner通过LifecycleRegistry进行注册,就可以发送状态发生变化的广播。Android中如果继承AppCompatActivity就可以获得相应的Lifecycle,所以两种方式随意选择。

package com.android.guide.archcomponents;

import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;

import com.android.guide.R;

/**
 * By using lifecycle-aware components,
 * you can move the code of dependent components out of the lifecycle
 * methods and into the components themselves.
 *
 * The android.arch.lifecycle package provides classes and interfaces that let
 * you build lifecycle-aware components—which are components that can automatically adjust
 * their behavior based on the current lifecycle state of an activity or fragment.
 */

public class LifecycleEvent extends AppCompatActivity {

    private static final int REQUEST_LOCATION_PERMISSION_CODE = 1;

    private LocationListener mGpsListener = new MyLocationListener();

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

        setContentView(R.layout.textview);

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.ACCESS_COARSE_LOCATION},
                    REQUEST_LOCATION_PERMISSION_CODE);
        } else {
            bindLocationListener();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED
                && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
            bindLocationListener();
        } else {
            Toast.makeText(this, "This sample requires Location access", Toast.LENGTH_LONG).show();
        }
    }

    private void bindLocationListener() {
        BoundLocationManager.bindLocationListenerIn(this, mGpsListener, getApplicationContext());
    }

    private class MyLocationListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            TextView textView = findViewById(R.id.text_view);
            textView.setText(location.getLatitude() + ", " + location.getLongitude());
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {
            Toast.makeText(LifecycleEvent.this, "Provider enabled: " + provider,
                    Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onProviderDisabled(String provider) {
            Toast.makeText(LifecycleEvent.this, "Provider disabled: " + provider,
                    Toast.LENGTH_SHORT).show();
        }
    }
}

编写一个LocationManager的实现,将它传递到Observer中,如果Observer监听到状态的变化,就会更新相关的UI,所以重新编写BoundLocationManager类。

package com.android.guide.archcomponents;
import android.annotation.SuppressLint;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;

public class BoundLocationManager {

    public static void bindLocationListenerIn(LifecycleOwner lifecycleOwner,
                                              LocationListener listener, Context context) {
        new BoundLocationListener(lifecycleOwner, listener, context);
    }

    static class BoundLocationListener implements LifecycleObserver {

        private final Context mContext;

        private LocationManager mLocationManager;

        private final LocationListener mListener;

        public BoundLocationListener(LifecycleOwner lifecycleOwner,
                                     LocationListener listener, Context context) {
            mContext = context;
            mListener = listener;

            // 把这个类加进去监听相关状态的变化,同时把结果返回给传递进来的监听器。
            lifecycleOwner.getLifecycle().addObserver(this);
        }

        @SuppressLint("MissingPermission")
        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        void addLocationListener() {

            mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
            mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                    0, 0, mListener);

            // Force an update with the last location, if available.
            Location lastLocation = mLocationManager.getLastKnownLocation(
                    LocationManager.GPS_PROVIDER);
            if (lastLocation != null) {
                mListener.onLocationChanged(lastLocation);
            }

        }

        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        void removeLocationListener() {
            if (mLocationManager == null) {
                return;
            }

            mLocationManager.removeUpdates(mListener);
            mLocationManager = null;
        }
    }
}

可以看到直接将mGpsListener的值传递到LocationManager中获取数据。

<think>嗯,用户之前问了关于withContext只能在协程或挂起函数中调用的问题,现在又转向询问LifecycleOwnerlifecycleScope属性。我需要先理解用户的需求。他们可能是在学习Kotlin协程,特别是与Android生命周期相关的部分。 首先,用户提供的代码片段是lifecycleScope的定义,属于AndroidX的Lifecycle KTX库。他们可能想知道这个属性的作用、用法以及背后的原理。用户之前的问题涉及协程的作用域和上下文切换,所以这次可能需要解释lifecycleScope如何与生命周期绑定,避免内存泄漏。 接下来,用户提到“CoroutineScope tied to this LifecycleOwner's Lifecycle.”,这说明lifecycleScope与组件的生命周期相关联,当Lifecycle被销毁时,协程作用域会被取消。需要强调自动取消的好处,比如防止在Activity或Fragment销毁后继续执行不必要的任务。 用户还提到“This scope is bound to Dispatchers.Main.immediate”,需要解释调度器的作用,Main.immediate意味着协程默认在主线程运行,适合UI操作。同时,用户可能需要知道如何切换调度器,比如使用withContext切换到IO线程进行网络请求。 用户提供的代码位置是androidx.lifecycle.LifecycleOwner.kt,说明他们可能在查看源码或文档,想要更深入的理解。可能需要说明如何在实际项目中使用lifecycleScope,比如在ViewModel或者Activity中启动协程。 可能的误区包括在非UI线程直接更新UI,或者忘记切换调度器导致主线程阻塞。需要提醒用户正确使用Dispatchers来切换线程,以及如何处理生命周期结束后的协程取消。 另外,用户可能需要示例代码来演示正确用法,比如在按钮点击时启动协程,或者在Repository层进行数据获取。同时,对比其他作用域,如viewModelScope,可以帮助用户理解不同场景下的选择。 总结来说,用户需要了解lifecycleScope的作用、如何正确使用它、以及背后的原理,包括生命周期绑定、协程取消和线程调度。确保回答结构清晰,分点说明,并提供实际示例和常见错误避免方法。</think>### 核心解释:`LifecycleOwner.lifecycleScope` 的作用与特性 `LifecycleOwner.lifecycleScope` 是 Android Jetpack 中 **协程与生命周期绑定** 的关键扩展属性,专为简化 Android 组件的协程管理而设计。以下是其核心要点: --- #### 1. **核心特性** | 特性 | 说明 | |------|------| | **生命周期绑定** | 协程作用域(`CoroutineScope`)与 `LifecycleOwner`(如 `Activity`/`Fragment`)的生命周期直接关联。当组件的 `Lifecycle` 进入 `DESTROYED` 状态时,作用域内所有未完成的协程将 **自动取消**,避免内存泄漏。 | | **默认调度器** | 协程默认运行在 `Dispatchers.Main.immediate` 调度器(主线程,立即执行)。适合直接操作 UI,例如更新 `TextView` 或 `RecyclerView`。 | | **结构化并发** | 通过 `lifecycleScope.launch` 启动的子协程会继承父作用域的上下文和取消逻辑,形成 **层级化任务管理**。 | --- #### 2. **典型使用场景** ```kotlin // 示例:在 Activity/Fragment 中发起网络请求 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 启动协程(默认在主线程) lifecycleScope.launch { // 切换到 IO 线程执行耗时操作 val data = withContext(Dispatchers.IO) { fetchDataFromApi() // 模拟网络请求 } // 自动切回主线程更新 UI textView.text = data } } } ``` --- #### 3. **关键原理** - **生命周期监听** `lifecycleScope` 内部通过 `Lifecycle` 的 `addObserver` 监听生命周期状态。当 `ON_DESTROY` 事件触发时,调用 `CoroutineScope.cancel()` 终止所有协程。 - **调度器绑定** 默认使用 `Dispatchers.Main.immediate` 意味着: - 协程体 **直接在主线程执行**(除非显式切换线程) - `immediate` 表示如果当前已在主线程,则 **立即执行** 协程代码,无需重新调度。 --- #### 4. **与其他作用域的对比** | 作用域 | 绑定对象 | 取消条件 | 适用场景 | |--------|----------|----------|----------| | `lifecycleScope` | `LifecycleOwner` | 组件销毁时 | UI 层(Activity/Fragment)的协程管理 | | `viewModelScope` | `ViewModel` | ViewModel 清除时 | 业务逻辑层(ViewModel)的协程管理 | | `GlobalScope` | 应用进程 | 永不自动取消 | **慎用**!容易导致内存泄漏 | --- #### 5. **常见问题与解决方案** **问题1:在 `lifecycleScope` 中执行耗时操作导致主线程卡顿** - **解决**:使用 `withContext(Dispatchers.IO)` 切换到 IO 线程: ```kotlin lifecycleScope.launch { val result = withContext(Dispatchers.IO) { /* 耗时操作 */ } updateUI(result) // 回到主线程 } ``` **问题2:协程未按预期取消** - **原因**:未正确绑定到 `lifecycleScope`,或手动创建了独立作用域。 - **解决**:始终通过 `lifecycleScope.launch` 启动协程,避免直接使用 `GlobalScope`。 --- ### 总结 - **核心价值**:`lifecycleScope` 实现了协程与 Android 生命周期的 **无缝集成**,开发者无需手动处理协程取消逻辑。 - **最佳实践**: - 在 `Activity`/`Fragment` 中优先使用 `lifecycleScope`。 - 耗时操作通过 `withContext` 切换到非主线程。 - 避免在 `lifecycleScope` 中启动 **长时间运行且与 UI 无关** 的任务(应使用 `viewModelScope`)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值