android Jetpack之Lifecycle的使用

Lifecycle是Jetpack提供的一个用于监听生命周期的库。我们知道在使用Activity和Fragment的时候,特别是两者一起使用的时候,生命周期将变得非常的复杂。而且我们需要在Activity和Fragment的生命周期方法里面执行非常多的操作,如地理位置,打开关闭资源等。这会造成很高的耦合。Lifecycle就是为了减低生命周期的耦合而设计的。目的是让各种资源自己监听生命周期变化,在独立的类里面实现相应的生命周期逻辑。
Lifecycle已经包含在androidx里面,也就是下面的包,默认情况下,gradle已经有下面的声明了。

 implementation 'androidx.appcompat:appcompat:1.2.0'

这里有一个特别的地方。就是lifecycle-extensions这个库,只要引用这个库就会把lifecycle里面的所有库都引用进来。

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

你也可以手动的引用你需要的库。推荐最开始还是用lifecycle-extensions这个库,避免麻烦。lifecycle-extensions这个库里面的所有API都已经被废弃。
在这里插入图片描述

    dependencies {
        def lifecycle_version = "2.5.0-rc01"
        def arch_version = "2.1.0"

        // ViewModel
        implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
        // LiveData
        implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
        // Lifecycles only (without ViewModel or LiveData)
        implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

        // Saved state module for ViewModel
        implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"

        // Annotation processor
        annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
        // alternately - if using Java8, use the following instead of lifecycle-compiler
        implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

        // optional - helpers for implementing LifecycleOwner in a Service
        implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"

        // optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
        implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"

        // optional - ReactiveStreams support for LiveData
        implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version"

        // optional - Test helpers for LiveData
        testImplementation "androidx.arch.core:core-testing:$arch_version"
    }
    

这里推荐使用2.2.0这个版本,因为这个版本提供的ViewModelProvider这个类多出了一个参数的构造方法,具体后面会用到。

1.计算真实运行时间的例子

我们要做这样的一个功能。运行app的时候计算运行时间,app退到后台的时候不计算时间。app继续运行,继续计算运行时间。
我们使用Chronometer这个系统提供的组件来实现这个功能。在onResume的时候开始计时,onPause的时候结束计时。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".lifecycle.LifecycleTimerActivity">

    <Chronometer
        android:id="@+id/chronometer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="20sp"
        android:gravity="center"
     />
    
</RelativeLayout>
public class LifecycleTimerActivity extends AppCompatActivity {

    private Chronometer chronometer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle_timer);
        chronometer = findViewById(R.id.chronometer);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("LifecycleTimerActivity", "onResume");
        chronometer.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        chronometer.stop();
    }
}

上面的代码的运行效果如下,我们在运行到3秒的时候按home键程序退到后台,调用onPause方法。再过来7秒后,我们把app运行到前台。对应的计时也变成了10秒,可见在这种情况下,chronometer即使在后台运行也是会计算时间的。
在这里插入图片描述
在这里插入图片描述
我们现在有一个需求,就是后台运行时间我们算在“休息时间”里面,不计算入总运行时间。例如,我们在3秒的时候点击home,程序进入后台,过来几秒后,手动让程序回到前台,这时间我们的app还是继续从3秒开始计时。要实现这个功能,只需要把代码改成下面的样子。
elapsedRealtime()这个方法表示系统自开机以来所运行的时间,包括休眠,锁屏。
setBase()实际就是传入一个时间值给mBase变量,这个变量就是个long类型的表示时间的变量。
elapse这个我们自己定义的变量非常关键,用来计算真实运行的时间。在onPause的时候调用。具体逻辑看下面的代码注释。

public class LifecycleTimerActivity extends AppCompatActivity {

    private Chronometer chronometer;
    private long elapse;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle_timer);
        chronometer = findViewById(R.id.chronometer);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("LifecycleTimerActivity", "onResume");
        //getBase获得的时间值就是等于elapsedRealtime的值。
        //减掉elapse意义是以后每次调用chronometer.getBase()都少了真实运行时间
        chronometer.setBase(SystemClock.elapsedRealtime() - elapse);
        chronometer.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("LifecycleTimerActivity", "onPause");
        //计算出真实运行时间
        elapse = SystemClock.elapsedRealtime() - chronometer.getBase();
        chronometer.stop();
    }
}

