LiveData原理解析和仿写一个LiveDataBus

2024-02-17 17:08

本文主要是介绍LiveData原理解析和仿写一个LiveDataBus,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引入LiveData:

implementation "androidx.lifecycle:lifecycle-viewmodel:2.2.0"

学习内容:

//这个实际上还是继承了LiveData
public class MutableLiveData<T> extends LiveData<T> {@Overridepublic void postValue(T value) {super.postValue(value);}@Overridepublic void setValue(T value) {super.setValue(value);}
}

开始使用

//初始化
MutableLiveData<String> liveData = new MutableLiveData<>();
//有两种发送值的方式
//第一种
liveData.setValue("123");
//第二种
liveData.postValue("456");

接下来从源码的角度来分析这两个方法的区别。
liveData.postValue

	private final Runnable mPostValueRunnable = new Runnable() {@Overridepublic void run() {Object newValue;synchronized (mDataLock) {newValue = mPendingData;mPendingData = NOT_SET;}//noinspection unchecked//postValue切换到主线程,最终还是调用了setValue()setValue((T) newValue);}};protected void postValue(T value) {boolean postTask;synchronized (mDataLock) {postTask = mPendingData == NOT_SET;mPendingData = value;}if (!postTask) {return;}//可以看到这里我们将赋值的操作切换到主线程,然后再执行。ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);}

所以liveData.postValue可以再任意的线程调用,因为最终会切换到主线程。
liveData.setValue

 @MainThreadprotected void setValue(T value) {//断言的方式判断当前是不是主线程assertMainThread("setValue");//每次设置值的时候都会+1mVersion++;mData = value;//分发更新的值dispatchingValue(null);}

所以liveData.setValue只能再主线程中调用。
然后当我们调用了setValue()之后,接着看dispatchingValue这个方法

public abstract class LiveData<T> {static final int START_VERSION = -1;//观察者的 mapprivate SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =new SafeIterableMap<>();private int mVersion = START_VERSION;
......void dispatchingValue(@Nullable ObserverWrapper initiator) {if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;if (initiator != null) {considerNotify(initiator);initiator = null;} else {//因为initiator = null 所以执行这个方法 遍历每个observerfor (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;}// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.//// we still first check observer.active to keep it as the entrance for events. So even if// the observer moved to an active state, if we've not received that event, we better not// notify for a more predictable notification order.if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}//这个判断非常重要哦//刚开始的时候这两个值都为-1//所以第一次进来就会return//但setValue()执行后,mVersion就+1了,所以就不会return了//这样保证了观察者的回调方法不会因为生命周期的多次回调而调用多次//这个判断也是我们下文仿写LiveDataBus的重要判断条件if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;//noinspection unchecked//调用观察者的回调方法,进行更新的操作。observer.mObserver.onChanged((T) mData);}//生命周期改变时会回调
//GenericLifecycleObserver.onStateChanged方法(是感知到生命周期的重要原因)
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);mOwner = owner;}@Overrideboolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}//生命周期改变时会回调这个方法@Overridepublic void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {removeObserver(mObserver);return;}//执行父类里的方法activeStateChanged(shouldBeActive());}@Overrideboolean isAttachedTo(LifecycleOwner owner) {return mOwner == owner;}@Overridevoid detachObserver() {mOwner.getLifecycle().removeObserver(this);}}private abstract class ObserverWrapper {final Observer<? super T> mObserver;boolean mActive;int mLastVersion = START_VERSION;ObserverWrapper(Observer<? super T> observer) {mObserver = observer;}abstract boolean shouldBeActive();boolean isAttachedTo(LifecycleOwner owner) {return false;}void detachObserver() {}void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}// immediately set active state, so we'd never dispatch anything to inactive// ownermActive = newActive;boolean wasInactive = LiveData.this.mActiveCount == 0;LiveData.this.mActiveCount += mActive ? 1 : -1;if (wasInactive && mActive) {onActive();}if (LiveData.this.mActiveCount == 0 && !mActive) {onInactive();}if (mActive) {//分发值 需要更新dispatchingValue(this);}}}
}

到这里观察的回调在哪里调用了,我们就搞清了,我们暂时先不要管onStateChanged再生命周期为什么回调,下文会介绍的不要急。
接下来就是设置观察者了。

liveData.observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {//在这里处理你自己的逻辑}});

我们就来看这个方法内部是怎么执行的。

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {assertMainThread("observe");//判断当前活动是否被销毁,被销毁直接返回,不注册if (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignorereturn;}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;}//所以这里就是等于在activity里写如下的代码//AppCompatActivity.getLifecycle().addObserver(wrapper);//这跟之前我们监听activity生周期的方法一样呢//这就是LiveData为什么能感知生命周期的原因owner.getLifecycle().addObserver(wrapper);}

可以看到这个owner,有的小伙会问,欸?为什么是这个形参的类型是LifecycleOwner这是因为我们的AppCompatActivity继承了FragmentActivity继承了ComponentActivity的实现了LifecycleOwner。

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {......
}public class FragmentActivity extends ComponentActivity implementsViewModelStoreOwner,ActivityCompat.OnRequestPermissionsResultCallback,ActivityCompat.RequestPermissionsRequestCodeValidator {
}public class ComponentActivity extends Activityimplements LifecycleOwner, KeyEventDispatcher.Component {
}

现在我们再来看一种代码

MutableLiveData<String> liveData = new MutableLiveData<>();
liveData.setValue("123");
liveData.observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {}
});

这段代码注意 我们是先发送值,然后注册监听者,大家认为我们可以在onChanged回调时接收到“123”吗?答案是肯定的,但这有点不符合常理了,毕竟我们先发送值,但这时候还没有注册事件监听者,后来才注册的事件监听者,也能收到,这就有点奇怪了,我们来看一下LiveData是怎么实现的。

这就要牵扯到下面这段代码了

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);mOwner = owner;}@Overrideboolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}@Override//每次生命周期变化都会调用public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {removeObserver(mObserver);return;}//调用父类里的方法activeStateChanged(shouldBeActive());}.....
}
private abstract class ObserverWrapper {final Observer<? super T> mObserver;boolean mActive;int mLastVersion = START_VERSION;.......void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}// immediately set active state, so we'd never dispatch anything to inactive// ownermActive = newActive;boolean wasInactive = LiveData.this.mActiveCount == 0;LiveData.this.mActiveCount += mActive ? 1 : -1;if (wasInactive && mActive) {onActive();}if (LiveData.this.mActiveCount == 0 && !mActive) {onInactive();}if (mActive) {//调用更新的值分发dispatchingValue(this);}}}.....
}

