Android Jetpack组件(四)LiveData

Android Jetpack架构组件(四)一文带你了解LiveData(使用篇) 本文首发于微信公众号「后厂村码农」 前言 在2017年前后,RxJava一直很火,我在Android进阶三部曲第一部《Android进阶之光》中就介绍了RxJava的使用和原理。谷歌推出的LiveData和RxJava类似,也是基于观察者,你可以认为LiveData是轻量级的RxJava。起初LiveData并不被看好,随着谷歌的大力推广,LiveData也慢慢的进入了大家的视野。一般来说,... 阅读详情

Android Jetpack组件系列文章:
Android Jetpack组件(一)LifeCycle
Android Jetpack组件(二)Navigation
Android Jetpack组件(三)ViewModel
Android Jetpack组件(四)LiveData
Android Jetpack组件(五)Room
Android JetPack组件(六)DataBinding
Android Jetpack组件(七)Paging
Android Jetpack组件(八)WorkManager
Android Jetpack组件(九)DataStore

首语

ViewModel 以注重生命周期的方式存储和管理界面相关的数据,当数据发生变化时,可通过接口的方式通知页面,但是有很多数据要通知时,需要定义大量的接口显得十分冗余,为此,Jetpack提供了LiveData组件解决这种问题,简化了开发过程。
LiveData 是一种可观察的数据存储器类。它是一个数据的容器,将数据包装起来,使数据成为被观察者,当数据发生变化时,观察者能够获得通知。
LiveData 具有生命周期感知能力,它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

优势

  1. 确保界面符合数据状态
    LiveData 遵循观察者模式。当数据发生变化时,LiveData 会通知观察者对象,无需在每次应用数据发生变化时更新界面。
  2. 不会发生内存泄漏
    LiveData会绑定到 LifeCycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。
  3. 不会因Activity停止而导致崩溃
    如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
  4. 不需要手动处理生命周期
    界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
  5. 数据始终保持最新状态
    如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
  6. 适当的配置更改
    如果由于配置更改(如设备旋转)而重新创建了Activity或Fragment,它会立即接收最新的可用数据。
  7. 共享资源
    使用单例模式扩展封装LiveData,以便在应用中共享它们。

依赖

    implementation 'androidx.lifecycle:lifecycle-livedata:2.3.0'
    //包含了 viewmodel 和 livedata,lifecycle-extensions 中的 API 已弃用
    //implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

使用

LiveData是一个抽象类,不能直接使用,通常使用的是它的直接子类MutableLiveData。通过LiveData+ViewModel 完成一个计数器的例子。

public class HomeViewModel extends ViewModel {
    //value字段用MutableLiveData包装,通常在ViewModel类中完成
    private MutableLiveData<Integer> value;

    public MutableLiveData<Integer> getCurrentValue() {
        if (value == null) {
            value = new MutableLiveData<>();
            value.setValue(0);
        }

        return value;
    }
}

定义完LiveData后,就要利用它来完成ViewModel与页面间的通信。

 HomeViewModel homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
 MutableLiveData<Integer> currentValue = homeViewModel.getCurrentValue();

 currentValue.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                textView.setText(String.valueOf(integer));
            }
 });
 button.setOnClickListener(view -> {
            homeViewModel.addValue();
 });

在页面中,通过LiveData.observe()对LiveData所包装的数据进行观察,我们也可以通过Livedata的postValue()或Livedata的setValue()来完成修改数据,postValue()用在非UI线程中,setValue()用在UI线程中。
更新页面的LiveData对象存储在ViewModel中,而不将其存储在Activity或Fragment中。

 public void addValue() {
        if (value.getValue() != null) {
            value.setValue(value.getValue() + 1);
        }
 }

通常,LiveData仅在数据发生更改时才发送更新,并且仅发送给活跃观察者。一种例外情况是,观察者从非活跃状态更改为活跃状态时也会收到更新。此外,如果观察者第二次从非活跃状态更改为活跃状态,则只有在自上次变为活跃状态以来值发生了更改时,它才会收到更新。

扩展LiveData

LiveData的优势之一就是共享资源,将LiveData类实现一个自定义单例。

public class LiveDataUtil extends LiveData<Integer> {

    private static LiveDataUtil sInstance;
    private LiveDataUtil manager;

    private SimplePListener listener = new SimpleListener() {
        @Override
        public void onPriceChanged(Integer value) {
            setValue(value);
        }
    };

