【Android Jetpack】Lifecycle 感知生命周期

news2024/11/18 11:33:54

文章目录

    • 背景
    • 示例
    • LifeCycle的原理
      • LifecycleOwner
      • 自定义LifecycleOwner
      • LifecycleObserver
    • 示例改进
    • 使用LifecycleService解耦Service与组件
    • 整个应用进程的生命周期ProcessLifecycleOwner

背景

在Android应用程序开发中,解耦很大程度上表现为系统组件的生命周期与普通组件之间的解耦。普通组件在使用过程中通常需要依赖于系统组件的生命周期。有时候,我们不得不在系统组件的生命周期回调方法中,主动对普通组件进行调用或控制。因为普通组件无法主动获知系统组件的生命周期事件。

我们希望我们对自定义组件的管理,不依赖于页面生命周期的回调方法。同时,在页面生命周期发生变化时,也能够及时收到通知。这在组件化和架构设计中显得尤为重要。

为此,Google提供了LifeCycle作为解决方案。LifeCycle可以帮助开发者创建可感知生命周期的组件。这样,组件便能够在其内部管理自己的生命周期,从而降低模块间的耦合度,并降低内存泄漏发生的可能性。LifeCycle不只对Activity/Fragment有用,在Service和Application中也能大显身手。

示例

Android开发中,经常需要管理生命周期。举个栗子,我们需要获取用户的地址位置,当这个Activity在显示的时候,我们开启定位功能,然后实时获取到定位信息,当页面被销毁的时候,需要关闭定位功能。

internal class MyLocationListener(
        private val context: Context,
        private val callback: (Location) -> Unit
) {

    fun start() {
        // 连接系统定位服务以及其他业务
    }

    fun stop() {
        //断开系统定位服务
    }
}

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this) { location ->
            ...
        }
    }

    public override fun onStart() {
        super.onStart()
        myLocationListener.start()
    }

    public override fun onStop() {
        super.onStop()
        myLocationListener.stop()
    }
}

虽然此示例看起来没问题,但在真实的应用中,最终会有太多管理界面和其他组件的调用,以响应生命周期的当前状态。管理多个组件会在生命周期方法(如 onStart()onStop())中放置大量的代码,这使得它们难以维护。

此外,无法保证组件会在 Activity 或 Fragment 停止之前启动。在我们需要执行长时间运行的操作(如 onStart() 中的某种配置检查)时尤其如此。这可能会导致出现一种竞态条件,在这种条件下,onStop() 方法会在 onStart() 之前结束,这使得组件留存的时间比所需的时间要长。

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this) { location ->
            // update UI
        }
    }

    public override fun onStart() {
        super.onStart()
        Util.checkUserStatus { result ->
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start()
            }
        }
    }

    public override fun onStop() {
        super.onStop()
        myLocationListener.stop()
    }

}

Lifecycle类是一个持有组件(activityfragment)生命周期信息的类,其他对象可以观察该状态。Lifecycle使用两个重要的枚举部分来管理对应组件的生命周期的状态:

  • Event:生命周期事件,由系统来分发,这些事件对应于ActivityFragment的生命周期函数。

  • State:Lifecycle对象所追踪的组件的当前状态

image-20230921165716822

LifeCycle的原理

Jetpack为我们提供了两个类:

  • LifecycleOwner: 被观察者
  • LifecycleObserver: 观察者

通过观察者模式,实现对页面生命周期的监听。

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,
        TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {
}            
public class FragmentActivity extends ComponentActivity implements
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator {
}            

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {
    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }            
}           
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
        ViewModelStoreOwner, SavedStateRegistryOwner {
}            

ComponentActivity和Fragment已经默认实现了LifecycleOwner接口。(代表有生命周期)

LifecycleOwner

那什么是LifecycleOwner呢?实现LifecycleOwner接口就表示这是个有生命周期的类他有一个getLifecycle()方法是必须实现的。

 //一个具有Android生命周期的类。自定义组件可以使用这些事件来处理生命周期更改,而无需在Activity或Fragment中实现任何代码。
@SuppressWarnings({"WeakerAccess", "unused"})
public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     */
    @NonNull
    Lifecycle getLifecycle();
}

从以上源码可知,Activity和Fragment已经替我们实现了被观察者应该实现的那一部分代码。因此,我们不需要再去实现这部分代码。当我们希望监听Activity的生命周期时,只需要实现观察者那一部分的代码,即让自定义组件实现LifecycleObserver接口即可。该接口没有接口方法,无须任何具体实现。

