Android Jetpack之Lifecycle的使用及源码分析

news2024/10/7 18:21:04

Lifecycle生命周期感知型组件可执行操作来响应另一个组件(如 Activity 和 Fragment)的生命周期状态的变化。这些组件有助于您编写出更有条理且往往更精简的代码,此类代码更易于维护。

尤其是在Activity和Fragment在已经默认支持LifeCycle的情况下,我们更有理由来使用它,以便让我们的代码变得更加整洁以及可维护。

本文的内容:

  • 一、Lifecycle的使用
  • 1.1,在Activity中使用
  • 1.2,在Application中使用
  • 二、自定义LifecycleOwner
  • 三、Lifecycle源码分析(知其然,知其所以然)

一、Lifecycle的使用

Lifecycle 出现之前,我们通常都是在生命周期的onStart和onStop中处理,我们的逻辑(比如,获取定位等等),随着项目的基类,我们的onStart和onStop会越来越臃肿,并难以维护。

下面,我们通过Lifecycle来实现。

1.1,在Activity中使用

首先,我们创建一个Lifecycle观察者

public class MyActLifeCycleObserver implements LifecycleObserver {

    private String mObserverNum;

    public MyActLifeCycleObserver(String observerNum) {
        this.mObserverNum = observerNum;
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onCreate() {
        printLog("onCreate");
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onStart() {
        printLog("onStart");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume() {
        printLog("onResume");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onStop() {
        printLog("onStop");
    }

    private void printLog(String eventStatus) {
        Log.d("liu.MyActivity", mObserverNum + ": " + eventStatus);
    }
}

然后,因为Activity默认已经实现了LifecycleOwner。我们可以直接添加到Activity中。如下

public class TestLifeCycleActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getLifecycle().addObserver(new MyActLifeCycleObserver("observer.onCreate"));
    }
}

这样,就完成了,对TestLifeCycleActivity生命周期的监听。在MyActLifeCycleObserver中,处理该Activity的逻辑,很简单吧

在这里插入图片描述

1.2,在Application中使用

之前,我们判断App的前后台运行,都是通过registerActivityLifecycleCallbacks()。在onStart跟onStop中通过计数器来判断App的前后台运行的。

现在,我们完全可以通过LifeCycle,更优雅的实现该功能

首先,跟Activity的监听一样,创建一个观察者

/**
 * Application的Lifecycle。
 * 1,oncreate只会执行一次
 * 2,onDestroy不执行
 */
public class MyAppLifeCycleObserver implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onCreate() {
        printLog("onCreate");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onStart() {
        printLog("onStart");
		//前台
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onStop() {
        printLog("onStop");
		//后台
    }

    private void printLog(String eventStatus) {
        Log.d("liu.MyAppLifeCycle", "--- " + eventStatus);
    }
}

然后,添加到自定义的Application中

public class MyLifecycleApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new MyAppLifeCycleObserver());
    }
}

最后,在MyAppLifeCycleObserver中,判断App的前后台逻辑。这样是不是更优雅呢。

这里需要注意的是,1,监听的Application的onCreate()方法,只会执行一次,不管是不是多进程;2,onDestroy方法不会执行

在这里插入图片描述
在这里插入图片描述

二、自定义LifecycleOwner

如果,我们想让自定义的控件(view,Dialog等),也具有生命周期感知的能力,我们就只需要实现LifecycleOwner,使用 LifecycleRegistry 类,将事件转发到该类,就可以让其具有了感知生命周期的能力。

代码如下:

public class MyActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        lifecycleRegistry = new LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED);
    }

    @Override
    public void onStart() {
        super.onStart();
        lifecycleRegistry.markState(Lifecycle.State.STARTED);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }
}

我们可以照猫画虎,通过上面代码,让自定义view或者Dialog等,也具有生命周期的感知能力

三、Lifecycle源码分析(知其然,知其所以然)

上面,我们一直说LifeCycle已经实现了Activity的生命周期感知能力,就一起来看看源码吧

这里,我们主要从3个方面来分析

  • 首先,就是LifecycleOwner是什么
  • 其次,就是把我们自定义的的Observer添加进去后,发生了什么
  • 最后,就是当Activity生命周期切换的时候,状态是怎么转换的

1,LifecycleOwner作用

LifecycleOwner相当于一个添加观察者的入口。

TestLifeCycleActivity extends AppCompatActivity
...
 AppCompatActivity extends FragmentActivity
