Android Jetpack系列之LiveData

简介: **LiveData是一种可观察的数据存储类**。LiveData 具有生命周期感知能力,遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的Observer,非活跃状态下的Observer不会受到通知。

LiveData介绍

LiveData是一种可观察的数据存储类。LiveData 具有生命周期感知能力,遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的Observer,非活跃状态下的Observer不会受到通知。

生命周期状态可以通过Lifecycle提供,包括DESTROYED、INITIALIZED、CREATED、STARTED、RESUMED,当且仅当生命周期处于STARTED、RESUMED时为活跃状态,其他状态是非活跃状态。

LiveData优点

  • 确保界面符合数据状态

LiveData 遵循观察者模式。当数据发生变化时,LiveData 会通知 Observer 对象,那么Observer回调的方法中就可以进行UI更新,即数据驱动。

  • 不会发生内存泄漏

观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁(如Activity进入ONDESTROY状态)后进行自我清理。

  • 不会因 Activity 停止而导致崩溃

如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。

  • 不再需要手动处理生命周期

界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。

  • 数据始终保持最新状态

如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。

  • 配置更改时自动保存数据

如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。

  • 共享资源

使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。

LiveData使用举例

基础用法

先上效果图:
livedata.gif

在Activity中动态添加了一个Fragment,点击按钮产生一个1000以内的随机值,并通过LiveData.setValue发送出去,在Fragment中通过LiveData.observe进行数据观察与接收,可以看到即使Activity中先发送的数据,Fragment中滞后注册观察者依然能收到数据,即LiveData发送的是粘性事件。

首先需要保证Activity和Fragment中的LiveData是同一个实例:

//LiveDataInstance.kt 使用object来声明单例模式
object LiveDataInstance {
    //MutableLiveData是抽象类LiveData的具体实现类
    val INSTANCE = MutableLiveData<String>()
}

Activity中随机生成一个数并通过LiveData.setValue进行发送:

//LiveDataActivity.kt
class LiveDataActivity : AppCompatActivity() {
    lateinit var mTextView: TextView
    var mFragment: LiveDataFragment? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)
        mTextView = findViewById(R.id.tv_text)
        addLiveDataFragment()
    }

    fun updateValue(view: View) {
        sendData(produceData())
    }

    //随机更新一个整数
    private fun produceData(): String {
        val randomValue = (0..1000).random().toString()
        mTextView.text = "Activity中发送:$randomValue"
        return randomValue
    }

    //通过setValue发送更新
    private fun sendData(randomValue: String) {
        LiveDataInstance.INSTANCE.value = randomValue
    }

    //添加Fragment
    fun addFragment(view: View) {
        addLiveDataFragment()
    }

    //移除Fragment
    fun removeFragment(view: View) {
        delLiveDataFragment()
    }

    private fun addLiveDataFragment() {
        val fragment = supportFragmentManager.findFragmentById(R.id.fl_content)
        if (fragment != null) {
            Toast.makeText(this, "请勿重复添加", Toast.LENGTH_SHORT).show()
            return
        }

        if (mFragment == null) {
            mFragment = LiveDataFragment.newInstance()
        }
        supportFragmentManager
            .beginTransaction()
            .add(R.id.fl_content, mFragment!!)
            .commitAllowingStateLoss()
    }

    private fun delLiveDataFragment() {
        val fragment = supportFragmentManager.findFragmentById(R.id.fl_content)
        if (fragment == null) {
            Toast.makeText(this, "没有Fragment", Toast.LENGTH_SHORT).show()
            return
        }
        supportFragmentManager.beginTransaction().remove(fragment).commitAllowingStateLoss()
    }
}

Fragment动态添加到Activity中,并通过LiveData.observe注册观察者并监听数据变化:

//LiveDataFragment.kt
class LiveDataFragment : Fragment() {
    lateinit var mTvObserveView: TextView