对于前面提到的监听位置的例子。可以把MyLocationListener实现LifecycleObserver,然后在Lifecycle(Activity/Fragment)onCreate方法中初始化。这样MyLocationListener就能自行处理生命周期带来的问题。

自定义LifecycleOwner

  • 如果想在自定义的类中实现LifecyclerOwner,就需要用到LifecycleRegistry类,并且需要自行发送Event:
class MyActivity : Activity(), LifecycleOwner {
    private lateinit var lifecycleRegistry: LifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

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

    public override fun onStart() {
        super.onStart()
        lifecycleRegistry.markState(Lifecycle.State.STARTED)
    }

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}

LifecycleObserver

/**
 * Marks a class as a LifecycleObserver. It does not have any methods, instead, relies on
 * {@link OnLifecycleEvent} annotated methods.
 * @see Lifecycle Lifecycle - for samples and usage patterns.
 //-------------
 * 将类标记为LifecycleObserver。它没有任何方法,而是依赖于
 *{@link OnLifecycleEvent}注释的方法。
 *@请参阅生命周期-了解示例和使用模式。
 */
@SuppressWarnings("WeakerAccess")
public interface LifecycleObserver {

}

注释上写的很明白,该接口依赖OnLifecycleEvent的注解方法

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnLifecycleEvent {
    Lifecycle.Event value();
}
public enum Event {
    /**
         * Constant for onCreate event of the {@link LifecycleOwner}.
         */
    ON_CREATE,
    /**
         * Constant for onStart event of the {@link LifecycleOwner}.
         */
    ON_START,
    /**
         * Constant for onResume event of the {@link LifecycleOwner}.
         */
    ON_RESUME,
    /**
         * Constant for onPause event of the {@link LifecycleOwner}.
         */
    ON_PAUSE,
    /**
         * Constant for onStop event of the {@link LifecycleOwner}.
         */
    ON_STOP,
    /**
         * Constant for onDestroy event of the {@link LifecycleOwner}.
         */
    ON_DESTROY,
    /**
         * An {@link Event Event} constant that can be used to match all events.
         */
    ON_ANY
}

示例改进

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // lifecycle是LifecycleOwner接口的getLifecycle()方法得到的
        lifecycle.addObserver(MyObserver()) 
    }
}

在Activity中只需要引用MyObserver即可,不用再关心Activity生命周期变化对该组件所带来的影响。生命周期的管理完全交给MyObserver内部自行处理。在Activity中要做的只是通过getLifecycle().addObserver()方法,将观察者与被观察者绑定起来。

class MyObserver : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun connectListener() {
        ...
        //填写逻辑业务代码
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun disconnectListener() {
        ...
        //填写逻辑业务代码
    }
}

上面的lifecycle.addObserver(MyObserver()) 的完整写法应该是aLifecycleOwner.getLifecycle().addObserver(new MyObserver())aLifecycleOwner一般是实现了LifecycleOwner的类,比如Activity/Fragment

internal class MyLocationListener(
        private val context: Context,
        private val lifecycle: Lifecycle,
        private val callback: (Location) -> Unit): LifecycleObserver {

    private var enabled = false

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun start() {
        if (enabled) {
            // connect
        }
    }

    fun enable() {
        enabled = true
        // 查询状态
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
            // connect if not connected
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stop() {
        // disconnect if connected
    }
}
  • 对于组件中那些需要在页面生命周期发生变化时得到通知的方法,我们需要在这些方法上使用==@OnLifecycleEvent(Lifecycle.Event.ON_XXX)==标签进行标识。这样,当页面生命周期发生变化时,这些被标识过的方法便会被自动调用。

LifeCycle完美解决了组件对页面生命周期的依赖问题,使组件能够自己管理其生命周期,而无须在页面中对其进行管理。这无疑大大降低了代码的耦合度,提高了组件的复用程度,也杜绝了由于对页面生命周期管理的疏忽而引发的内存泄漏问题,这在项目工程量大的情况下是非常有帮助的。

使用LifecycleService解耦Service与组件

拥有生命周期概念的组件除了Activity和Fragment,还有一个非常重要的组件是Service。为了便于对Service生命周期的监听,达到解耦Service与组件的目的,Android提供了一个名为LifecycleService的类。该类继承自Service,并实现了LifecycleOwner接口。与Activity/Fragment类似,它也提供了一个名为getLifecycle()的方法供我们使用。

  • 想要使用LifecycleService必须先增加lifecycle-service的依赖:
implementation 'androidx.lifecycle:lifecycle-service:2.3.1'

结构:

public class LifecycleService
    extends Service implements LifecycleOwner
java.lang.Objectandroid.content.Contextandroid.content.ContextWrapperandroid.app.Serviceandroidx.lifecycle.LifecycleService 

源码:

public class LifecycleService extends Service implements LifecycleOwner {

    private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);

    @CallSuper
    @Override
    public void onCreate() {
        mDispatcher.onServicePreSuperOnCreate();
        super.onCreate();
    }

    @CallSuper
    @Nullable
    @Override
    public IBinder onBind(@NonNull Intent intent) {
        mDispatcher.onServicePreSuperOnBind();
        return null;
    }

    @SuppressWarnings("deprecation")
    @CallSuper
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        mDispatcher.onServicePreSuperOnStart();
        super.onStart(intent, startId);
    }

    // this method is added only to annotate it with @CallSuper.
    // In usual service super.onStartCommand is no-op, but in LifecycleService
    // it results in mDispatcher.onServicePreSuperOnStart() call, because
    // super.onStartCommand calls onStart().
    @CallSuper
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @CallSuper
    @Override
    public void onDestroy() {
        mDispatcher.onServicePreSuperOnDestroy();
        super.onDestroy();
    }

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