这段逻辑,相信从上面看到下面的小伙伴都有印象,所以弄清楚onStateChanged为什么在生命周期改变时会被调用。
owner.getLifecycle().addObserver(wrapper);这句话就是我们观察者被注册到监听者的方法。

public class FragmentActivity extends ComponentActivity implementsViewModelStoreOwner,ActivityCompat.OnRequestPermissionsResultCallback,ActivityCompat.RequestPermissionsRequestCodeValidator {.....@Overridepublic Lifecycle getLifecycle() {return super.getLifecycle();}......
}
public class ComponentActivity extends Activityimplements LifecycleOwner, KeyEventDispatcher.Component {private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);@Overridepublic Lifecycle getLifecycle() {return mLifecycleRegistry;}}

所以当我们getLifecycle().addObserver()得到的对象是LifecycleRegistry.addObserver()

	@Overridepublic void addObserver(@NonNull LifecycleObserver observer) {//获取当前activity处在那个生命周期//DESTROYED:0  INITIALIZED:1State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;//下面这两行代码跟LiveData.observe()里的两行代码差不多的ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);if (previous != null) {return;}LifecycleOwner lifecycleOwner = mLifecycleOwner.get();if (lifecycleOwner == null) {// it is null we should be destroyed. Fallback quicklyreturn;}boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;State targetState = calculateTargetState(observer);mAddingObserverCounter++;while ((statefulObserver.mState.compareTo(targetState) < 0&& mObserverMap.contains(observer))) {pushParentState(statefulObserver.mState);statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));popParentState();// mState / subling may have been changed recalculatetargetState = calculateTargetState(observer);}if (!isReentrance) {// we do sync only on the top level.//到这了sync();}mAddingObserverCounter--;}private void sync() {LifecycleOwner lifecycleOwner = mLifecycleOwner.get();if (lifecycleOwner == null) {Log.w(LOG_TAG, "LifecycleOwner is garbage collected, you shouldn't try dispatch "+ "new events from it.");return;}while (!isSynced()) {mNewEventOccurred = false;// no need to check eldest for nullability, because isSynced does it for us.//if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {backwardPass(lifecycleOwner);}Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();if (!mNewEventOccurred && newest != null&& mState.compareTo(newest.getValue().mState) > 0) {forwardPass(lifecycleOwner);}}mNewEventOccurred = false;}private void forwardPass(LifecycleOwner lifecycleOwner) {Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =mObserverMap.iteratorWithAdditions();//从观察者map 迭代所有的观察者while (ascendingIterator.hasNext() && !mNewEventOccurred) {Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred&& mObserverMap.contains(entry.getKey()))) {pushParentState(observer.mState);//然后就调用这个方法observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));popParentState();}}}private void backwardPass(LifecycleOwner lifecycleOwner) {Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =mObserverMap.descendingIterator();while (descendingIterator.hasNext() && !mNewEventOccurred) {Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred&& mObserverMap.contains(entry.getKey()))) {Event event = downEvent(observer.mState);pushParentState(getStateAfter(event));observer.dispatchEvent(lifecycleOwner, event);popParentState();}}}static class ObserverWithState {State mState;GenericLifecycleObserver mLifecycleObserver;ObserverWithState(LifecycleObserver observer, State initialState) {mLifecycleObserver = Lifecycling.getCallback(observer);mState = initialState;}void dispatchEvent(LifecycleOwner owner, Event event) {State newState = getStateAfter(event);mState = min(mState, newState);//然后到这儿就会回调我们在LiveData里的LifecycleBoundObserver的onStateChanged方法mLifecycleObserver.onStateChanged(owner, event);mState = newState;}}

所以sync()方法最终会导致我们的事件回调(记下这个方法名)
然后我们继续

public class ComponentActivity extends Activityimplements LifecycleOwner, KeyEventDispatcher.Component {......@Override@SuppressWarnings("RestrictedApi")protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);//看到这里,我们把自己传了进去ReportFragment.injectIfNeededIn(this);}......
}
public class ReportFragment extends Fragment {private static final String REPORT_FRAGMENT_TAG = "androidx.lifecycle"+ ".LifecycleDispatcher.report_fragment_tag";public static void injectIfNeededIn(Activity activity) {// ProcessLifecycleOwner should always correctly work and some activities may not extend// FragmentActivity from support lib, so we use framework fragments for activities//这里我们看到我们启动了一个ReportFragmentandroid.app.FragmentManager manager = activity.getFragmentManager();if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();// Hopefully, we are the first to make a transaction.manager.executePendingTransactions();}}@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);dispatchCreate(mProcessListener);dispatch(Lifecycle.Event.ON_CREATE);}@Overridepublic void onStart() {super.onStart();dispatchStart(mProcessListener);dispatch(Lifecycle.Event.ON_START);}@Overridepublic void onResume() {super.onResume();dispatchResume(mProcessListener);dispatch(Lifecycle.Event.ON_RESUME);}private void dispatch(Lifecycle.Event event) {Activity activity = getActivity();if (activity instanceof LifecycleRegistryOwner) {((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);return;}if (activity instanceof LifecycleOwner) {Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();if (lifecycle instanceof LifecycleRegistry) {((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);}}}
.......
}

我们可以看到在ReportFragment的生命周期中都有同一个方法dispatch(),而且最终都会调用getLifecycle().handleLifecycleEvent(event)