    //数据观察者 数据改变时在onChange()中进行刷新
    private val changeObserver = Observer<String> { value ->
        value?.let {
            Log.e(JConsts.LIVE_DATA, "observer:$value")
            mTvObserveView.text = value
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.live_data_fragment, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mTvObserveView = view.findViewById(R.id.tv_observe)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        //通过LiveData.observe注册观察者,监听数据变化
        LiveDataInstance.INSTANCE.observe(this, changeObserver)
    }

    companion object {
        fun newInstance() = LiveDataFragment()
    }
}

上面就是一个LiveData的基本用法了,很简单,Activity/Fragment中共用LiveData实例,在Activity中通过点击按钮生成一个随机数并通过LiveData.setValue发送数据(如果在子线程中发送,需要使用postValue),然后Fragment中通过LiveData.observe注册观察者并监听数据变化。

改一下代码:

 //LiveDataActivity.kt
 override fun onStop() {
     super.onStop()
     val data = produceData()
     Log.e(JConsts.LIVE_DATA, "onStop():$data")
     sendData(data)
 }

 //LiveDataFragment.kt
 private val changeObserver = Observer<String> { value ->
     value?.let {
         Log.e(JConsts.LIVE_DATA, "observer:$value")
         mTvObserveView.text = value
     }
 }

点击Home键,Activity的onStop会触发,并通过LiveData.setValue发送数据,看下打印日志:

2021-07-13 17:07:08.662 1459-1459/com.example.jetpackstudy E/LIVEDATA: onStop():742

Activity中在onStop中重新生成了一个随机值并发送了出去,但是在Fragment中的Observer中并没有收到数据,这是为什么呢?还记得LiveData的能力吗,它是能感知生命周期的,并且只会更新处于活跃状态下的Observer(STARTED、RESUMED状态),所以在onStop中发送的事件,Fragment作为观察者已经不在活跃状态下了,并不会收到通知,当我们App切回前台时,Observer重新回到活跃状态,所以会收到Activity之前发送的事件:

2021-07-13 17:12:47.433 5850-5850/com.example.jetpackstudy E/LIVEDATA: observer:742

如果想让Observer不管在什么状态下都能马上收到数据变化的通知,可以使用LiveData.observeForever来注册并监听数据变化:

 //LiveDataFragment.kt
 private val changeObserver = Observer<String> { value ->
     value?.let {
         Log.e(JConsts.LIVE_DATA, "observer:$value")
         mTvObserveView.text = value
     }
 }

//observeForever不管Observer是否处于活跃状态都会立马相应数据变化
//注意这里只需要传一个Observer即可,不需要传入LifecycleOwner,因为不需要考虑Observer是否处于活跃状态
LiveDataInstance.INSTANCE.observeForever(changeObserver)

override fun onDestroy() {
    super.onDestroy()
    //需要手动移除观察者
    LiveDataInstance.INSTANCE.observeForever(changeObserver)
}

上述代码重新实验,点击Home键将App切到后台:

2021-07-13 17:29:56.848 15679-15679/com.example.jetpackstudy E/LIVEDATA: onStop():878
2021-07-13 17:29:56.849 15679-15679/com.example.jetpackstudy E/LIVEDATA: observer:878

可以看到通过LiveData.observeForever注册的Observer即使不在活跃状态也是会立马相应数据变化的,这里要注意一点,LiveData.observeForever注册的Observer并不会自动解除注册,需要我们手动处理。

进阶用法

Transformations.map()修改数据源

先上效果图:
map.gif

//LiveDataFragment.kt
//数据观察者 数据改变时在onChange()中进行刷新
private val changeObserver = Observer<String> { value ->
    value?.let {
        Log.e(JConsts.LIVE_DATA, "transform observer:$value")
        mTvObserveView.text = value
    }
}

//Transformations.map()改变接收的data
val transformLiveData = Transformations.map(LiveDataInstance.INSTANCE) { "Transform:$it" }

//观察者监听的时候传入了LifecycleOwner 用以监听生命周期变化
transformLiveData.observe(this, changeObserver)

可以看到在Activity中发送的数据源是“xxx”,Fragment中经过Transformations.map变换后变成"Transform:xxx",通过Transformations.map()可以对接收的数据源进行修改。

Transformations.switchMap()切换数据源

switchMap.gif

//LiveDataInstance.kt
object LiveDataInstance {
    val INSTANCE = MutableLiveData<String>()
    val INSTANCE2 = MutableLiveData<String>()
    val SWITCH = MutableLiveData<Boolean>()
}

注:一般LiveData都是与ViewModel结合使用的,本文主要介绍LiveData,所以使用了单例

//LiveDataActivity.kt
mBtnSwitch = findViewById(R.id.btn_switch)
mBtnSwitch.setOnCheckedChangeListener { _, isChecked ->
//发送开关状态 用以在Transformations.switchMap中切换数据源
LiveDataInstance.SWITCH.value = isChecked
}

//通过setValue发送更新
private fun sendData(randomValue: String, isLeft: Boolean) {
  if (isLeft) {
    LiveDataInstance.INSTANCE.value = randomValue
  } else {
    LiveDataInstance.INSTANCE2.value = randomValue
  }
}
//LiveDataFragment.kt
//数据观察者 数据改变时在onChange()中进行刷新
private val changeObserver = Observer<String> { value ->
    value?.let {
        Log.e(JConsts.LIVE_DATA, "transform observer:$value")
        mTvObserveView.text = value
    }
}

//Transformations.switchMap()切换数据源
val switchMapLiveData =
   Transformations.switchMap(LiveDataInstance.SWITCH) { switchRight ->
       if (switchRight) {
            LiveDataInstance.INSTANCE2
        } else {
            LiveDataInstance.INSTANCE
        }
     }
switchMapLiveData.observe(this, changeObserverTransform)

例子中有两个数据源:LiveDataInstance.INSTANCE、LiveDataInstance.INSTANCE2,当Switch开关切换时,通过Transformations.switchMap()可以来回切换数据源,Observer中也会更新对应的数据。

示例代码地址

Jetpack Livedata完整代码地址

源码解析

发送数据setValue/postValue

//LiveData.java
    //setValue发送数据,只能在主线程中使用
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

    //postValue发送数据,可以在子线程中使用
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
 ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };

可以看到setValue/postValue都可以发送数据,区别是postValue还可以在子线程中发送数据,本质上postValue通过Handler将事件发送到Main线程中,最终也是调用了setValue发送事件,所以只看setValue()方法,该方法最后调用了dispatchingValue()方法并传入了一个参数null,继续看该方法:

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                //2、通过observe()的方式会调用这里
                considerNotify(initiator);
                initiator = null;
            } else {
                //1、通过setValue/postValue的方式会调用这里,遍历所有观察者并进行分发
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            //观察者不在活跃状态 直接返回
            return;
        }
        //如果是observe(),则是在STARTED、RESUMED状态时活跃;如果是ObserveForever(),则认为一直是活跃状态
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //Observer中的Version必须小于LiveData中的Version,防止重复发送
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //回调Observer的onChange方法并接收数据
        observer.mObserver.onChanged((T) mData);
    }

因为传入的参数是null,所以最终走到了1处,遍历所有的观察者并回调Observer的onChange方法接收数据,这样就完成了一次数据的传递。2处是单独调用一个观察者并回调其onChange方法接收数据,是执行observe()方法的时候执行的,具体等后面分析。

注册观察者Observer并监听数据变化