整个应用进程的生命周期ProcessLifecycleOwner

具有生命周期的系统组件除Activity、Fragment、Service外,还有Application。很多时候,我们会遇到这样的需求:我们想知道应用程序当前处在前台还是后台,或者当应用程序从后台回到前台时,我们能够得到通知。有不少方案能够实现该需求,但都不够好。在此之前,Google并没有为该需求提供官方解决方案,直到LifeCycle的出现。

  • 需要先添lifecycle-process的依赖:
implementation 'androidx.lifecycle:lifecycle-process:2.3.1'

源码:

/**
 * Class that provides lifecycle for the whole application process.
 * <p>
 * You can consider this LifecycleOwner as the composite of all of your Activities, except that
 * {@link Lifecycle.Event#ON_CREATE} will be dispatched once and {@link Lifecycle.Event#ON_DESTROY}
 * will never be dispatched. Other lifecycle events will be dispatched with following rules:
 * ProcessLifecycleOwner will dispatch {@link Lifecycle.Event#ON_START},
 * {@link Lifecycle.Event#ON_RESUME} events, as a first activity moves through these events.
 * {@link Lifecycle.Event#ON_PAUSE}, {@link Lifecycle.Event#ON_STOP}, events will be dispatched with
 * a <b>delay</b> after a last activity
 * passed through them. This delay is long enough to guarantee that ProcessLifecycleOwner
 * won't send any events if activities are destroyed and recreated due to a
 * configuration change.
 *
 * <p>
 * It is useful for use cases where you would like to react on your app coming to the foreground or
 * going to the background and you don't need a milliseconds accuracy in receiving lifecycle
 * events.
 */
/**
翻译:
*为整个应用程序流程提供生命周期的类。
*您可以将此LifecycleOwner视为所有活动的组合,除了
*{@link Lifecycle。事件#ON_CREATE}将被调度一次,并且{@linkLifecycle。事件#ON_DESTROY}
*永远不会被派遣。其他生命周期事件将按照以下规则进行调度:
*ProcessLifecycleOwner将调度{@link Lifecycle。事件#ON_START},
*{@linkLifecycle.Event#ON_RESUME}事件,作为第一个活动在这些事件中移动。
*{@link Lifecycle。Event#ON_PAUSE},{@link Lifecycle。Event#ON_STOP},事件将与上次活动后的a延迟穿过他们。此延迟足够长,可以保证ProcessLifecycleOwner
*如果活动由于配置更改。
*它适用于您希望对应用程序进入前台或
*进入后台,在接收生命周期中不需要毫秒的准确性事件。
*/
@SuppressWarnings("WeakerAccess")
public class ProcessLifecycleOwner implements LifecycleOwner {

ProcessLifecycleOwner的使用方式与Activity、Fragment和Service是类似的,其本质也是观察者模式。由于我们要观察的是整个应用程序,因此,需要在Application中进行相关代码的编写。

class StApplication : Application() {
    companion object {
        private lateinit var instance: Application
        fun getInstance() = instance
    }

