Android 开发艺术探索笔记(1)

<正常情况下的生命周期分析>

1. 关于 onStart() onResume() 和 onPause() onStop()的实质区别:

onStart()和onStop()是对于Activity **是否可见**这个角度来进行的方法

而onResume()和onStop()是对于Activity **是否处于前台**这个角度来进行的方法,除此之外没有实质的区别

2. 假设当前的Activity为A,如果用户这个时候打开一个新的Activity B,那么B的onResume()和A的onPause()哪一个先执行?

简单理解,启动Activty的请求会由Instrumentation来处理,然后它通过Binder向AMS(ActivityManagerService)发送请求,AMS内部维护者一个ActivityStack并负责栈内的Activity的状态同步,AMS通过ActivityThread去同步Activity的状态从而完成生命周期方法的调用。在ActivityStack中的ResumeTopActivityInnerLocker方法中的代码看出需要栈顶的Activity先onPause()后,新的Activity才会启动。最终在ActivityStackSupervisor中的realStartActivityLocked方法中调用scheduelLaunchActivity方法实现了新的Activity的onCreate、onStart、onResume的调用。

因此得出结论是**旧的Activity先onPause,新的Activity再启动**。

下面是实现 新的Activity的onCreate等的的源码

这里写图片描述

打印日志显示:

这里写图片描述

官方文档规定我们在onPasue中尽量不要做重量级的耗时的回收操作,onStop亦然。所以在onStop中做一些稍微重量级的耗时操作而不是在onPause里。

<异常情况下的生命周期分析>

3. 资源相关的系统配置发生改变导致Activity被杀死并重新创建。

屏幕突然从竖屏旋转到横屏,Activity的生命周期会被销毁并且重新创建。下图为默认情况的生命周期图。

这里写图片描述

可知,当发生异常终止,则在onDestory()之前调用**onSaveInstanceState()来保存当前状态,在下个Activity创建onCreate()之后用传来的Bundle的SavaInStacneState调用onRestoreInstanceState()**来加载之前的状态。Actvity重启后为我们来恢复这些数据,比如文本框的用户输入的数据,ListView的滚动位置等,每个View都有onSaveInstanceState和onRestoreInstanceState这两个方法。

恢复流程:Activty首先保存了数据,然后委托Window去保存数据,Window再委托它上面的顶级容器去保存数据。顶级容器是是ViewGroup或者DecorView,通知它们的子View来保存。

总之,当onRestoreInstanceState被调用时,系统一定出现了异常终止的Activity,参数 Bundle SaveInstanceState一定是有值的。onCreate中也可以去通过额外判断SaveInstanceState是否非空(因为正常启动一定是null)来恢复信息。但官方文档建议我们还是在onRestoreInstanceState()方法中进行恢复!

4. 资源内存不足导致低优先级的Activity被杀死

数据恢复情况和过程和情况3完全一致,Activity的优先级分为三种

(1)前台Activity——正在和用户交互的Activity,优先级最高

(2)可见但非前台的Activity——比如弹出了对话框,导致Activity可见但是位于后台无法和用户交互

(3)后台Activity——已经被暂停的Activity,比如执行了onStop(),优先级最低。

当系统内存不足的时候会通过优先级去杀死目标Activity所在的进程,后续通过onSaveInstanceState()和onRestoreInstanceState()来恢复数据。可以通过将后台工作放在Service中,这样保证了进程不会被轻易的杀死。

<其他>

当我们不想在翻转屏幕的时候销毁并重建Activity的时候,我们可以通过给ConfigChanges添加属性。

android:configChanges = “orientation”