LiveData.observe()

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        //如果当前观察者处于DESTROYED状态,直接返回
        return;
    }
    //将LifecycleOwner、Observer包装成LifecycleBoundObserver
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //ObserverWrapper是LifecycleBoundObserver的父类
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    //如果mObservers中存在该Observer且跟传进来的LifecycleOwner不同,直接抛异常,一个Observer只能对应一个LifecycleOwner
    if (existing != null && !existing.isAttachedTo(owner)) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    //如果已经存在Observer且跟传进来的LifecycleOwner是同一个,直接返回
    if (existing != null) {
        return;
    }
    //通过Lifecycle添加观察者
    owner.getLifecycle().addObserver(wrapper);
}

可以看到最后observe()将Observer加入到Lifecycle里去了,并通过onStateChanged()回调来监听LifecycleOwner生命周期的变化,主要看onStateChanged()方法:

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        //Observer对应的LifecycleOwner是DESTROYED状态,直接删除该Observer,所以LiveData有自动解除Observer的能力
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        //
        activeStateChanged(shouldBeActive());
    }

    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}

//ObserverWrapper.java
void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    mActive = newActive;
    boolean wasInactive = LiveData.this.mActiveCount == 0;
    LiveData.this.mActiveCount += mActive ? 1 : -1;
    if (wasInactive && mActive) {
        //观察者数量从0变为1时
        onActive();
    }
    if (LiveData.this.mActiveCount == 0 && !mActive) {
        //观察者数量从1变为0时
        onInactive();
    }
    if (mActive) {
        //观察者为活跃状态,进行分发
        dispatchingValue(this);
    }
}

onActive()在观察者数量从0变为1时执行;onInactive()在观察者数量从1变为0时执行。最后如果当前观察者是活跃状态,直接执行dispatchingValue(this),this是当前ObserverWrapper对象,还记得dispatchingValue()方法吗,前面讲这个方法的时候留了个疑问,这里就会执行前面讲的该方法里2处的代码,用以分发事件并在Observer的onChange()方法里接收并处理事件。

LiveData.observeForever()

@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing instanceof LiveData.LifecycleBoundObserver) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    wrapper.activeStateChanged(true);
}

observeForever()中不需要传LifecycleOwner参数,因为observeForever()认为是一直活跃的状态,所以不需要监听LifecycleOwner的生命周期,最后是直接执行了wrapper.activeStateChanged(true)方法,后续的逻辑跟上面observe()一样了。这里注意一点,observeForever()注册的观察者当处于DESTROYED的时候并不会自动删除,需要手动删除之

LiveData实现类MutableLiveData

public class MutableLiveData<T> extends LiveData<T> {

    public MutableLiveData(T value) {
        super(value);
    }

    public MutableLiveData() {
        super();
    }

    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

MutableLiveData是抽象类LiveData的具体实现类。

数据切换/修改 Transformations.map()/switchMap()

//Transformations.java
public static <X, Y> LiveData<Y> map(
        @NonNull LiveData<X> source,
        @NonNull final Function<X, Y> mapFunction) {
    final MediatorLiveData<Y> result = new MediatorLiveData<>();
    result.addSource(source, new Observer<X>() {
        @Override
        public void onChanged(@Nullable X x) {
            result.setValue(mapFunction.apply(x));
        }
    });
    return result;
}

从源码的注释上,看到了这么一句话This method is analogous to {@link io.reactivex.Observable#map},哦,原来用法是跟RxJava中的Map操作符类似。第一个参数是源LiveData< X>,第2个参数是个Funtion< X,Y>,目的就是将LiveData< X>变换为LiveData< Y>,然后再重新发送事件。map()方法里new了一个MediatorLiveData并执行了addSource()方法,看看这个方法怎么实现的:

//MediatorLiveData.java
public class MediatorLiveData<T> extends MutableLiveData<T> {
    private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();

    @MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        //将源LiveData及Observer包装成Source
        Source<S> e = new Source<>(source, onChanged);
        Source<?> existing = mSources.putIfAbsent(source, e);
        //如果源LiveData中已经有Observer且跟传进来的不一致,直接抛异常
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
            //判断有活跃观察者时
            e.plug();
        }
    }

