Android--Jetpack--Lifecycle详解

news2024/10/7 16:23:39

富贵本无根,尽从勤里得

一,定义

Lifecycle 是一个具备宿主生命周期感知能力的组件。它持有组件(Activity/Fragment)生命周期状态信息,并且允许其观察者监听宿主生命周期状态变化。

顾名思义,Lifecycle的主要作用其实就是帮助我们监听Activity或者Fragment的生命周期,不需要我们自己去定义回调接口来监听了,这样就使我们的代码更加简洁,逻辑更加清晰。

二,角色介绍

1,Lifecycle(生命周期) :一个核心抽象类,用于存储有关组件(如 activity/fragment )的生命周期状态的信息,并允许其他对象观察此状态。继承该类的子类,表示本身是一个 具有Android生命周期特性的对象。

2,LifecycleOwner:核心接口,Lifecycle 持有者,该接口的实现类表示能够为外部提供Lifecycle实例。具有 Android 生命周期的类。这些事件可以被自定义组件用来处理生命周期的变化,而不需要在 Activity/Fragment 中实现任何代码。

3,LifecycleRegistry:核心类,Lifecycle 的实现类,可以处理多个观察者。实现 Lifecycle 定义生命周期观察订阅,生命周期查询的方法。还实现了架构中,生命周期变化时触发的自身状态处理和相关对观察者的订阅回调的逻辑。

4,LifecycleObserver:观察者,将一个类标记为生命周期观察者。实现该接口的类,通过注解的方式,可以通过被 LifecycleOwner 类的 addObserver() 方法注册,LifecycleObserver 便可以观察到 LifecycleOwner 的生命周期事件。

5,State :当前生命周期所处的状态。

6,Event :当前生命周期改变对应的事件。从框架和 Lifecycle 类分派的生命周期事件。这些事件对应到 activity/fragment 中的回调事件。

三,基本使用

第一张使用方式非常简单:

1,添加依赖:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1"
implementation "androidx.lifecycle:lifecycle-common:2.5.1"

2,自定义一个类,这个类就是观察者,实现上面我们提到的LifecycleObserver 接口

定义方法,实现需要监控的生命周期,最主要的是注解

 @OnLifecycleEvent

以及上面提到的生命周期所处的状态:

public class YuanZhenLifecycleObserver implements LifecycleObserver {


    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    void onCreate(){
        System.out.println("yz-----onCreate");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onStart(){
        System.out.println("yz-----onStart");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    void onResume(){
        System.out.println("yz-----onResume");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    void onPause(){
        System.out.println("yz-----onPause");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onStop(){
        System.out.println("yz-----onStop");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestory(){
        System.out.println("yz-----onDestory");
    }

}

 3,在需要被观察的宿主中,注册刚刚我们创建的观察者:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getLifecycle().addObserver(new YuanZhenLifecycleObserver());
        View viewById = findViewById(R.id.txt);
        viewById.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent =new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
                finish();
            }
        });
    }


}

SecondActivity代码如下:

public class SecondActivity extends AppCompatActivity {

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

最后,运行后点击按钮,输出如下日志:

 至此,MainActivity的生命周期,就被我们轻松的观察到了。

第二种实现方式:

上一种实现方式方法已经过时了,所以我们推荐这种实现方式,直接实现接口DefaultLifecycleObserver 

然后我们重写它的生命周期方法即可:

public class YuanZhenFullObserver implements DefaultLifecycleObserver {

    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onCreate(owner);
        System.out.println("yz-----onCreate");
    }

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onStart(owner);
        System.out.println("yz-----onStart");
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onResume(owner);
        System.out.println("yz-----onResume");
    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onPause(owner);
        System.out.println("yz-----onPause");
    }

    @Override
    public void onStop(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onStop(owner);
        System.out.println("yz-----onStop");
    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onDestroy(owner);
        System.out.println("yz-----onDestroy");
    }
}

然后再MainActivity使用:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getLifecycle().addObserver(new YuanZhenFullObserver());
        View viewById = findViewById(R.id.txt);
        viewById.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent =new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
                finish();
            }
        });
    }


}

运行后输出:

使用方式都非常的简单高效。

四,基本原理

从上面的使用中我们就可以看出,lifecycle显然是使用了观察者模式,如果对于观察者模式不清楚的,建议看下文章Android设计模式--观察者模式-CSDN博客

 我们看源码,只能是先从使用入手:

getLifecycle().addObserver(new YuanZhenFullObserver());

通过addObserver方法,我们找到了Lifecycle这个抽象类:

public abstract class Lifecycle {

    
    //使用的入口
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);

    
    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);

    。。。。
  
}

它的实现类LifecycleRegistry 中addObserver方法:

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    enforceMainThreadIfNeeded("addObserver");
    //判断当前的生命周期,将当前生命周期保存
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    //将YuanZhenLifecycleObserver这个观察者对象保存起来
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
    if (previous != null) {
        return;
    }
    //获取到当前的被观察者 也就是MainActivity
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) {
        // it is null we should be destroyed. Fallback quickly
        return;
    }
    boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    //计算当前生命周期
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        pushParentState(statefulObserver.mState);
        final Event event = Event.upFrom(statefulObserver.mState);
        if (event == null) {
            throw new IllegalStateException("no event up from " + statefulObserver.mState);
        }
        statefulObserver.dispatchEvent(lifecycleOwner, event);
        popParentState();
        // mState / subling may have been changed recalculate
        targetState = calculateTargetState(observer);
    }
    if (!isReentrance) {
        // we do sync only on the top level.
        sync();
    }
    mAddingObserverCounter--;
}

上面的 LifecycleOwner lifecycleOwner = mLifecycleOwner.get();是怎么来的呢?

再MainActivity中使用getLifecycle()方法,就进入到了它的父类ComponentActivity:

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


    //创建LifecycleRegistry 实例
    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    
    //获取到创建的LifecycleRegistry 实例
    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

        @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // Restore the Saved State first so that it is available to
        // OnContextAvailableListener instances
        mSavedStateRegistryController.performRestore(savedInstanceState);
        mContextAwareHelper.dispatchOnContextAvailable(this);
        super.onCreate(savedInstanceState);
        //创建一个透明的fragment
        ReportFragment.injectIfNeededIn(this);
        if (mContentLayoutId != 0) {
            setContentView(mContentLayoutId);
        }
    }

    。。。。

}

ComponentActivity实现了LifeCyclerOwern接口,在ComponentActivity这个类中,创建了LifecycleRegistry,并将它本省传递给了LifecycleRegistry。

在这个类的onCreate方法中,有一个非常重要的方法,ReportFragment.injectIfNeededIn(this);它创建了一个透明的fragment。我们看看这个fragment里面干了什么。

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public class ReportFragment extends android.app.Fragment {
    private static final String REPORT_FRAGMENT_TAG = "androidx.lifecycle"
            + ".LifecycleDispatcher.report_fragment_tag";

    public static void injectIfNeededIn(Activity activity) {
        if (Build.VERSION.SDK_INT >= 29) {
            //注册回调
            LifecycleCallbacks.registerIn(activity);
        }
        //绑定fragment
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
           
            manager.executePendingTransactions();
        }
    }

    @SuppressWarnings("deprecation")
    static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
        if (activity instanceof LifecycleRegistryOwner) {
        //如果activity实现了LifecycleOwner接口 调用handleLifecycleEvent
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        }

        if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }

    static ReportFragment get(Activity activity) {
        return (ReportFragment) activity.getFragmentManager().findFragmentByTag(
                REPORT_FRAGMENT_TAG);
    }

    private ActivityInitializationListener mProcessListener;

    private void dispatchCreate(ActivityInitializationListener listener) {
        if (listener != null) {
            listener.onCreate();
        }
    }

    private void dispatchStart(ActivityInitializationListener listener) {
        if (listener != null) {
            listener.onStart();
        }
    }

    private void dispatchResume(ActivityInitializationListener listener) {
        if (listener != null) {
            listener.onResume();
        }
    }

    @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 onPause() {
        super.onPause();
        dispatch(Lifecycle.Event.ON_PAUSE);
    }

    @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;
    }

    private void dispatch(@NonNull Lifecycle.Event event) {
        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);
        }
    }

    void setProcessListener(ActivityInitializationListener processListener) {
        mProcessListener = processListener;
    }

    interface ActivityInitializationListener {
        void onCreate();

        void onStart();

        void onResume();
    }

    // this class isn't inlined only because we need to add a proguard rule for it (b/142778206)
    // In addition to that registerIn method allows to avoid class verification failure,
    // because registerActivityLifecycleCallbacks is available only since api 29.
    @RequiresApi(29)
    static class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks {

        static void registerIn(Activity activity) {
            activity.registerActivityLifecycleCallbacks(new LifecycleCallbacks());
        }

        @Override
        public void onActivityCreated(@NonNull Activity activity,
                @Nullable Bundle bundle) {
        }

        @Override
        public void onActivityPostCreated(@NonNull Activity activity,
                @Nullable Bundle savedInstanceState) {
            dispatch(activity, Lifecycle.Event.ON_CREATE);
        }

        @Override
        public void onActivityStarted(@NonNull Activity activity) {
        }

        @Override
        public void onActivityPostStarted(@NonNull Activity activity) {
            dispatch(activity, Lifecycle.Event.ON_START);
        }

        @Override
        public void onActivityResumed(@NonNull Activity activity) {
        }

        @Override
        public void onActivityPostResumed(@NonNull Activity activity) {
            dispatch(activity, Lifecycle.Event.ON_RESUME);
        }

        @Override
        public void onActivityPrePaused(@NonNull Activity activity) {
            dispatch(activity, Lifecycle.Event.ON_PAUSE);
        }

        @Override
        public void onActivityPaused(@NonNull Activity activity) {
        }

        @Override
        public void onActivityPreStopped(@NonNull Activity activity) {
            dispatch(activity, Lifecycle.Event.ON_STOP);
        }

        @Override
        public void onActivityStopped(@NonNull Activity activity) {
        }

        @Override
        public void onActivitySaveInstanceState(@NonNull Activity activity,
                @NonNull Bundle bundle) {
        }

        @Override
        public void onActivityPreDestroyed(@NonNull Activity activity) {
            dispatch(activity, Lifecycle.Event.ON_DESTROY);
        }

        @Override
        public void onActivityDestroyed(@NonNull Activity activity) {
        }
    }
}