...
 FragmentActivity extends ComponentActivity 
...
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner

通过上面,我们看到,通过连续的继承,在ComponentActivity的时候,实现了LifecycleOwner

看下LifecycleOwner类

public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    @NonNull
    Lifecycle getLifecycle();
}

他只有一个方法,就是我们在使用LifeCycle时候的getLifecycle()方法,

查看下Activity的具体实现

    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
	...
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

这里,可以看到,方法只返回了一个LifecycleRegistry。我们再来看下,需要感知Activity生命周期的代码

public class TestLifeCycleActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getLifecycle().addObserver(new MyActLifeCycleObserver("observer.onCreate"));
    }
}

通过这里,我们能确定了,感知生命周期的核心就是LifecycleRegistry这个类了。

先看下这个LifecycleRegistry的初始化,因为是成员变量,所以,每个Activity只会存在一个

    public LifecycleRegistry(@NonNull LifecycleOwner provider) {
        mLifecycleOwner = new WeakReference<>(provider);
        mState = INITIALIZED;
    }

这里,可以看到,传入的了一个LifecycleOwner,这个owner就是Activity(现在,分析的是Activity)
做了2个事:

  • 1,把LifecycleOwner通过mLifecycleOwner保存
  • 2,初始化mState的状态

下面,我们分析,添加观察者都做了什么事情

getLifecycle().addObserver()

2,看下添加观察者的源码

 @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
		//如果observer已经存在,直接返回
        if (previous != null) {
            return;
        }
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
		//如果lifecycleOwner(Activity)已经destroy,直接返回
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }
		
		//这里是为了计算State的状态,以及是否需要同步其它Observer的状态State
		//毕竟可以再Event的不同阶段(onCreate,onStart)都可以添加Observer
        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 recalculate
            targetState = calculateTargetState(observer);
        }

        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }

这里,首先是把observer观察者放到mObserverMap里面

3,当Activity生命周期切换时,Lifecycle是怎么记录状态的

1,首先看下ComponentActivity的onCreate()方法

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         ReportFragment.injectIfNeededIn(this);
         }
}

该Activity实现了LifecyclOwner接口,并在onCreate调用了ReportFragment.injectIfNeededIn(this);

接着看下 ReportFragment.injectIfNeededIn(this);

 public static void injectIfNeededIn(Activity activity) {
        if (Build.VERSION.SDK_INT >= 29) {
            // On API 29+, we can register for the correct Lifecycle callbacks directly
            activity.registerActivityLifecycleCallbacks(
                    new LifecycleCallbacks());
        }
        
        android.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();
        }
    }

该段代码的作用就是把一个空白的ReportFragment通过FragmentManager添加到Activity上,使其有观察Activity生命周期的能力。(SDK大于29的话,通过registerActivityLifecycleCallbacks方式监听Activity生命周期)
这种方式,有没有熟悉的感觉呢,当然啦,根本就是和我们常用的大名鼎鼎的图片加载框架Glide,使用的是一种监听方式。

看下Fragment的生命周期,是否会分发生命周期

public class ReportFragment extends Fragment {

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatchCreate(mProcessListener);
        dispatch(Lifecycle.Event.ON_CREATE);
    }

    @Override
    public void onStart() {
        super.onStart();
        dispatchStart(mProcessListener);
        dispatch(Lifecycle.Event.ON_START);
    }

    @Override
    public void onResume() {
        super.onResume();
        dispatchResume(mProcessListener);
        dispatch(Lifecycle.Event.ON_RESUME);
    }
    @Override
    public void onStop() {
        super.onStop();
        dispatch(Lifecycle.Event.ON_STOP);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        dispatch(Lifecycle.Event.ON_DESTROY);
        // just want to be sure that we won't leak reference to an activity
        mProcessListener = null;
    }

在这里我们就看到了,Fragment的每个生命周期,都会调用disatch()的方法

看下dispatch方法

 private void dispatch(@NonNull Lifecycle.Event event) {
		//前面说了,SDK>29的话,会调用 registerActivityLifecycleCallbacks方式监听生命周期
        if (Build.VERSION.SDK_INT < 29) {
            // Only dispatch events from ReportFragment on API levels prior
            // to API 29. On API 29+, this is handled by the ActivityLifecycleCallbacks
            // added in ReportFragment.injectIfNeededIn
            dispatch(getActivity(), event);
        }
    }