<think>好的,我现在需要帮助用户解决如何使用PyTorch下载MNIST数据集、创建DataLoader以及打印数据类型的任务。让我仔细分析用户的问题,并回忆相关的PyTorch知识。 首先,用户的需求很明确:下载MNIST数据集,创建batch_size为100且shuffle为True的DataLoader,然后输出数据类型。根据用户提供的引用内容,特别是引用[2]和引用[3],他们可能已经看过一些示例,但需要更具体的指导。 PyTorch中的torchvision.datasets模块提供了MNIST数据集的下载功能。通常的做法是使用datasets.MNIST类,并指定保存的路径。同时,需要将图像转换为张量,通常使用transforms.ToTensor()。然后,使用DataLoader来加载数据集,设置batch_size和shuffle参数。用户提到的num_workers和pin_memory在引用[1]和[2]中出现过,但用户的问题中没有特别要求,所以可能不需要特别处理,不过可以适当提到作为优化选项。 接下来是创建DataLoader的步骤。用户希望batch_size为100,shuffle=True,这在训练集上是常见的设置,而测试集通常不需要shuffle。所以需要分别创建train_loader和test_loader,但用户的问题可能只需要关注训练集?或者用户可能希望同时展示训练和测试集的处理?需要仔细看用户的问题描述,用户提到“完成下载MNIST数据集并创建DataLoader”,所以可能需要同时处理训练和测试集。 然后,关于打印数据类型,每个batch的数据是图像和标签,所以需要从DataLoader中取出一个batch,然后打印它们的类型。例如,使用next(iter(train_loader))获取一个批次,然后打印images.dtype和labels.dtype。不过要注意,图像经过ToTensor转换后会变成torch.FloatTensor,而标签通常是torch.LongTensor。 现在,整合这些步骤,写出代码示例。需要注意的是数据下载可能因为网络问题而失败,可以设置download=True,并建议用户如果下载失败可以手动下载。同时,数据保存的路径可能需要用户指定,比如root参数设为'./data'。 可能的问题点:用户是否已经安装了必要的库,比如torch和torchvision。但假设用户已经安装,所以不需要额外说明。 最后,根据用户提供的引用[3],可能需要提到自定义batchsampler,但用户的问题中没有提到,所以可以忽略这部分。但用户引用的示例中有一些关于DataLoader参数的讨论,比如num_workers和pin_memory,可以在代码中作为可选参数添加,但用户的问题没有特别要求,所以可能作为注释或提到优化参数。 总结步骤: 1. 导入必要的库(torchvision.datasets, transforms, DataLoader) 2. 定义数据转换,包括转换为Tensor 3. 下载训练集和测试集 4. 创建DataLoader,设置batch_size和shuffle 5. 获取一个batch的数据,打印数据类型 在代码中,需要注意训练集和测试集的不同处理,比如shuffle参数在测试集中设为False。但用户的问题可能只需要处理训练集?用户的问题描述是“创建DataLoader”,可能包括训练和测试,但需要看具体需求。根据引用[2],用户提到train_loader和test_loader,所以可能需要同时创建两者,但问题中用户可能只需要展示如何创建训练集的DataLoader,或者在示例中同时展示两者? 用户的问题中明确提到“下载MNIST数据集并创建DataLoader”,所以可能同时处理训练和测试集。但根据用户提供的引用[2],他们的示例中同时创建了train_loader和test_loader。因此,在回答中应该包括两者的创建,但用户的问题可能只需要训练集?需要再仔细看问题。 用户的问题具体是:“如何用PyTorch下载MNIST数据集,创建一个batch_size为100且shuffle为True的DataLoader,并打印其中的数据类型?”这里的DataLoader可能指的是训练集的DataLoader,因为shuffle=True通常用于训练集。测试集一般不需要shuffle。所以可能只需要创建训练集的DataLoader,但为了全面,可能在代码中包含训练和测试,但只对训练集设置shuffle=True。 现在,编写代码示例: 首先,导入必要的模块: import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader 然后定义transform,将图像转换为张量: transform = transforms.Compose([ transforms.ToTensor(), ]) 下载数据集: train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform) test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform) 创建DataLoader: train_loader = DataLoader(train_dataset, batch_size=100, shuffle=True, num_workers=4) test_loader = DataLoader(test_dataset, batch_size=100, shuffle=False, num_workers=4) 然后,获取一个batch的数据并打印类型: images, labels = next(iter(train_loader)) print("图像数据类型:", images.dtype) # 应该输出torch.float32 print("标签数据类型:", labels.dtype) # 应该输出torch.int64 但用户的问题可能只需要训练集的DataLoader,所以可以只展示train_loader的创建。此外,关于num_workers,用户可能根据引用[1]和[2]中的例子使用不同的值,但用户的问题中没有指定,所以可以设置或作为可选参数。 然后,关于数据类型的输出,需要确认是否正确。ToTensor会将图像像素值转换为[0,1]的float32,而标签是整数,转换为int64(即torch.long)。 现在,整合所有内容,确保代码正确,并添加必要的注释。同时,处理可能出现的错误,比如下载失败,建议设置download=True,并提示用户可能需要手动下载。 最后,生成相关问题,如MNIST数据集的预处理方法,DataLoader参数的影响,数据类型的转换等。</think>以下是使用PyTorch下载MNIST数据集并创建DataLoader的完整实现: ```python import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader # 定义数据转换:将图像转换为张量 transform = transforms.Compose([ transforms.ToTensor() ]) # 下载训练集和测试集 train_dataset = datasets.MNIST( root='./data', # 数据存储路径 train=True, # 训练集 download=True, # 自动下载 transform=transform ) test_dataset = datasets.MNIST( root='./data', train=False, # 测试集 download=True, transform=transform ) # 创建DataLoader train_loader = DataLoader( train_dataset, batch_size=100, # 每个批次100个样本 shuffle=True, # 打乱训练数据顺序[^2] num_workers=4 # 使用4个子进程加载数据[^1] ) # 获取一个批次数据并验证类型 batch = next(iter(train_loader)) images, labels = batch print("图像数据类型:", images.dtype) # 输出torch.float32(由ToTensor转换得到) print("标签数据类型:", labels.dtype) # 输出torch.int64(原始标签格式) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值