    override fun onCreate() {
        super.onCreate()
        instance = this
        ProcessLifecycleOwner.get().lifecycle.addObserver(MyApplicationObserver())
    }
}
class MyApplicationObserver : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {

    }
    // 前台出现时调用
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() {
        Log.e("xoliu", "onStart")
    }
    // 前台出现时调用
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun onResume() {
        Log.e("xoliu", "onResume")
    }
    // 退出到后台时调用
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun onPause() {
        Log.e("xoliu", "onPause")
    }
    // 退出到后台时调用
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onStop() {
        Log.e("xoliu", "onStop")
    }
}
  • 当应用程序从后台回到前台,或者应用程序被首次打开时,会依次调用Lifecycle.Event.ON_STARTLifecycle.Event.ON_RESUME

  • 当应用程序从前台退到后台(用户按下Home键或任务菜单键),会依次调用Lifecycle.Event.ON_PAUSELifecycle.Event.ON_STOP。需要注意的是,这两个方法的调用会有一定的延后。这是因为系统需要为“屏幕旋转,由于配置发生变化而导致Activity重新创建”的情况预留一些时间。也就是说,系统需要保证当设备出现这种情况时,这两个事件不会被调用。因为当旋转屏幕时,你的应用程序并没有退到后台,它只是进入了横/竖屏模式而已。

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

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

相关文章

C++学习之路(十三)C++ 用Qt5实现一个工具箱(增加一个Base64加解密功能)- 示例代码拆分讲解

上篇文章&#xff0c;我们用 Qt5 实现了在小工具箱中添加了《XML文本格式化功能》功能。为了继续丰富我们的工具箱&#xff0c;今天我们就再增加一个平时经常用到的功能吧&#xff0c;就是「 Base64加解密 」功能。下面我们就来看看如何来规划开发一个这样的小功能并且添加到我…

改造http.server为简单的文件下载服务

改造 修改http.server.SimpleHTTPRequestHandler&#xff0c;实现简单的文件上传下载服务 simple_http_file_server.py&#xff1a; # !/usr/bin/env python3import datetime import email import html import http.server import io import mimetypes import os import posi…

hql面试题之字符串使用split分割,并选择其中的一部分字段的问题

版本&#xff1a;20231109 1.题目&#xff1a; 有两张表,a表有id和abstringr两个字段&#xff0c;b表也有id和bstr两个字段&#xff0c;具体如下 A表&#xff1a; 1abc,bcd,cdf2123,456,789 B表: 1acddef2123456 在a表的abstring字段中用‘,’分割&#xff0c;并取出前两…

万宾科技水环境综合治理监测系统的融合与应用

随着社会经济的快速发展&#xff0c;我国的水环境污染问题日益凸显&#xff0c;这不仅对生态环境造成了严重破坏&#xff0c;也严重威胁到人民群众的健康和生活质量。为了解决这一问题&#xff0c;城市生命线与水环境综合治理监测系统应运而生&#xff0c;二者的结合将为水环境…

TA-Lib学习研究笔记——Overlap Studies(二)下

TA-Lib学习研究笔记——Overlap Studies&#xff08;二&#xff09;下 &#xff08;11&#xff09;SAR - Parabolic SAR 抛物线指标 函数名&#xff1a;SAR 名称&#xff1a; 抛物线指标 简介&#xff1a;抛物线转向也称停损点转向&#xff0c;是利用抛物线方式&#xff0c;随…

在Springboot中将数据渲染到前端页面1.0

前端数据代码&#xff1a; <?xml version"1.0" encoding"UTF-8" ?> <emps><emp><name>金毛狮王</name><age>55</age><image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/1.jpg</image…

《异常检测——从经典算法到深度学习》24 用于单变量时间序列异常检测的端到端基准套件

《异常检测——从经典算法到深度学习》 0 概论1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法3 基于One-Class SVM的异常检测算法4 基于高斯概率密度异常检测算法5 Opprentice——异常检测经典算法最终篇6 基于重构概率的 VAE 异常检测7 基于条件VAE异常检测8 Donut: …

Flutter加固原理及加密处理

​ 引言 为了保护Flutter应用免受潜在的漏洞和攻击威胁&#xff0c;加固是必不可少的措施之一。Flutter加固原理主要包括代码混淆、数据加密、安全存储、反调试与反分析、动态加载和安全通信等多个方面。通过综合运用这些措施&#xff0c;可以提高Flutter应用的安全性&#xf…

android开发:用IDEA建立你的第一个APP