    @MainThread
    public static LiveDataUtil getInstance(String symbol) {
        if (sInstance == null) {
            sInstance = new LiveDataUtil(symbol);
        }
        return sInstance;
    }

    private LiveDataUtil(String symbol) {
        manager = new LiveDataUtil(symbol);
    }

    @Override
    protected void onActive() {
        manager.requestUpdates(listener);
    }

    private void requestUpdates(SimpleListener listener) {
        this.listener = listener;
    }

    @Override
    protected void onInactive() {
        manager.removeUpdates(listener);
    }

    private void removeUpdates(SimpleListener listener) {
        this.listener = listener;
    }
}

在Activity或Fragment中使用它获取数据。

LiveDataUtil.getInstance("flag").observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                Log.e("yhj", "onChanged: "+integer);
            }
});

转换LiveData

计数器的例子中,value的类型是Integer,而给Textview设置文本类型是String,我们需要对其中的类型进行更改,LiveData中提供了Transformations类来进行LiveData的转换,类似于RxJava的操作符。

//aLiveData监听bLiveData内容的变化,变化时将bLiveData转换为相应的内容并通知aLiveData  
liveData = Transformations.map(homeViewModel.getCurrentValue(), String::valueOf);
 
//aLiveData监听bLiveData内容的变化,变化时从bLiveData获取相应的cLiveData,
//添加到aLiveData的监听列表里,即aLiveData同时监听bLiveData和cLiveData,bLiveData的变化只会switch cLiveData,cLiveData变化才会通知aLiveData
aLiveData=Transformations.switchMap(bLiveData, new Function<Integer, LiveData<String>>() {
            @Override
            public LiveData<String> apply(Integer input) {
                return cLiveData;
            }
});

合并多个LiveData

同时监听多个LiveData,只要其中一个LiveData更新则收到通知,通过LiveData的子类MediatorLiveData来实现。

MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>();
mediatorLiveData.addSource(liveData1, new Observer<String>() {
            @Override
            public void onChanged(String s) {
             mediatorLiveData.setValue(s);
            }
});
mediatorLiveData.addSource(liveData2, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                mediatorLiveData.setValue(s);
            }
 });

mediatorLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
            }
});

LiveData实现事件总线

实现事件总线的方式有许多种,诸如EventBus和RxJava实现的RxBus。可参考之前的两篇文章。这两个框架都需要对生命周期进行特殊处理。LiveData自带生命周期感知能力,它本身可感知数据更新,因此,通过LiveData可以实现一个自带生命周期感知能力的事件总线框架。

public class LiveDataBus {

    private static class Lazy {
        static LiveDataBus sLiveDataBus = new LiveDataBus();
    }

    public static LiveDataBus get() {
        return Lazy.sLiveDataBus;
    }

    private ConcurrentHashMap<String, StickyLiveData> mHashMap = new ConcurrentHashMap<>();

    public StickyLiveData with(String eventName) {

        StickyLiveData liveData = mHashMap.get(eventName);
        if (liveData == null) {
            liveData = new StickyLiveData(eventName);
            mHashMap.put(eventName, liveData);
        }
        return liveData;
    }

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

        private String mEventName;

        private T mStickyData;

        private int mVersion = 0;

        public StickyLiveData(String eventName) {

            mEventName = eventName;
        }

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

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

        public void setStickyData(T stickyData) {
            this.mStickyData = stickyData;
            setValue(stickyData);
        }

        public void postStickyData(T stickyData) {
            this.mStickyData = stickyData;
            postValue(stickyData);
        }

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            observerSticky(owner, observer, false);
        }

        public void observerSticky(LifecycleOwner owner, Observer<? super T> observer, boolean sticky) {
            super.observe(owner, new WrapperObserver(this, observer, sticky));
            owner.getLifecycle().addObserver(new LifecycleEventObserver() {
                @Override
                public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        mHashMap.remove(mEventName);
                    }
                }
            });
        }


        private class WrapperObserver<T> implements Observer<T> {
            private StickyLiveData<T> mLiveData;
            private Observer<T> mObserver;
            private boolean mSticky;

            //标记该liveData已经发射几次数据了,用以过滤老数据重复接收
            private int mLastVersion = 0;

            public WrapperObserver(StickyLiveData liveData, Observer<T> observer, boolean sticky) {


                mLiveData = liveData;
                mObserver = observer;
                mSticky = sticky;

                //比如先使用StickyLiveData发送了一条数据。StickyLiveData#version=1
                //那当我们创建WrapperObserver注册进去的时候,就至少需要把它的version和 StickyLiveData的version保持一致
                //用以过滤老数据,否则 岂不是会收到老的数据?
                mLastVersion = mLiveData.mVersion;
            }

            @Override
            public void onChanged(T t) {
                //如果当前observer收到数据的次数已经大于等于了StickyLiveData发送数据的个数了则return
                if (mLastVersion >= mLiveData.mVersion) {
                    //但如果当前observer它是关心 黏性事件的,则给他。
                    if (mSticky && mLiveData.mStickyData != null) {
                        mObserver.onChanged(mLiveData.mStickyData);
                    }
                    return;
                }

                mLastVersion = mLiveData.mVersion;
                mObserver.onChanged(t);
            }
        }

    }
}