从这个fragment中我们可以看出,ReportFragment的生命周期函数都调用了dispatch()方法,而dispatch()方法则会判断Activity是否实现了LifecycleOwner接口,如果实现了该接口就调用LifecycleRegister的handleLifecycleEvent()。再来看看handleLifecycleEvent:

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    enforceMainThreadIfNeeded("handleLifecycleEvent");
    moveToState(event.getTargetState());
}
private void moveToState(State next) {
    if (mState == next) {
        return;
    }
    if (mState == INITIALIZED && next == DESTROYED) {
        throw new IllegalStateException("no event down from " + mState);
    }
    mState = next;
    if (mHandlingEvent || mAddingObserverCounter != 0) {
        mNewEventOccurred = true;
        // we will figure out what to do on upper level.
        return;
    }
    mHandlingEvent = true;
    sync();
    mHandlingEvent = false;
    if (mState == DESTROYED) {
        mObserverMap = new FastSafeIterableMap<>();
    }
}


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.");
    }
    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);
        }
        Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
        if (!mNewEventOccurred && newest != null
                && mState.compareTo(newest.getValue().mState) > 0) {
            forwardPass(lifecycleOwner);
        }
    }
    mNewEventOccurred = false;
}

事件发生的时候,先得到当前activity应该出现的下一个状态,

moveToState(next); mState = next;更新现在的状态

sync();

backwardPass(lifecycleOwner);逆推

forwardPass(lifecycleOwner);正推

看看这两个方法:

private void forwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
            mObserverMap.iteratorWithAdditions();
    while (ascendingIterator.hasNext() && !mNewEventOccurred) {
        Map.Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            pushParentState(observer.mState);
            final Event event = Event.upFrom(observer.mState);
            if (event == null) {
                throw new IllegalStateException("no event up from " + observer.mState);
            }
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}
private void backwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    while (descendingIterator.hasNext() && !mNewEventOccurred) {
        Map.Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            Event event = Event.downFrom(observer.mState);
            if (event == null) {
                throw new IllegalStateException("no event down from " + observer.mState);
            }
            pushParentState(event.getTargetState());
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}

大致原理请看下图:

然后就调用 observer.dispatchEvent(lifecycleOwner, event); 生成观察者适配器:

static class ObserverWithState {
    State mState;
    LifecycleEventObserver mLifecycleObserver;
    ObserverWithState(LifecycleObserver observer, State initialState) {
        //创建观察者adapter 并将观察者传入adapter 
        mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
        mState = initialState;
    }
    void dispatchEvent(LifecycleOwner owner, Event event) {
        State newState = event.getTargetState();
        mState = min(mState, newState);
        mLifecycleObserver.onStateChanged(owner, event);
        mState = newState;
    }
}

mLifecycleObserver.onStateChanged(owner, event);将状态的变化通知给了观察者,来看看具体实现:

class FullLifecycleObserverAdapter implements LifecycleEventObserver {

    private final FullLifecycleObserver mFullLifecycleObserver;
    private final LifecycleEventObserver mLifecycleEventObserver;