主要是记录一下各种小坑。 IDEA目前是第一流行的java开发工具&#xff0c;同时也支持android开发&#xff0c;可以替代安卓官方的andriod studio&#xff0c;不过仍然要依赖android sdk。 本例指导你完成第一个app&#xff0c;需要一台Windows PC和一部android手机。 目录 一…

「Verilog学习笔记」状态机-非重叠的序列检测

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 根据题意 定义一个五位的中间变量lock 每次始终上升沿来临时 判断当前寄存器的低四位新数据是否等于10111 如果等于 则下一时刻lock应被清空 否则lock等于当前的lock的低四…

【刷题笔记】两数之和II_二分法||二分查找||边界||符合思维方式

两数之和II_二分法||二分查找 1 题目描述 https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/ 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设…

相机标定张正友、opencv和halcon对比(1)

本文将从基本标定开始&#xff0c;结合实际工作经验&#xff0c;分析张正友、opencv和halcon三者相机标定的深层原理与不同之处&#xff0c;内容比较多&#xff0c;如果出现错误请指正。 相机光学模型 我们使用的镜头都是由多组镜片组成&#xff0c;它实际上是一种厚透镜模型…

企业微信应用文本消息

应用支持推送文本、图片、视频、文件、图文等类型&#xff0c;本篇主要实现发送应用文本消息。 获取企业凭证 发送应用消息首先需要获取调用凭证access_token&#xff0c;此处的凭证为企业凭证&#xff0c;可通过企业授权安装时返回的授权信息中获取access_token&#xff1b;之…

nexus 制品库管理

目录 一、nexus 介绍 二、nexus 支持的仓库 三、nexus 部署 四、nexus 数据备份 五、创建一个内网yum源 六、创建一个代理yum仓库 七、jenkins 使用 nexus插件 7.1 jenkins 安装插件 7.2 配置 maven 工程 7.3 查看构建和上传 一、nexus 介绍 Nexus 是一个强大的仓库管…

【重点文章】将Java程序打包成exe文件,无Java环境也可以运行(解决各种疑难杂症)

文章目录 一、将Java程序打成jar包二、将Jar打成exe三、加壳改造成安装包 编译器为IDEA 一、将Java程序打成jar包 2. 3. 你打的包一般会出现在根目录下面的out文件夹下面  当然你也可以用maven的package功能打包&#xff0c;效果是一样的   二、将Jar打成exe 使用工具e…

AD4209 双路LED、集成充电一体 可做双色温芯片调节 适用于台灯、手电筒

AD4209 是一款双路输出的可调色温的 台灯控制芯片&#xff0c;集成了锂电池充电管理模块、 LED 功能控制模块和保护模块&#xff0c;关机待机电流仅 3uA。 AD4209 为双路输出控制&#xff0c;每一路最大输出 电 流 为 1.2A 开 关 模 式 &#xff1a;CH1→CH2→CH1CH2→OFF。…

Qt MVC示例 simpletreemodel 树模型

Qt MVC示例 simpletreemodel 树模型 从文本中读取树模型数据&#xff0c;缩进代表子项 TreeItem 表示一行字符串数据 treeitem.h #ifndef TREEITEM_H #define TREEITEM_H#include <QList> #include <QVariant>//! [0] class TreeItem { public:explicit Tree…

EasyRecovery2024免费强大的电脑文件恢复软件

文件的保存一直是我们对电子化数据较为关注的一个环节&#xff0c;毕竟这是一份文件或数据的根本所在。但是在计算机操作中难免会出现有文件丢失或文件误删的现象&#xff0c;给我们的日常和工作带来不必要的困扰。 今天小编就要和大家分享一款功能超级强大的文件恢复软件&…

DCGAN 使用指南:将卷积神经网络和对抗网络结合,适用于生成小尺寸的图像

DCGAN 使用指南&#xff1a;将卷积神经网络和对抗网络结合 网络结构细节设计 论文地址&#xff1a;https://arxiv.org/abs/1511.06434 项目代码&#xff1a;https://github.com/tensorlayer/DCGAN.git DCGAN 适用于生成小尺寸的图像&#xff0c;并且具有简单易用的优势 Styl…

使用 Webshell 访问 SQL Server 主机并利用 SSRS

本文将指导您使用RDS SQL Server实例的主机账号登录和管理SQL Server Reporting Services&#xff08;SSRS&#xff09;数据库。 背景信息 RDS SQL Server提供Webshell功能&#xff0c;用户可以通过Web界面登录RDS SQL Server实例的操作系统。通过Webshell&#xff0c;用户可…