LiveData的原理

LiveData的observe()方法接收两个参数,第一个是LifecycleOwner,第二个是Observer,源码中Observer与Activity的生命周期关联在一起,因此,LiveData能够感知页面的生命周期,也可避免引发的内存泄漏问题。

 @MainThread
 public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
  }

LiveData还有一个observeForever(),和observe()没有太大区别,主要区别在于,当LiveData发生变化时,无论页面处于什么状态,都能收到通知。因此,使用完以后一定要调用removeObserver()停止对LiveData的观察,否则会造成内存泄漏。

 @MainThread
 public void removeObserver(@NonNull final Observer<? super T> observer) {
        assertMainThread("removeObserver");
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
            return;
        }
        removed.detachObserver();
        removed.activeStateChanged(false);
 }
深入浅出Android Jetpack之LiveData LiveData是Jetpack组件的一部分,它是一个可观察的数据存储容器,能够确保在数据变更时,只有处于活跃状态(即当前界面可见或者正在运行)的组件才会收到通知并进行相应的更新。在实际的MVVM架构模式下,ViewModel通常作为LiveData的持有者,负责处理业务逻辑并提供给UI层进行数据绑定。:LiveData默认在主线程中进行数据的推送,如果需要在后台线程中更新数据,可以通过Transformations或其他方式切换线程,保证数据访问的安全性。// 这里模拟异步加载数据操作。 阅读详情

相关推荐

Jetpack常用组件-深入理解LiveData

LiveData是Android Jetpack的核心组件,采用观察者模式实现数据与UI的双向绑定。它具有生命周期感知能力,能自动管理订阅关系,避免内存泄漏,并确保UI只在活跃状态下更新。使用步骤包括:创建LiveData对象(通常在ViewModel中)、添加观察者、更新数据(主线程用value,子线程用postValue)。其源码实现通过ObserverWrapper处理生命周期,使用版本号机制保证数据一致性,并通过线程安全设计支持跨线程更新。核心类包括MutableLiveData、MediatorL

qq_42653920的博客 1908

Android Jetpack 介绍

Jectpcak 的出现 相当于为了androidX打一个补丁 也在众多mvc、mvp、mvvm中脱颖而出 成为一个好的解决方案 Jetpack 是一个由多个库组成的套件。可帮助开发者遵循最佳做法,减少样板代码编写并编写可在各种Android版本和设备中一致运行的代码 让开发者集中精力编写重要的代码 为何使用Jetpack Android Jetpack 组件采用最新的设计方法构建,具有向后兼容性,可以减少崩溃和内存泄露。>消除样板代码 Android Jetpack .

丿灬安之若死 1421

Android Jetpack架构组件(一)带你了解Android Jetpack

本文首发于微信公众号「后厂村码农」 前言 Android已经发展了11年,可以说是比较成熟的技术了,一开始时框架很少,也没有什么规范,所有的代码都是要自己写,比如网络请求,数据库请求,数据解析等等。后来出现了一些框架来帮助开发者快速进行开发,比如XUtils、Volley、OKHttp、EventBus等,随着框架越来越多,一个应用可以有多种技术选型,直接导致应用开发越来越不规范,导致做出来的...

Android进阶三部曲 - 刘望舒 7399

Android jetpck学习

优势 加速开发 消除样板代码(避免过多地写重复的样板代码) 构建高质量的应用(减少崩溃和内存泄漏) 原理 其实是一些库的集合,可组合使用,也可单独使用 架构 数据绑定库:将数据与xml页面绑定 gradle配置,支持dataBinding 创建需要的model xml文件中导入model(选中根布局,alt+Enter),使用@{…}填充内容,可以声明default 重新Build项目 在U...