    FullLifecycleObserverAdapter(FullLifecycleObserver fullLifecycleObserver,
            LifecycleEventObserver lifecycleEventObserver) {
        mFullLifecycleObserver = fullLifecycleObserver;
        mLifecycleEventObserver = lifecycleEventObserver;
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
        switch (event) {
            case ON_CREATE:
                mFullLifecycleObserver.onCreate(source);
                break;
            case ON_START:
                mFullLifecycleObserver.onStart(source);
                break;
            case ON_RESUME:
                mFullLifecycleObserver.onResume(source);
                break;
            case ON_PAUSE:
                mFullLifecycleObserver.onPause(source);
                break;
            case ON_STOP:
                mFullLifecycleObserver.onStop(source);
                break;
            case ON_DESTROY:
                mFullLifecycleObserver.onDestroy(source);
                break;
            case ON_ANY:
                throw new IllegalArgumentException("ON_ANY must not been send by anybody");
        }
        if (mLifecycleEventObserver != null) {
            mLifecycleEventObserver.onStateChanged(source, event);
        }
    }
}

FullLifecycleObserverAdapter 在创建时,会持有LifecycleOwner ,当调用onStateChanged时,会调用具体观察者LifecycleOwner 的具体生命周期方法。

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

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

相关文章

[论文阅读]Sparse Fuse Dense

SFD Sparse Fuse Dense: Towards High Quality 3D Detection with Depth Completion 论文网址&#xff1a;SFD 论文代码&#xff1a;SFD 论文简读 本文主要关注如何利用深度完成技术提高三维目标检测的质量。论文提出了一种名为 SFD&#xff08;Sparse Fuse Dense&#xff0…

SQL server 2016安装

1、关系数据库的基本概念。 行&#xff1a;每行成为一条“记录”或“元组”&#xff0c;用于描述一个对象的信息。 列&#xff1a;每列称为一个“字段”或“属性”&#xff0c;用于描述对象的一个属性。 2、主键与外键。 主键&#xff1a;键&#xff0c;即关键字。主键由一个或…

CentOS或RHEL安装vscode

下载rpm安装包 网络下载或者下载到本地再上传到服务器&#xff0c;点击访问国内下载地址&#xff0c;不需要积分curl -fOL https://github.com/coder/code-server/releases/download/v4.19.1/code-server-4.19.1-amd64.rpm安装 rpm -i code-server-4.19.1-amd64.rpm关闭和禁用…

高端网站设计公司 -蓝蓝设计数据可视化大屏服务

UI设计公司-蓝蓝设计&#xff08;北京兰亭妙微科技有限公司&#xff09;是一支由清华美院毕业的专业团队组成的设计公司。我们的设计师们在大屏科研信息软件UI设计领域拥有多年的工作经验和丰富的行业知识。我们对设计充满热爱&#xff0c;设计不仅是我们的专业和职业&#xff…

locked1勒索病毒,刚攻击完海康威视系统,又再针对速达软件服务器攻击

导言&#xff1a; .locked、.locked1勒索病毒正成为数字安全的一大威胁。本文91数据恢复将深入介绍.locked、.locked1勒索病毒的特点、如何有效恢复被其加密的数据文件&#xff0c;以及预防这一数字噩梦的方法。如果您正在经历勒索病毒数据恢复的困境&#xff0c;我们愿意与您…

【动态规划】LeetCode-62.不同路径

&#x1f388;算法那些事专栏说明&#xff1a;这是一个记录刷题日常的专栏&#xff0c;每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目&#xff0c;在这立下Flag&#x1f6a9; &#x1f3e0;个人主页&#xff1a;Jammingpro &#x1f4d5;专栏链接&…

webGL开发学科演示项目方案

开发学科演示项目需要考虑到教育目标、互动性和用户体验。以下是一个可能的技术方案&#xff0c;可用于实现这样的项目&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.WebGL 框架&#xff1a; 选择…

java企业财务管理系统springboot+jsp

1、基本内容 &#xff08;1&#xff09;搭建基础环境&#xff0c;下载JDK、开发工具eclipse/idea。 &#xff08;2&#xff09;通过HTML/CSS/JS搭建前端框架。 &#xff08;3&#xff09;下载MySql数据库&#xff0c;设计数据库表&#xff0c;用于存储系统数据。 &#xff08;4…

微信小程序自定义tabBar简易实现