...

    static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
        if (activity instanceof LifecycleRegistryOwner) {
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        }
		//这里就会调用LifecycleRegistry的handleLifecycleEvent方法
        if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }

到这里,我们看到了生命周期变化,监听的全过程。
1,给Activity添加一个空白的Fragment
2,通过Fragment的生命周期监听,最终回调到Activity的成员变量LifecycleRegistry#handleLifecycleEvent()方法

再次回到LifecycleRegistry里面看看handleLifecycleEvent()方法

 public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
		//这里把event转换成State保存
        State next = getStateAfter(event);
        moveToState(next);
    }

    private void moveToState(State next) {
		//如果当前的状态跟传入的状态一样的话,不改变
		//猜测,Application中如果多进程的话,onCreate()方法也只走一次,是不是因为这个原因呢
        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();
        mHandlingEvent = false;
    }
	
	...

	static State getStateAfter(Event event) {
        switch (event) {
			//这里的把Event转换成State,为什么ON_CREATE/ON_STOP都转成年CREATED,是因为State属于LifecycleRegistry,通用
			//而Event更接近Activity的周期。这样的话,扩展性就出来了
            case ON_CREATE:
            case ON_STOP:
                return CREATED;
            case ON_START:
            case ON_PAUSE:
                return STARTED;
            case ON_RESUME:
                return RESUMED;
            case ON_DESTROY:
                return DESTROYED;
            case ON_ANY:
                break;
        }
        throw new IllegalArgumentException("Unexpected event value " + event);
    }

这里除了判断,把mState赋值成新的State状态。就是走了一个sync()方法,从名字看,应该是同步状态用的

看下源码

 private void sync() {
		//判断宿主是否存在
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                    + "garbage collected. It is too late to change lifecycle state.");
        }
		//如果没有同步过的话。从mObserverMap获取数据,判断走backwardPass还是forwardPass方法
        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;
    }

	...
	//是否同步过,判断条件:1,是否有观察者;2,是否观察者mObserverMap集合的状态跟mState一样
	private boolean isSynced() {
        if (mObserverMap.size() == 0) {
            return true;
        }
        State eldestObserverState = mObserverMap.eldest().getValue().mState;
        State newestObserverState = mObserverMap.newest().getValue().mState;
        return eldestObserverState == newestObserverState && mState == newestObserverState;
    }


看下backwordPass和forwardPass代码


    private void forwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
                mObserverMap.iteratorWithAdditions();
        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()))) {
                
                observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
                
            }
        }
    }

    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()))) {
                    //State转换成Event
                Event event = downEvent(observer.mState);
                //分发给观察者
                observer.dispatchEvent(lifecycleOwner, event);
                
            }
        }
    }
	

	...

	static class ObserverWithState {
        State mState;
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }

从代码,可以看出。不管走哪个方法,都会遍历mObserverMap集合。这个集合在开始的时候已经看过,就是用来存观察者的集合。

遍历之后,把State转换成Event,调用observer.dispatchEvent()方法,调用ObserverWithState#dispatchEvent()方法,来回调观察者对应的当前的Activity生命周期。

到这里,基本就看完了,那什么时候,执行forwardPass,什么时候执行backwardPass()方法呢。

因为枚举enum类型的compareTo()方法,比较的是序数差。所以,我们需要看下State枚举类

public enum State {

        DESTROYED,

        INITIALIZED,

        CREATED,


        STARTED,

        RESUMED;

        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }

看到每个State定义后,我们通过官网的图,知道。
在这里插入图片描述

forwardPass()方法,是State,按照箭头向右走时执行(INITIALIZED–CREATED–STARTED–RESUMED),并获取相应的Event
backwardPass()方式,是State,按照箭头向左走时执行(RESUMED–STARTED–CREATED–INITIALIZED),并获取相应的Event

通过这2个方法内部的downEvent/upEvent()也可以知道


  private static Event downEvent(State state) {
        switch (state) {
            case INITIALIZED:
                throw new IllegalArgumentException();
            case CREATED:
                return ON_DESTROY;
            case STARTED:
                return ON_STOP;
            case RESUMED:
                return ON_PAUSE;
            case DESTROYED:
                throw new IllegalArgumentException();
        }
        throw new IllegalArgumentException("Unexpected state value " + state);
    }

    private static Event upEvent(State state) {
        switch (state) {
            case INITIALIZED:
            case DESTROYED:
                return ON_CREATE;
            case CREATED:
                return ON_START;
            case STARTED:
                return ON_RESUME;
            case RESUMED:
                throw new IllegalArgumentException();
        }
        throw new IllegalArgumentException("Unexpected state value " + state);
    }