snoto的专栏 454

Android Jetpack架构组件之 LiveData(使用、源码篇)

1、前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面。 Android Architecture组件是Android Jetpack的一部分,它们是一组库,旨在帮助开发者设计健壮、可测试和可维护的应用程序,包含一下组件: 带你领略Android Je...

浅谈Android 7543

Android Jetpack之LiveData源码分析

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。

蜗牛快跑 3089

Android Jetpack从入门到精通,干货满满

自2018年面世,Jetpac也迎来自己的第五个年头,在当初的基础上又多了许多的新组件。但是,也有很多Android工程师五年过去了都停留在:知道、了解过、但没用过。Jetpack 是Android组件的集合,可帮助开发者遵循最佳实践、让开发者摆脱编写样板代码并简化复杂任务,以便于开发者可将精力集中于真正重要的编码工作。1.1 简介1.2 特性1.3 分类1.4 应用架构11.1 Hilt - Jetpack 推荐的依赖注入类库11.2 Paging3 - 逐步加载和显示数据。

大模型训练 1175

Android Jetpack架构组件(四)之LiveData

一、 LiveData简介 LiveData是Jetpack架构组件Lifecycle 库的一部分,是一个可感知生命周期的可观察容器类 (Observable)。与常规的可观察类不同,LiveData 具有生命周期感知能力,这意味着它具有感知应用组件(如 Activity、Fragment 或 Service)的生命周期的能力,并且LiveData仅更新处于活跃生命周期状态的应用组件观察者。 因此,LiveData具有如下一些特效。 LiveData是一个持有数据的容器类,它持有的数据是可以被观察者订阅的

xiangzhihong8的专栏 905

安卓Android LiveData 超简单实例

便于理解 2.搞个实体类 代码如下(示例): 3.将消息发送给观察者 4.将消息发送给观察者 5.某观察者onChanged 总结 就是这样

IT程序员的编程黑洞(鸽子王)抖音同名 595

使用LiveData的MVP模式Demo

使用LiveData的MVP模式Demo,解决了传统MVP模式接口爆炸的问题,新的MVP设计模式耦合性更低,不强制用户必须实现大量接口

基于OpenSSL的CA建立及证书签发(签发多域名/IP)