 public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {State next = getStateAfter(event);moveToState(next);}private void moveToState(State next) {if (mState == next) {return;}mState = next;if (mHandlingEvent || mAddingObserverCounter != 0) {mNewEventOccurred = true;// we will figure out what to do on upper level.return;}mHandlingEvent = true;//看这个sync(),上面我们就见过这个方法,所以就可以说通了sync();mHandlingEvent = false;}

正是通过这个handleLifecycleEvent调用了sync然后再调用了dispatchEvent然后调用了mLifecycleObserver.onStateChanged

但是我们LiveData一般都不是用来监听生命周期的,都是用来组件间通信的所以我就来仿照LiveDataBus写一个自己的组件通信,但是我们有的时候不需要粘性事件(未注册的监听者不因该监听到注册前所发送过的事件),所以我们需要自己实现一个可以控制黏性的事件通知者。

//黏性事件
public class MyLiveDataBus {private static MyLiveDataBus instance = new MyLiveDataBus();private Map<String, MyMutableLiveData<Object>> liveDataMap;public static MyLiveDataBus getInstance(){return instance;}private MyLiveDataBus(){liveDataMap = new HashMap<>();}public synchronized<T> MyMutableLiveData<T> with(String key,Class<T> clazz){if(!liveDataMap.containsKey(key)){liveDataMap.put(key,new MyMutableLiveData<Object>());}return (MyMutableLiveData<T>) liveDataMap.get(key);}private static class MyMutableLiveData<T> extends MutableLiveData<T> {private boolean isSticky = false;public void observe(@NonNull LifecycleOwner owner, boolean isSticky , @NonNull Observer<? super T> observer) {this.isSticky = isSticky ;observe(owner,observer);}@Overridepublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {super.observe(owner, observer);try {if(!isSticky ){hook((Observer<T>) observer);}} catch (Exception e) {e.printStackTrace();}}//让mLastVersion和mVersion相等,这样可以在注册监听的时候就不会回调onStateChanged了private void hook(Observer<T> observer) throws Exception {Class<LiveData> liveDataClass = LiveData.class;Field mObserversField = liveDataClass.getDeclaredField("mObservers");mObserversField.setAccessible(true);Object mObservers = mObserversField.get(this);Method get = mObservers.getClass().getDeclaredMethod("get", Object.class);get.setAccessible(true);Object invokeEntry = get.invoke(mObservers, observer);Object observerWrapper = null;if(invokeEntry!=null && invokeEntry instanceof Map.Entry){observerWrapper = ((Map.Entry)invokeEntry).getValue();}if(observerWrapper == null){throw new NullPointerException("ObserverWrapper不能为空");}Class<?> superclass = observerWrapper.getClass().getSuperclass();Field mLastVersionField = superclass.getDeclaredField("mLastVersion");mLastVersionField.setAccessible(true);Field mVersionField = liveDataClass.getDeclaredField("mVersion");mVersionField.setAccessible(true);Object o = mVersionField.get(this);mLastVersionField.set(observerWrapper,o);}}
}

在Activity中

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MutableLiveData<String> liveData = MyLiveDataBus.getInstance().with("key",String.class);liveData.postValue("123");}}public class TwoActivity extends AppCompatActivity {LiveDataBus2.BusMutableLiveData<String> liveData;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);liveData = LiveDataBus2.getInstance().with("code", String.class);liveData.observe(TwoActivity.this,false, new Observer<String>() {@Overridepublic void onChanged(String s) {Log.e("!!!!!!!!",s);}});}}