    @MainThread
    public <S> void removeSource(@NonNull LiveData<S> toRemote) {
        Source<?> source = mSources.remove(toRemote);
        if (source != null) {
            source.unplug();
        }
    }

    private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;

        Source(LiveData<V> liveData, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        void plug() {
            //通过observeForever添加观察者,有变动时就会回调下面的onChange()方法
            mLiveData.observeForever(this);
        }

        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }
}

首先将源LiveData及Observer包装成Source,经过了几次判断,最后执行到了Source#plug()方法,里面通过observeForever添加观察者,有变动时就会回调Source#onChange()方法,而这个方法里又会回调传进来的Observer#onChange()方法,即执行到了map()中传入的Observer的onChange()方法,里面通过setValue发送了转换之后的数据格式,这样就完成了整个的数据转换格式。那么再看switchMap()就简单了:

public static <X, Y> LiveData<Y> switchMap(
        @NonNull LiveData<X> source,
        @NonNull final Function<X, LiveData<Y>> switchMapFunction) {
    final MediatorLiveData<Y> result = new MediatorLiveData<>();
    result.addSource(source, new Observer<X>() {
        LiveData<Y> mSource;

        @Override
        public void onChanged(@Nullable X x) {
            LiveData<Y> newLiveData = switchMapFunction.apply(x);
            if (mSource == newLiveData) {
                return;
            }
            if (mSource != null) {
                result.removeSource(mSource);
            }
            mSource = newLiveData;
            if (mSource != null) {
                result.addSource(mSource, new Observer<Y>() {
                    @Override
                    public void onChanged(@Nullable Y y) {
                        result.setValue(y);
                    }
                });
            }
        }
    });
    return result;
}

可以看到switchMap()中实现方式跟map()基本一致,只不过map()改变的是数据,而switchMap()改变的是数据源,可以对数据源进行切换。Transformations还有个distinctUntilChanged方法简单看一下:

public static <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) {
    final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>();
    outputLiveData.addSource(source, new Observer<X>() {

        boolean mFirstTime = true;

        @Override
        public void onChanged(X currentValue) {
            final X previousValue = outputLiveData.getValue();
            if (mFirstTime
                    || (previousValue == null && currentValue != null)
                    || (previousValue != null && !previousValue.equals(currentValue))) {
                mFirstTime = false;
                outputLiveData.setValue(currentValue);
            }
        }
    });
    return outputLiveData;
}

也很简单,只有当数据源发生改变时,Observer才会相应,即发送重复的数据时,除第一次之外的数据都会被忽略。

最后画一下类图:
LiveData.png

参考

【1】https://developer.android.com/topic/libraries/architecture/livedata?hl=zh_cn

【2】Android LiveData 使用详解