Lifecycle的整体流程

1,Activity添加Lifecycle观察者

在这里插入图片描述

2,当Activity生命周期发生变化通知观察者

在这里插入图片描述

猜测。
因为Lifecycle生命周期的监听,不光可以用在Activity,Fragment等当中,在自定义View,Dialog或者其它我们有可以定义Event的组件上都是可以使用的。所以,Lifecycle内容维护的是State而不是Activity等独有的Event。这样扩展性更强,也更独立。

官网文档:https://developer.android.google.cn/topic/libraries/architecture/lifecycle#java

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/27835.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【第五部分 | JS WebAPI】3:DOM 节点操作

目录 | 节点操作 1-1 概述 2-1 获取父节点 3-1 获取子节点&#xff08;获取所有子对象 不推荐&#xff09; 3-2 获取子节点&#xff08;获取所有子【元素节点】&#xff09; 3-3 获取首尾子节点 4-1 获取兄弟节点 5-1 动态创建、添加节点 5-2 案例&#xff1a;评论区 …

性能测试_JMeter_connection timed out :connect

jmeter报错:failed:connection timed out :connect/java.net.BindException: Address already in use: connect java.net.BindException: Address already in use: connectat java.net.DualStackPlainSocketImpl.connect0(Native Method)at java.net.DualStackPlainSocketImpl…

Linux系统上安装软件

安装jdk&#xff0c;安装tomcat&#xff0c;安装Mysql 四种安装方式&#xff1a; 安装jdk 1.去这个网站上下载linux版本的jdk Java Archive Downloads - Java SE 8 2.在虚拟机中的服务器终端中输入ifconfig&#xff08;注意不是ipconfig&#xff0c;而是ifconfig…

智慧机场解决方案-最新全套文件

智慧机场解决方案-最新全套文件一、建设背景二、建设思路三、建设方案四、获取 - 智慧机场全套最新解决方案合集一、建设背景 中国处在机场持续大规模建设过程中&#xff0c;政府也有意愿建设机场作为城市名片&#xff0c;经济持续增长会带来机场的持续建设&#xff1b;我国机…

螺旋模型的优点与缺点

螺旋模型&#xff1a; 特点&#xff1a; 螺旋模型在“瀑布模型”的每一个开发阶段前引入一个非常严格的风险识别、风险分析和风险控制&#xff0c;它把软件项目分解成一个个小项目。每个小项目都标识一个或多个主要风险&#xff0c;直到所有的主要风险因素都被确定 螺旋模型强…

Copilot:AI自动写代码,人工智能究竟还能取代什么?

Copilot&#xff1a;AI自动写代码&#xff0c;人工智能究竟还能取代什么&#xff1f; 前言 在AI绘画掀起一阵热潮之后&#xff0c;AI写代码又逐渐进入了我们的视野&#xff0c;似乎这一步我们还没想到就迅速到来了&#xff0c;难道说AI在取代画家之后&#xff0c;还要取代程序…

引擎入门 | Unity UI简介–第1部分(7)

本期我们继续为大家进行Unity UI简介&#xff08;第一部分&#xff09;的后续教程 本篇内容 14.放置标题图像 15.添加开始按钮 16.定位按钮 文章末尾可免费获取教程源代码 本篇Unity UI简介&#xff08;第一部分&#xff09;篇幅较长&#xff0c;分为十篇&#xff0c;本篇…

sqli-labs/Less-48

欢迎界面还是以sort为注入参数 接下来进行注入类型的判断 首先输入一下内容 sortrand() 多尝试几次 发现界面会发生变化 所以这一关属于数字型注入 然后我们选择使用报错注入 尝试输入一下内容 sortupdatexml(1,if(11,concat(0x7e,database(),0x7e),1),1)-- 回显如下 呦…

网络层 408真题 大题详解

1、【2009】 第一问有两种分配可能性&#xff0c;要想到位 记住&#x1f6a9; 路由器到互联网的路由相当于默认路由0/0 即目的地址0.0.0.0 子网掩码0.0.0.0 2、【2015】 注意&#x1f6a9;DHCP服务器不能转发信息 要观察到本图网络拓扑是同一个网络&#xff0c;在同一个网络中…