这样我们就可以实现MainActivity组件和TwoActivity组件之间的通信了,可以不在使用Intent(大小限制)了。

追记:
LiveData当我们继承自Activity就会报错(之前的都是继承了AppCompatActivity)

public class MainActivity extends Activity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyLiveDataBus.MyMutableLiveData<String> liveData = MyLiveDataBus.getInstance().with("key",String.class);//这个observe就会报错 因为继承了ActivityliveData.observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {}});liveData.setValue("123");}
}

那我们需要怎么修改呢

public class MainActivity extends Activity {LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);@SuppressLint("RestrictedApi")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ReportFragment.injectIfNeededIn(this);MyLiveDataBus.MyMutableLiveData<String> liveData = MyLiveDataBus.getInstance().with("key",String.class);liveData.observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {}});liveData.setValue("123");}@NonNull@Overridepublic Lifecycle getLifecycle() {return lifecycleRegistry;}}}

这篇关于LiveData原理解析和仿写一个LiveDataBus的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/718454

相关文章

Linux中shell解析脚本的通配符、元字符、转义符说明

《Linux中shell解析脚本的通配符、元字符、转义符说明》:本文主要介绍shell通配符、元字符、转义符以及shell解析脚本的过程,通配符用于路径扩展,元字符用于多命令分割,转义符用于将特殊... 目录一、linux shell通配符(wildcard)二、shell元字符(特殊字符 Meta)三、s

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C

Java解析JSON的六种方案

《Java解析JSON的六种方案》这篇文章介绍了6种JSON解析方案,包括Jackson、Gson、FastJSON、JsonPath、、手动解析,分别阐述了它们的功能特点、代码示例、高级功能、优缺点... 目录前言1. 使用 Jackson:业界标配功能特点代码示例高级功能优缺点2. 使用 Gson:轻量