Lifecycle解决了什么问题,以及它的基本用法

2023-10-22 13:58:53 浏览数 (3)

1.为何要引入Lifecycle?

  我首先来举个大家都比较常见的例子:我们在android开发的时候,经常需要在页面的onCreate()方法中对组件进行初始化,在onPause()方法中停止组件,而在页面的onDestroy()方法中对组件进行资源回收工作。这样的工作非常繁琐,会让页面和组件间的耦合度变高。但这些工作又不得不做,因为可能会引起内存泄漏。

  这里我先给出普通组件和系统组件这两个名词的概念,系统组件是指Activity/Fragment,Service和Application;普通组件是指我们将代码按照功能或作用进行封装的组件。我们希望对自定义组件/普通组件的管理不依赖于页面生命周期的回调方法,同时又在页面生命周期发生变化的时候及时收到通知。这在组件化和架构设计中显得尤为重要。为此,Google引入了Lifecycle作为解决方案,Lifecycle可以帮助开发者创建可感知生命周期的组件。这样,组件就可以在其内部管理自己的生命周期,降低了和页面的耦合度。

  接下来,从三个方面来讲解一下Lifecycle的用法。

2.使用Lifecycle解耦Activity和组件

  案例分析:假设有这样一个需求,在用户打开某个页面的时候,获取用户当前的地理位置,离开这个页面的时候,停止获取。面对这个需求,我们可以这样写代码:

代码语言:javascript复制
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化位置管理器
        initLocationManager();
    }

    @Override
    protected void onResume() {
        super.onResume();
        //开始获取用户的地理位置
        startGetLocation();
    }

    @Override
    protected void onPause() {
        super.onPause();
        //停止获取用户的地理位置
        stopGetLocation();
    }
}

  从以上的代码可以看出,获取地理位置这个需求的实现和页面的生命周期息息相关。如果我们想要把这个功能独立成一个组件,那么必须得感知页面的生命周期变化。Lifecycle是如何解决这个问题的呢?Jetpack为我们提供了两个类LifecycleOwner(被观察者)和LifecycleObserver(观察者),即通过观察者模式实现对页面生命周期的监听。

  通过查看ComponentActivity源码,可以得知该类实现了LifecycleOwner接口,并重写了getLifecycle()方法。如下图所示:

   LifecycleOwner接口只有getLifecycle()这一个方法,LifecycleOwner正是通过该方法实现观察者模式的。所以,从以上源码可以得知,ComponentActivity已经帮我们实现了被观察者应该实现的那一部分代码,我们只需要实现观察者应该实现的那一部分代码即可。实现的方式也很简单,就是让自定义组件实现DefaultLifecycleObserver接口,然后将其添加为观察者就行了。

代码语言:javascript复制
public class MyLocationListener implements DefaultLifecycleObserver {
    private LocationManager manager;
    private Context context;
    private OnLocationChangedListener onLocationChangedListener;
    public MyLocationListener(Activity context, OnLocationChangedListener onLocationChangedListener) {
        manager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
        this.context=context;
        this.onLocationChangedListener=onLocationChangedListener;
    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onPause(owner);
        Log.i("MyLocationListener","stopGetLocation");
    }

    public interface OnLocationChangedListener{
        void onChanged(double latitude,double longitude);
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onResume(owner);
        Log.i("MyLocationListener","startGetLocation");
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        manager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1, new LocationListener() {
            @Override
            public void onLocationChanged(@NonNull Location location) {
                onLocationChangedListener.onChanged(location.getLatitude(),location.getLongitude());
            }
        });
    }
}
代码语言:javascript复制
public class MainActivity extends AppCompatActivity {
    private TextView tv_display;
    private MyLocationListener myLocationListener;
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_display = findViewById(R.id.tv_display);
        myLocationListener=new MyLocationListener(this, new MyLocationListener.OnLocationChangedListener() {
            @Override
            public void onChanged(double latitude, double longitude) {
                tv_display.setText("" latitude "," longitude);
            }
        });
        getLifecycle().addObserver(myLocationListener);
    }
}

  就这么简单!Lifecycle完美解决了组件对页面生命周期的依赖问题,使得组件可以自行管理生命周期。当将自定义组件作为页面生命周期的观察者时,页面处于哪个生命周期,就会回调DefaultLifecycleObserver接口中的同名方法。是的,就是同名方法!

代码语言:javascript复制
public interface DefaultLifecycleObserver extends FullLifecycleObserver {

    @Override
    default void onCreate(@NonNull LifecycleOwner owner) {
    }


    @Override
    default void onStart(@NonNull LifecycleOwner owner) {
    }


    @Override
    default void onResume(@NonNull LifecycleOwner owner) {
    }


    @Override
    default void onPause(@NonNull LifecycleOwner owner) {
    }


    @Override
    default void onStop(@NonNull LifecycleOwner owner) {
    }

    @Override
    default void onDestroy(@NonNull LifecycleOwner owner) {
    }
}

  可以看到这些方法名前面加了一个default关键词,就是你可以有选择性的重写所需要的方法,而不需要全部重写。是不是很简单?

3.使用LifecycleService解耦Service与组件

  这个类继承自Service并且实现了LifecycleOwner接口, 它也提供了getLifecycle()方法供我们使用。我们只需要继承这个类即可。下面给出代码:

代码语言:javascript复制
public class MyService extends LifecycleService {
    private MyServiceObserver myServiceObserver;
    public MyService(){
        myServiceObserver=new MyServiceObserver();
        getLifecycle().addObserver(myServiceObserver);
    }
}

  MyServiceObserver同样要实现DefaultLifecycleObserver接口,和前面的一模一样,这里不再赘述。

4.使用ProcessLifecycleOwner监听应用程序的生命周期

  具有生命周期的系统组件除了Activity,Fragment,Service外,还有Application。很多时候,我们会遇到这样的需求:我们想知道应用程序当前处在前台还是后台,以便作出不同的处理。这个功能用ProcessLifecycleOwner实现起来十分简单,和前面非常的相似。不过这次我们想要观察的是整个应用程序,因此需要在Application中进行相关代码的编写。

代码语言:javascript复制
public class AppApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppApplicationObserver());
    }
}

  AppApplicationObserver也是要实现同样的接口:DefaultLifecycleObserver。

代码语言:javascript复制
public class AppApplicationObserver implements DefaultLifecycleObserver {
    private String TAG=getClass().getName();

    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {
        Log.i(TAG,"onCreate");
        DefaultLifecycleObserver.super.onCreate(owner);
    }

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {
        Log.i(TAG,"onStart");
        DefaultLifecycleObserver.super.onStart(owner);
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {
        Log.i(TAG,"onResume");
        DefaultLifecycleObserver.super.onResume(owner);
    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {
        Log.i(TAG,"onPause");
        DefaultLifecycleObserver.super.onPause(owner);
    }

    @Override
    public void onStop(@NonNull LifecycleOwner owner) {
        Log.i(TAG,"onStop");
        DefaultLifecycleObserver.super.onStop(owner);
    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        Log.i(TAG,"onDestroy");
        DefaultLifecycleObserver.super.onDestroy(owner);
    }
}

  应用程序创建的时候调用onCreate()方法并只调用一次,在前台的时候分别调用onStart()和onResume(),应用程序在后台的时候调用onPause()和onStop()。不过需要注意的是,onDestroy()永远不会调用,系统不会分发调用这个事件。

  Lifecycle的用法到这里就基本讲解完毕了,怎么样,感觉如何?

0 人点赞