自签SSL证书(多域名/IP) 本文基于以下环境: 内核信息:Linux zabbix 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux 系统版本:CentOS Linux release 7.6.1810 (Core) OpenSSL版本:OpenSSL 1.0.2k-fips 26 Jan 2017 【前言】 在基于OpenSSL的CA建立及证书签发一文中(后面统.

hobby云说 4647

Android Jetpack组件(三)ViewModel

对于支持横竖屏切换的应用程序,我们切换横竖屏时,Activity会被重新创建,我们需要考虑数据的存储和恢复。Jetpack为我们提供了ViewModel组件帮我们解决这个问题,ViewModel以注重生命周期的方式存储和管理界面相关的数据。ViewModel独立于配置变化,就算Activity重建,也不会影响ViewModel的生命周期。

八归少年 2085

Halcon dyn_threshold详解

dyn_threshold 原型 dyn_threshold(OrigImage, ThresholdImage : RegionDynThresh : Offset, LightDark : ) 功能 利用局部阈值分割图像 参数列表 OrigImage (input_object):原始图像 ThresholdImage (input_object):处理后图像(一般采用滤波处理) RegionDynThresh (output_object):分割后区域 Offset (input_control):灰

ZiLiangQin的博客 1万+

(四)Android Jetpack 组件之LiveData

1、LiveData到底是个啥? LiveData是可以在给定生命周期内观察到的数据持有者类。 它是一个类,这个类可以干嘛呢? 可以在给定的生命周期内观察数据变化。 给定的生命周期是什么意思? 指的是AppCompatActivity的onStart() 和 onResume()方法。 为什么要是AppCompatActivity 这个类而不是单纯的Activity类呢? 很简单当我们查看AppC...

James-Tom的博客 418

BUUCTF reverse题解汇总

BUUCTF平台刷题过程中做的一些逆向题解的总结归类

于高山之巅,方见大河奔涌;于群峰之上,更觉长风浩荡。 1万+

Springboot+Vue 实现鸿蒙商城管理系统开发实践

通过使用 Springboot 和 Vue 技术栈,我们成功实现了鸿蒙商城管理系统的开发。系统具备用户管理、商品管理、订单管理、库存管理和统计分析等功能,支持 Web 端和鸿蒙端的访问和操作。在开发过程中,我们充分利用了 Springboot 的快速开发优势和 Vue 的组件化开发特点,提高了开发效率和系统的可维护性。同时,通过与鸿蒙设备的集成,实现了多设备之间的数据交互和协同工作,提升了用户体验。

ZXJ_SXT的博客 1324

Android Jetpack架构组件(四)LiveData使用篇

前言: 上一篇我们讲解了Jetpack中Lifecycle原理篇, 本片我来讲讲Jetpack中的另一个重要组件LiveData. LiveData概述 LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveDat...

周将的博客 1182

从芯片选型到光学集成:手持激光测距仪硬件设计全解析

本文全面解析手持激光测距仪的硬件设计,从芯片选型到光学集成,详细介绍了相位法测距技术的核心原理与方案选择。通过模块化设计、信号链路优化及PCB布局技巧,实现毫米级精度。文章还分享了量产化关键控制点,帮助工程师规避常见设计陷阱,提升产品可靠性。

weixin_30425949的博客 445

JetPack初体验

一、Android JetPack——Google多么痛的领悟 最近好几个小伙伴问我什么是Android JetPack,听说这个包好像有点牛,萧哥你会不? 我心想什么鬼!Android JetPack这货不是一个库,是一整套的库,是一种信仰一种态度好么。从前,Android开发者基本都是被放养的。生态基本全靠自建,代表有Square全家桶,Glide,Google自己也肯定是出力的,但是并没有明确Android开发的几个大方向,所以安卓的开发生态一直是百花齐放百家争鸣。带来的问题就是经常出现包引用莫名

augfun的博客 528

Matlab实战:如何用MMG方程预测船舶轨迹(附完整代码)

本文提供了一份基于MMG方程的Matlab实战指南,详细讲解了如何从零构建船舶轨迹预测模型。内容涵盖MMG模型的核心原理、Matlab代码框架设计、动力学函数实现、参数调优与验证方法,并附有完整代码示例,帮助工程师和研究者快速掌握这一船舶操纵性预测的关键技术。

v6b7n8m9q0的博客 518

2026年3月GESP真题及题解(C++七级):物流网络

2026年3月GESP真题及题解(C++七级):物流网络

王老师青少年编程 1124

Android Jetpack,AndroidX介绍

Google在17年的I/O大会上推出了架构组件(Architecture Component) Google在2018 Google I/O 2018大会上发布了新的框架组件,大致如上图所示。Android Jetpack 能帮助您加快应用开发速度,处理类似后台任务、UI 导航以及生命周期管理之类的活动,免去开发者编写样板代码的麻烦,专注提升应用体验。包括这几部分:Architecture、F...

chengzuidongfeng的博客 572

tsfknn 预测R语言中的时间序列

rolling参数应该设置为FALSE,这使得最后的18个观测值成为测试集,其余的作为训练集;如果我们将rolling参数设置为默认值TRUE,那么测试集就不会是一个恒定的向量。lag 滞后参数表示时间序列数据的滞后值。在这个例子中,由于我们的时间序列数据是月度的,我们将参数设置为1:12。作为药品福利计划的一部分,澳大利亚健康保险委员会记录的属于ATC代码A10的产品的每月政府支出(百万美元)。我们将使用tsfknn包,它可以用来预测R语言中的时间序列。格式:ts类别的月度时间序列。

Mrrunsen的博客 323

Android Jetpack系列——Android Jetpack介绍

背景介绍 早在2008年,Google 推出了Android ,但那个时候 Android 刚刚问世,经过这将近11年的发展和不断优化,Android 可以说逐渐变得成熟,方便和应用越来越广。 随着 Android 手机的市场保有量越来越多,APP的研发朝着愈发的简单化,易上手的方向发展。而 Google 也是站在这一个角度出发,如何快速得让一个研发人员开发出一款APP,也可以快速的添加新的...

weixin_34355559的博客 571

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

带你领略Android Jetpack组件的魅力

1、前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面。 Android Architecture组件是Android Jetpack的一部分,它们是一组库,旨在帮助开发者设计健壮、可测试和可维护的应用程序,包含一下组件:  带你领略Android Je...

浅谈Android 3万+

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

上一篇: Android Jetpack组件(三)ViewModel
下一篇: Android Jetpack组件(五)Room
八归少年
八归少年 新星创作者: 操作系统技术领域 新星创作者: 操作系统技术领域
博客等级 码龄9年 9011粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八归少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值