Linux系统man帮助一文通-尚文网络xUP楠哥

~~全文共1453字&#xff0c;阅读需约5分钟。 进Q群11372462&#xff0c;领取专属报名福利&#xff0c;包含云计算学习路线图代表性实战训练大厂云计算面试题资料! Linux帮助手册的常见章节 man是Manual的缩写&#xff0c;用来查看系统中命令和配置的帮助信息。Linux本地系统上…

Java#21(抽象与接口)

目录 一.抽象方法和抽象类 1.抽象方法: 2.抽象类: 3.注意: 二.接口 1.接口的定义 2.注意 3.接口中成员的特点 三.接口中的方法 1.JDK7以前: 接口中只能定义抽象方法2.JDK8: 接口中可以定义有方法体的方法(默认、静态) 3.JDK9: 接口中可以定义私有方法 一.抽象方法和…

【Call for papers】DSN-2023(CCF-B/截稿日期: 2022年12月7日)

文章目录1.会议信息2.时间节点3.论文主题On behalf of the Organizing Committee, we extend you a warm welcome to the 53rd Annual IEEE/IFIP International Conference on Dependable Systems and Networks (DSN 2023), organized by the University of Coimbra, Portugal.…

[ Linux ] 如何查看Linux系统版本

文章目录查看Linux内核Kernel的场景情况查看 Linux 版本的几种方式1、通过查看 redhat-release &#xff08;可查看小版本&#xff09;2、使用 lsb_release 命令 &#xff08;可查看小版本&#xff09;3、使用 hostnamectl 命令 &#xff08;只可查看大版本&#xff09;4、通过…

使用NNO区域进行色偏检测

想做图像的色偏检测&#xff0c;网上的资料全是同一套代码&#xff0c;就是2013年那个计算等价圆&#xff0c;然后直接用D-r>9 and K>0.6) or K>1.5&#xff0c;判断的代码&#xff08;相信大家都查到过了&#xff09; 但是色偏问题并不是这样简单的判断就可以的&…

一文掌握Python虚拟环境-提升你的开发效率

在真正开始Python代码编写、编译、运行、调试和开发项目之前&#xff0c;必须要了解下Python的虚拟环境的配置&#xff0c;熟悉使用后&#xff0c;会大大提升后续的开发效率&#xff0c;减少非代码原因导致的问题。virtualenv就是Python中的Virtual Environment-虚拟环境。本文…

C#界面里Form.HelpButton 属性的使用

C#界面里Form.HelpButton 属性的使用 Form.HelpButton 属性是获取或设置一个值,该值指示是否应在窗体的标题框中显示“帮助”按钮。 在一般的开发中,很少有人使用这个属性,因为程序比较简单,只要用户一上手就可以使用了。 如果界面比较复杂,或者说功能比较多,就需要使…

04【MyBatis的类型处理器】

四、MyBatis的类型处理器 4.1 typeAliases别名配置 类型别名是为 Java 类型设置一个短的名字&#xff0c;可以方便我们引用某个类。 我们仔细观察mapper.xml配置文件&#xff0c;会发现不管是入参&#xff08;paramterType&#xff09;还是出参&#xff08;ResultType&#…

大数据面试题(三):MapReduce核心高频面试题

文章目录 MapReduce核心高频面试题 一、ReduceTask工作机制 二、请描述mapReduce有几种排序及排序发生的阶段&#xff1f; 1、排序的分类 2、自定义排序WritableComparable 3、排序发生的阶段 三、请描述mapReduce中shuffle阶段的工作流程&#xff0c;如何优化shuffle阶…

Android App开发手机阅读中实现平滑翻书效果和卷曲翻书动画实战(附源码 简单易懂 可直接使用)

需要图片集和源码请点赞关注收藏后评论区留言~~~ 一、平滑翻书效果 与纸质书籍类似&#xff0c;手机上的电子书也有很多页&#xff0c;逐页浏览可采用翻页视图&#xff0c;然而翻页视图犹如一幅从左到右的绵长画卷&#xff0c;与现实生活中上下层叠的书籍并不相像&#xff0c;…

百度paddle框架 目标检测

random recording 随心记录 What seems to us as bitter trials are often blessings in disguise. 看起来对我们痛苦的试炼&#xff0c;常常是伪装起来的好运。 数据集准备 2183张图片&#xff0c;训练集1693张&#xff0c;验证集245&#xff0c;测试集245张。 包含7种昆虫&a…