相关文章
|
5月前
|
安全 Java Android开发
安卓开发中的新趋势:Kotlin与Jetpack的完美结合
【6月更文挑战第20天】在不断进化的移动应用开发领域,Android平台以其开放性和灵活性赢得了全球开发者的青睐。然而,随着技术的迭代,传统Java语言在Android开发中逐渐显露出局限性。Kotlin,一种现代的静态类型编程语言,以其简洁、安全和高效的特性成为了Android开发中的新宠。同时,Jetpack作为一套支持库、工具和指南,旨在帮助开发者更快地打造优秀的Android应用。本文将探讨Kotlin与Jetpack如何共同推动Android开发进入一个新的时代,以及这对开发者意味着什么。
|
1月前
|
测试技术 数据库 Android开发
深入解析Android架构组件——Jetpack的使用与实践
本文旨在探讨谷歌推出的Android架构组件——Jetpack,在现代Android开发中的应用。Jetpack作为一系列库和工具的集合,旨在帮助开发者更轻松地编写出健壮、可维护且性能优异的应用。通过详细解析各个组件如Lifecycle、ViewModel、LiveData等,我们将了解其原理和使用场景,并结合实例展示如何在实际项目中应用这些组件,提升开发效率和应用质量。
44 6
|
2月前
|
编译器 Android开发 开发者
带你了解Android Jetpack库中的依赖注入框架:Hilt
本文介绍了Hilt,这是Google为Android开发的依赖注入框架,基于Dagger构建,旨在简化依赖注入过程。Hilt通过自动化的组件和注解减少了DI的样板代码,提高了应用的可测试性和可维护性。文章详细讲解了Hilt的主要概念、基本用法及原理,帮助开发者更好地理解和应用Hilt。
77 8
|
2月前
|
安全 Java Android开发
探索安卓应用开发的新趋势:Kotlin和Jetpack Compose
在安卓应用开发领域,随着技术的不断进步,新的编程语言和框架层出不穷。Kotlin作为一种现代的编程语言,因其简洁性和高效性正逐渐取代Java成为安卓开发的首选语言。同时,Jetpack Compose作为一个新的UI工具包,提供了一种声明式的UI设计方法,使得界面编写更加直观和灵活。本文将深入探讨Kotlin和Jetpack Compose的特点、优势以及如何结合使用它们来构建现代化的安卓应用。
61 4
|
4月前
|
存储 数据库 Android开发
🔥Android Jetpack全解析!拥抱Google官方库,让你的开发之旅更加顺畅无阻!🚀
【7月更文挑战第28天】在Android开发中追求高效稳定的路径?Android Jetpack作为Google官方库集合,是你的理想选择。它包含多个独立又协同工作的库,覆盖UI到安全性等多个领域,旨在减少样板代码,提高开发效率与应用质量。Jetpack核心组件如LiveData、ViewModel、Room等简化了数据绑定、状态保存及数据库操作。引入Jetpack只需在`build.gradle`中添加依赖。例如,使用Room进行数据库操作变得异常简单,从定义实体到实现CRUD操作,一切尽在掌握之中。拥抱Jetpack,提升开发效率,构建高质量应用!
70 4
|
4月前
|
存储 前端开发 测试技术
Android Kotlin中使用 LiveData、ViewModel快速实现MVVM模式
使用Kotlin实现MVVM模式是Android开发的现代实践。该模式分离UI和业务逻辑,借助LiveData、ViewModel和DataBinding增强代码可维护性。步骤包括创建Model层处理数据,ViewModel层作为数据桥梁,以及View层展示UI。添加相关依赖后,Model类存储数据,ViewModel类通过LiveData管理变化,而View层使用DataBinding实时更新UI。这种架构提升代码可测试性和模块化。
182 2
|
4月前
|
存储 移动开发 Android开发
使用kotlin Jetpack Compose框架开发安卓app, webview中h5如何访问手机存储上传文件
在Kotlin和Jetpack Compose中,集成WebView以支持HTML5页面访问手机存储及上传音频文件涉及关键步骤:1) 添加`READ_EXTERNAL_STORAGE`和`WRITE_EXTERNAL_STORAGE`权限,考虑Android 11的分区存储;2) 配置WebView允许JavaScript和文件访问,启用`javaScriptEnabled`、`allowFileAccess`等设置;3) HTML5页面使用`<input type="file">`让用户选择文件,利用File API;
|
5月前
|
安全 JavaScript 前端开发
kotlin开发安卓app,JetPack Compose框架,给webview新增一个按钮,点击刷新网页
在Kotlin中开发Android应用,使用Jetpack Compose框架时,可以通过添加一个按钮到TopAppBar来实现WebView页面的刷新功能。按钮位于右上角,点击后调用`webViewState?.reload()`来刷新网页内容。以下是代码摘要:
|
4月前
|
XML 存储 API
Jetpack初尝试 NavController,LiveData,DataBing,ViewModel,Paging
Jetpack初尝试 NavController,LiveData,DataBing,ViewModel,Paging
|
5月前
|
Android开发
Jetpack Compose: Hello Android
Jetpack Compose: Hello Android