文章目录 1.app.json设置custom为true开启自定义2.根目录创建自定义的tab文件3.app.js全局封装一个设置tabbar选中的方法4.在onshow中使用选中方法最终效果预览 1.app.json设置custom为true开启自定义 2.根目录创建自定义的tab文件 index.wxml <view class"tab-bar&quo…

Java零基础——vue篇

1.【熟悉】Vue简介 1.1 简介 它是一个构建用户界面的框架 Vue是一个前端框架 js jq https://www.pmdaniu.com/#file UI网站 UI 一般开发者使用蓝湖 工具 看着UI图 写接口 https://lanhuapp.com/web/#/item 是一个轻量级的MVVM&#xff08;Model-View-ViewModel&#xff0…

STM32学习笔记--闪存Flash

STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分&#xff0c;通过闪存存储器接口&#xff08;外设&#xff09;可以对程序存储器和选项字节进行擦除和编程。 读写FLASH的用途&#xff1a;利用程序存储器的剩余空间来保存掉电不丢失的用户数据 &#xff0c;通过…

NodeJS(二):npm包管理工具、yarn、npx、pnpm工具等

目录 (一)npm包管理工具 1.了解npm 2.npm的配置文件 常见的配置属性 scripts属性*** 依赖的版本管理 3.npm安装包的细节 4.package-lock文件 5.npm install原理** 6.npm的其他命令 (二) 其他包管理工具 1.yarn工具 基本指令 2.cnpm工具 3.npx工具 (1)执行本地…

流媒体方案之FFmepeg——实现物联网视频监控项目

目录 前言 一、FFmpeg介绍 二、FFmpeg简易理解 三、FFmpeg的重要概念 四、软硬件准备 五、移植、运行FFmpeg 六、运行FFmpeg 前言 最近想做一个安防相关的项目&#xff0c;所以跟着韦东山老师的视频来学习视频监控方案的相关知识&#xff0c;韦东山老师讲的课非常好&…

Syntax Error: TypeError: Cannot read properties of undefined (reading ‘styles‘)

日志只有这一行&#xff0c;比较难排查 排查途径&#xff1a; 1、从上图找到唯一的文件输出output.js&#xff0c;断点查看堆栈信息&#xff0c;如下图&#xff0c;可以看到这个错误是由于哪个文件引起的 以为从App.vue中定位到原因了&#xff0c;其实也不对&#xff0c;继续…

卷积神经网络(VGG-16)猫狗识别

文章目录 一、前言二、前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;2. 导入数据3. 查看数据 二、数据预处理1. 加载数据2. 再次检查数据3. 配置数据集4. 可视化数据 三、构建VG-16网络四、编译五、训练模型六、模型评估七、保存and加载模型八、预测…

DynamicDataSource

DynamicDataSource 多数据源&#xff0c;读写分离&#xff0c;主从数据库

【力扣周赛】第 115 场双周赛(⭐优化背包DP)(TODO)

文章目录 竞赛链接Q1&#xff1a;2899. 上一个遍历的整数&#x1f4a9;&#xff08;阅读理解题&#xff0c;按题意模拟&#xff09;Q2&#xff1a;2900. 最长相邻不相等子序列 I&#xff08;贪心&#xff09;Q3&#xff1a;2901. 最长相邻不相等子序列 II&#xff08;类似 最长…

Seaborn图形可视化基础_Python数据分析与可视化

Seaborn图形可视化基础 Seaborn可视化Seaborn与Matplotlib Seaborn可视化 即使matplotlib已经如此强大了&#xff0c;但是不得不承认它不支持的功能还有很多。 例如&#xff1a; 2.0之前的版本的默认配置样式绝对不是用户的最佳选择&#xff1b; matplotlib的API比较底层。虽…

如何下载IEEE出版社的Journal/Conference/Magazine的LaTeX/Word模板

当你准备撰写一篇学术论文或会议论文时&#xff0c;使用IEEE&#xff08;电气和电子工程师协会&#xff09;的LaTeX或Word模板是一种非常有效的方式&#xff0c;它可以帮助你确保你的文稿符合IEEE出版的要求。无论你是一名研究生生或一名资深学者&#xff0c;本教程将向你介绍如…

zabbix6.4.0配置邮件及企微机器人群聊告警

一、邮件告警 根据公司邮箱自行配置&#xff0c;电子邮件、用户账号密码填自己的邮箱账号密码 动作本次使用的默认的&#xff0c;如果为了更加美观可自行修改。 二、企业微信机器人告警 首先在企微上创建群聊&#xff0c;之后添加群聊机器人 将地址复制&#xff0c;后面用 …