上面的代码已经完成了我们需要的功能。有没有发现上面代码有什么问题?这仅仅是一个小功能,要是我们有很多代码都写在声明周期里面,生命周期方法将变得非常臃肿。耦合度非常的高。为了解决这个问题,就要使用我们今天的主角Lifecycle了。

2.使用Lifecycle改进

我们可以把前面的逻辑做一个封装,问题的关键是我们怎么感知生命周期。通过实现LifecycleObserver接口就可以感知生命周期了,这个能力是SDK已经帮我们实现了,ComponentActivity已经实现了感知生命周期的功能。所以我们可以直接使用。@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)可以和onResume方法绑定,其它生命周期方法也是一样。

class Timer extends Chronometer implements LifecycleObserver {
    private long elapse;

    public Timer(Context context) {
        super(context);
    }

    public Timer(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void startTimer() {
        setBase(SystemClock.elapsedRealtime() - elapse);
        start();
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void stopTimer() {
        elapse = SystemClock.elapsedRealtime() - getBase();
        stop();
    }
}

在Activity里面使用封装后的代码:

public class LifecycleTimerActivity extends AppCompatActivity {

    private Timer chronometer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle_timer);
        chronometer =  findViewById(R.id.chronometer);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("LifecycleTimerActivity", "onResume");
        chronometer.startTimer();
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("LifecycleTimerActivity", "onPause");
        //计算出真实运行时间
        chronometer.stopTimer();
    }
    
}

通过封装加Lifecycle,代码得到了简化,耦合度也大大减低了。Lifecycle还是非常有用的。

3.结合Service例子

在Service里面我们添加Lifecycle观察者。

public class LocationService extends LifecycleService {

    public LocationService() {
        LocationObsever obsever=new LocationObsever(this);
        getLifecycle().addObserver(obsever);
    }

}

最主要的实现是我们的LocationObsever。

class LocationObsever implements LifecycleObserver {

    private final Context context;
    private LocationManager locationManager;
    private MyLoactionListener myLoactionListener;

    public LocationObsever(Context context) {
        this.context = context;
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void startLocation() {
        Log.d("LocationObsever", "startLocation");
        locationManager = (LocationManager) context.getSystemService(Service.LOCATION_SERVICE);
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        myLoactionListener = new MyLoactionListener();
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 1,myLoactionListener);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void stopLocation() {
        Log.d("LocationObsever", "stopLocation");
        locationManager.removeUpdates(myLoactionListener);
    }

    static class MyLoactionListener implements LocationListener {

        @Override
        public void onLocationChanged(Location location) {
            Log.d("MyLoactionListener", location.toString());
        }

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

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }
    }

}
public class LocationActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_location);
    }

    public void start(View view) {
        startService(new Intent(this, LocationService.class));
    }

    public void stop(View view) {
        stopService(new Intent(this,LocationService.class));
    }
}

最主要的就是LocationManager这个类,可以获取经纬度等信息。可以通过下面的adb代码改变。

adb -s emulator-5554 emu geo fix -122.08400000000002 37.421998333333335 
adb -s emulator-5554 emu geo fix -122.08400000000002 38.421998333333335 

4.application配合Lifecycle

Application也是可以被Lifecycle监听的,当然和一般的activity不同,Application的onDestory永远不会被调用。代码也是非常的简单。

public class App extends Application {
    
    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationObsever());
    }
}
public class ApplicationObsever implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onStart() {
        Log.d("ApplicationObsever", "onStart");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onCreate() {
        Log.d("ApplicationObsever", "onCreate");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume() {
        Log.d("ApplicationObsever", "onResume");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void onPause() {
        Log.d("ApplicationObsever", "onPause");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onStop() {
        Log.d("ApplicationObsever", "onStop");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值