59. 螺旋矩阵 II(JS实现)

59. 螺旋矩阵 II(JS实现)

1 题目
给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3
输出:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]

2 思路
这道题就比54那道螺旋矩阵简单很多,因为行列都是一样的大小,注意行列数为奇数的时候,矩阵中间那个数要*后推入

3代码
/**
* @param {number} n
* @return {number[][]}
*/
var generateMatrix = function(n) {
if (n === 0) return [];
if (n === 1) return [[1]];

let result = [];
for (let i=0; i<n; i++) {
result.push([]);
}

let num = 1;

let i,j;
let min = 0;
let max = n – 1;

while(max > min) {
i = min;
j = min;

while(j < max) {
result[i][j++] = num++;
}

while(i < max) {
result[i++][j] = num++;
}

while(j > min) {
result[i][j–] = num++;
}

while(i > min) {
result[i–][j] = num++;
}

min++;
max–;
}

if (n % 2 === 1) result[max][max] = num++;

return result;
};

60. 第k个排列(JS实现)

60. 第k个排列(JS实现)

1 题目
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
“123”
“132”
“213”
“231”
“312”
“321”
给定 n 和 k,返回第 k 个排列。
说明:
给定 n 的范围是 [1, 9]。
给定 k 的范围是[1, n!]。
示例 1:
输入: n = 3, k = 3
输出: “213”
示例 2:
输入: n = 4, k = 9
输出: “2314”

2 思路
这道题刚开始时直接深度优先遍历构造树,虽然通过了,但运行时间太长,后来发现有个技巧,每层for循环下面的子分支总数量为(m-1)!,其中m为当前没有用过的数的个数,比如*层for循环,一个数也没用过,则每个分支对应的子分支的总数量为(n-1)!,这样就可以用k/(m-1)!来看一下需要的字符串在当前for循环的第几个分支下面,从而进行剪枝

3代码
/**
* @param {number} n
* @param {number} k
* @return {string}
*/
var getPermutation = function(n, k) {
if (n === 1) return “1”;

let nums = [];
let x = 1;
for (let i=1;i<=n;i++) {
nums.push(” + i);
x *= i;
}
x = x / n;

let ans = ”;
let index = 0;
let y = Math.floor(k / x) !== k / x ? Math.floor(k / x) : k / x – 1;

for (let i=0;i<n;i++) {
if (i < y) continue; //这里对*层for循环进行剪枝
d(nums[i], k – y * x);
}

function d(str, k) {
if (ans) return;

if (str.length === n && ++index === k) {
ans = str;
return;
}

for (let i=0;i<n;i++) {
if (str.includes(nums[i])) continue;
d(str + nums[i], k);
}
}

return ans;
};

ARM 开启Dcache 问题

ARM926EJS Dcache是依赖于MMU,只有开启MMU后Dcache 才真正有效。

正常情况下,开启 Dcache 可以大大加快 CPU 性能;但是遇到特殊情况则出现很大的问题。

有以下三种情况:

采用不可缓存代码;
采用自修改代码;
操作AHB总线。
采用不可缓存代码
与其他ARM9系列的缓存内核来比,尽管非缓存代码的性能得到了改善,仍然推荐采用ICache,这是实践证明了的。

非缓存代码通常用在boot loader上面,防止cache污染。但是现在ICache在没有启用MMU的情况下仍然能够使能,而且可以通过控制 cache lockdown register 来防止污染,所以采用非缓存代码是没有优点的。

采用自修改代码
采用一个四字的缓冲区来保存推测到的将要获取的取指令。只有连续的指令可以准确地获取,万一 ARM9EJ-S 内核,缓冲区的内容会被丢掉(discard/flush)。在内核连续预取指的序列中,预取缓冲区的内容可能变为无效,这种情况下,预取缓冲器也应该被刷新(flush)。

操作AHB总线
ss

为了保证数据和指令的一致性,必须做以下操作

1. Clean the DCache
2. Drain the write buffer
3. Synchronize data and instruction streams in level two AHB subsystems
4. Invalidate the ICache
5. Flush the prefetch buffer

代码如下:

clean_loop
MRC p15, 0, r15, c7, c10, 3 ; clean entire dcache using test and clean
BNE clean_loop
MCR p15, 0, r0, c7, c10, 4 ; drain write buffer
STR rx,[ry] ; nonbuffered store to signal L2 world to synchronize
MCR p15, 0, r0, c7, c5, 0 ; invalidate icache

c语言(iar):

<code>

__root unsigned int a_a=9;
#pragma optimize=none
void flush_cache(void)
{
CP15_TestCleanDcache();
CP15_DrainWriteBuffer();
a_a ++;
CP15_InvalidateIcache();
}
</code>

嵌入式系统的内存管理

嵌入式系统的内存管理

摘要:实时性、可靠性的要求,使得许多嵌入式应用使用自己的内存管理程序。本文探讨嵌入式系统中对内存管理的要求、存在的问题以及可能的解决策略;介绍一种“一次分配,多次使用”的动态内存分配方法,并给出2个例子。
关键词:嵌入式系统 内存管理 一次分配多次使用
1 嵌入式系统中对内存分配的要求
①快速性。嵌入式系统中对实时性的保证,要求内存分配过程要尽可能地快。因此在嵌入式系统中,不可能采用通用操作系统中复杂而完善的内存分配策略,一般都采用简单、快速的内存分配方案。当然,对实性要求的程序不同,分配方案也有所不同。例如,VxWorks采用简单的*先匹配如立即聚合方法;VRTX中采用多个固定尺寸的binning方案。
②可靠性。也就是内存分配的请求必须得到满足,如果分配失败可能会带来灾难性的后果。嵌入式系统应用的环境千变万化,其中有一些是对可靠性要求*高的。比如,汽车的自动驾驶系统中,系统检测到即将撞车,如果因为内存分配失败而不能相应的操作,就会发生车毁人亡的事故,这是不能容忍的。
③高效性。内存分配要尽可能地少浪费。不可能为了保证满足所有的内存分配请求而将内存配置得无限大。一方面,嵌入式系统对成本的要求使得内存在其中只是一种很有限的资源;另一方面,即使不考虑成本的因素,系统有限的空间和有限的板面积决定了可配置的内存容量是很限的。
2 静态分配与动态分配 究竟应用使用静态分配还是动态分配,一直是嵌入式系统设计中一个争论不休的总是。当然,*合适的答案是对于不同的系统采用不同的方案。如果是系统对于实时性和可靠性的要求*高(硬实时系统),不能容忍一点延时或者一次分配失败,当然需要采用静态分配方案,也就是在程序编译时所需要的内存都已经分配好了。例如,火星探测器上面的嵌入式系统就必须采用静态分配的方案。另外,WindRiver公司的一款专门用于汽车电子和工业自动化领域的实时操作系统OSEKWorks中就不支持内存的动态分配。在这样的应用场合,成本不支持内存的动态分配。在这样的应用场合,成本不是优先考虑的对象,实时性和可靠性才是必须保证的。当然,采用静态分配一个不可避免的总是就是系统失去了灵活性,必须在设计阶段就预先知道所需要的内存并对之作出分配;必须在设计阶段就预先考虑到所有可能的情况,因为一旦出现没有考虑到的情况,系统就无法处理。这样的分配方案必须导致很大的浪费,因为内存分配必须按照*坏情况进行*大的配置,而实际上在运行中可能使用的只是其中的一小部分;而且在硬件平台不变的情况下,不可能灵活地为系统添加功能,从而使得系统的升级变得困难。 大多数的系统是硬实时系统和软实时系统的综合。也就是说,系统中的一部分任务有严格的时限要求,而另一部分只是要求完成得越快越好。按照RMS(Rate Monotoin Scheduling)理论,这样的系统必须采用抢先式任务调度;而在这样的系统中,就可以采用动态内存分配来满足那一部分可靠性和实时性要求不那么高的任务。采用动态内存分配的好处就是给设计者很大的灵活性,可以方便地将原来运行于非嵌入式操作系统的程序移植到嵌入式系统中,比如,许多嵌入式系统中使用的网络协议栈。如果必须采用静态内存分配,移植这样的协议栈就会困难得多。另外,采用动态内存分配可以使设计者在不改变基本的硬件平台的情况下,比较灵活地调整系统的功能,在系统中各个功能之间作出权衡。例如,可以在支持的VLAN数和支持的路由条目数之间作出调整,或者不同的版本支持不同的协议。说到底,动态内存分配给了嵌入式系统的程序设计者在比较少的限制和较大的自由。因此,大多数实时操作系统提供了动态内存分配接口,例如malloc和free函数。
3 RTOS提供的内存分配接口 不同的RTOS由于其不同的定位,采用不同的内存分配策略。
例如VRTX中,采用类似于GNU C中由Doug Lea开发的内存分配方案,即Binning算法,系统内存被分成了一些固定尺寸的内存块的算法,系统内存被分成了一些固定尺寸的内存块的集合。这种方法的优点是查找速度快而且不会产生内存碎片。但是,它的缺点也很明显,就是容易造成浪费,因为内存块的尺寸只有有限个,分配时只能取较大的内存块来满足一个较小的需求,累积起来,浪费就很大了;而且操作系统管理这样一个内存分配表也是一个很大的负担。 下面详细介绍一下我们常用的RTOS——美国风河公司(WindRiver)的VxWorks中采用的内存分配策略。VxWorks的前身就是VRTX,据说VxWorks的名称来自make vrtx work。 VxWorks的内存管理函数存在于2个库中;memPartLib(紧凑的内存分区管理器)和memLib(完整的内存分区管理器)。前者(memPartLib)提供的工具用于从内存分区中分配内存块。该库包含两类程序,一类是通用工具创建和管理内存分区并从这些分区中分配和管理内存块;另一类是标准的malloc/free程序提供与内存分区的接口。系统内存分区(其ID为memSysPartId是一个全局变量)在内核初始化时由usrRoot调用memInit创建。其开始地址为RAM中紧接着VxWorks的BSS段之后,大小为所有空闲内存,如图1所示。 当创建其它分区时,一般需要先调用malloc从系统内存分区中分配一段内存才能创建。内存分区的结构定义为mem_part,包含1个对象标记,1个双向链表管理空闲块,1个信号量保护该分区及一些统计信息,如总尺寸、*大块尺寸、调试选项、已分配的块数、已分配的尺寸等。其语句如下:
typedef struct mem_part
{ OBJ_CORE objCore; /*对象标志*/
DL-LIST freeList; /*空闲链表*/
SEMAPHORE sem; /*保护分区的信号量*/
Unsigned totalWords; /*分区中字(WORD)数*/
Unsigned minBlockWords; /*以字为单位的*小块尺寸*/
Unsigned options; /*选项,用于调试或统计*/ /*分配统计*/
unsigned curBlocksAllocated; /*当前分配的块数*/
unsigned curWorkdAllocated; /*当前分配的字数*/
unsigned cumBlockAllocated; /*累积分配的块数*/
unsigned cumWordsAllocated; /*累积分配的字数*/
}PARTITION;
一般系统中只有1个内存分区,即系统分区,所有任务所需要的内存直接调用malloc从其中分配。分配采用First-Fit算法(注意这种算法容易导致大量碎片),通过free释放的内存将被聚合以形成更大的空闲块。这就是VxWorks的内存分配机理。分配时可以要求一定的对齐格式。注意,不同的CPU架构有不同的对齐要求。为了优化性能,malloc返回的指针是经过对齐的,为此的开销随构不同而不同。例如,68K为4字节对齐,开销8字节;SPARC为8字节对齐,开销12字节;MIPS为16字节对齐,开销12字节;I960为16字节对齐,开销16字节。 MemLib库中提供了增强的内存分区管理工具,并且增加了一些接口,而且可以设置调试选项。可以检测2类错误:①尝试分配太大的内存;②释放内存时发现坏块。有4种错误处理选项,当发生错误时记录消息或挂起任务。 但是,使用动态内存分配malloc/free时要注意到以下几方面的限制。①因为系统内存分区是一种临界资源,由信号量保护,使用malloc会导致当前调用挂起,因此它不能用于中断服务程序;②因为进行内存分配需要执行查找算法,其执行时间与系统当前的内存使用情况相关,是不确定的,因此对于有规定时限的操作它是不适宜的;③由于采用简单的*先匹配算法,容易导致系统中存在大量的内存碎片,降低内存使用效率和系统性能。 针对这种情况,一般在系统设计时采用静态分配与动态分配相结合的方法。也就是对于重要的应用,在系统初始化时分配好所需要的内存。在系统运行过程中不再进行内存的分配/释放,这样就避免了因内存的分配释放带来的总是。而且在系统初始化,因为没有内存碎片,对于大的内存块的需求容易满足。对于其它的应用,在运行时进行动态内存分配。尤其是某些应用所要求的大量固定尺寸的小内存块,这时就可以采用一次分配多次使用的内存分配方案。下面详细介绍这种内存分配方案及其应用场合。
4 一次分配多次使用的内存分配方案 在嵌入式系统设计中,经常有一些类似于内存数据库的应用。这些应用的特点是在内存中管理一些树,比如以太网交换机中的MAC地址表、VLAN表等,或者路由器中的路由表。这些树是由许多相同尺寸的节点组成的。这样,就可以每次分配一个大的缓冲池,比如包含多个内存单元的数组,每个内存单元用于1个节点。我们用一个空闲链表来管理该数组中的空闲内存单元。每次程序需要分配内存以创建1个新的节点时,就从空闲链表中取1个单元给调用者。程序删除节点并释放内存时,将释放的内存单元返还给空闲链表。如果链表中的空闲内存单元取空了,就再次调用malloc从系统内存中分配一个大的内存块作为新的缓冲池。采用这样一种方案主要有如下优点:①减少了malloc/free的调用次数,从而降低了风险,减少了碎片;②因为从缓冲池中取一个内存单元是时间确定的(当然,如果缓冲池耗尽从而需要重新调用malloc分配除外),因此它可以用于严格时限的场合从而保证实时性;③它给用户以自由来添加一些用于内存分配和释放的调试函数以及一些统计功能,更好地监测系统中内存的使用情况。 这种方案必然涉及到一个缓冲池的结构。一般缓冲池的结构由以下几部分组成:单元尺寸、块尺寸(或者单元数目)、缓冲池指针、空闲链表、用于统计和调试的参数等。对缓冲池的操作包括创建缓冲池、释放缓冲池、从缓冲池中分配1个内存单元、释放内存单元回缓冲池等。下面举2个例子说明一下该方案的具体使用情况。
4.1 Intel交换机驱动程序中内存分配 在以Intel的交换芯片为基础的交换机方案中,因为采用的是软件地址学习的方式,需要在内存中维护许多数据,如MAC地址表的软拷贝、VLAN表、静态单播地址表、组播地址表等。这些表都是由一些树组成,每个树由一些固定尺寸的节点组成。一般每个节点几十个字节,每棵树的节点数是可增长的,少则几十,*多可到16K个节点。因此,很适合于采用该方案,具体的实现如下:
(1)缓冲池结构BlockMemMgr typedef struct{ MemSize data_cell_size; /*数据单元的尺寸*/ MemSize block_size; /*块尺寸*/ /*下面的变量为预定义的每个管理器*多包含的块数,如64 MAX_BLOCKS_OF_MEM_SIZE*/ Unsigned short blocks_being_used;/*已使用的块数*/ Void mem_ptr[PAX_BLOCKS_OF_MEM_SIZE]; /*块数组*/ SLList free_data_cells_list; /*空闲链表*/ }BlockMemMgr; 结构中的参数包括:单元尺寸、块尺寸、已用块数、所有块的地址、空闲链表(单向链表)。
(2)缓冲池的管理函数
◆block_mem_create:创建块内存管理器,参数包括内存指针(如为NULL,表示自己分配)、块尺寸、单元尺寸、返回管理器指针。 过程如下: ①检验参数合法性。 ②单元尺寸4字节对齐,计算每个块中的单元数。对内存指针进行4字节对齐或者分配内存指针。 ③初始化结构BlockMemMgr,包括单元尺寸和块尺寸。设置第1个内存块的指针。如果内存是外来的,设置块已用标志(已用为0),表示不能增加块;否则,已用块数设为1。 ④创建空闲链表,将块内所有单元添加到链表中,*后一个单元处于链表的*前面。 ⑤返回BlockMemMgr。
◆block_mem_destroy:解构一个块内存管理器,释放它所分配的所有内存,调用者负责外部内存的释放。参数为BlockMemMgr。返回成功失败标志。 ①参数合法性检测。 ②删除单向链表(设链表指针为NULL)。 ③如果块是动态分配的,释放它们。 ④释放结构BlockMemMgr。
◆block_malloc:从块内存管理器中分配1个单元。参数为BlockMemMgr,返回数据单元指针。 ①参数合法性检测。 ②判断空闲链表是否为空(是否为NULL)。如果为空,判断是否可以动态分配块,如果不能,返回失败;如果可以动态分配块,则分配1个块,执行与block_mem_create一样的操作。 ③从空闲链表中分配第1个单元,返回其指针。 注意这里有一个小技巧,即数据单元在空闲时其中存放空闲链表的节点信息,而分配后则存放数据内容。
◆block_free:释放1个数据单元,返回块内存管理器。小心不要对1个单元释放2次。参数为BlockMemMgr和单元指针。 ①参数合法性检测。 ②地址比较,判断数据单元属于哪个块。 ③判断数据单元的内容是否为空闲链表节点信息(也就是块内某单元的地址),从而确定是否为2次释放。 ④将该数据单元插入到空闲链表的前面。 ⑤引用该单元的指针设为NULL。
内存管理代码遵守如下约定:①管理的内存是实际可写的内存;②分配内存是4字节或32位对齐;③block_malloc、block_free在中断级调用是部分安全的,除非BLOCK中已经没有空闲CELL,需要重新调用malloc分配新的BLOCK(而malloc和free就不是安全的,因为其中使用了信号量和搜索算法,容易引起中断服务程序阻塞)。当然,block_mem_create和block_mem_destroy必须在进程级调用。 4.2 TMS中的内存分配 TMS是WindRiver公司为可管理式交换机推出的开发包。它用用IDB来管理各种协议的数据,比如STP和GVRP等。为了支持IDB,它建立了自己的缓冲池管理方案,程序在bufPoolLib.c中。该程序包含用于缓冲池管理的函数,这些函数允许从1个池中分配固定数目和大小的缓冲区。通过预先分配一定数目固定大小的缓冲区,避免了反复的小的内存块分配/释放相关联的内存碎片和浪费。既然它从1个单一的块中分配缓冲池,也比对每一个缓冲区执行1次分配有更高的空间效率。模块对每个缓冲区加上1个标记(MAGIC),释放时会检查标记。模块给用户提供分配和释放操作定义回调函数的能力。这样可以做到自动的对象创建和解构,同时允许由多个缓冲池分配的成员组成的对象做为1个单一的实体删除。这类似于C++中自动的对象构建和解构,不过是用C语言并且没有堆栈分配的负担。模块既允许从堆栈中分配缓冲池(通过calloc),也可以在用户分配的空间中创建它们。模块用1个单向链表来维护未分配的缓冲区,但不跟踪已分配的缓冲区。模块并不是任务安全的,用户需要用信号时来保护缓冲池。
(1)缓冲池结构
typedef struct
{ ulong_t magic; /*用于一致性检测的特殊标记*/
Boolean localAlloc; /*内存是否在创建缓冲区时分配*/
SL_LIST freeList; /*空闲链表*/
Void store; /*缓冲区指向的内存指针*/
STATUS(*createFn)(void*,ulong_t argl); /*创建缓冲区时的回调函数指针*/
STATUS(*destroyFn)(void*,ulong_targl);/*释放缓冲区时的回调函数指针*/
Ulong_t argVal;/*回调函数的参数*/
} buf_pool_t;
结构中的参数包括检查标记MAGIC、是否本地分配、空闲链表、内存指针、创建缓冲池的回调函数指针、释放时的回调函数指针、回调函数参数。
(2)相关函数
◆BufPoolInitializeStorage:分配和初始化存储区。参数包括存储区地址(如为NULL,则本地分配)、缓冲区大小、缓冲区个数。 ①根据缓冲区大小和个数获得所需的内存大小。 ②如果指针为NULL,则调用calloc分配内存。设置本地分配标志。 ③初始化内存为0。 ④初始化指针。分配的内存块*前面为缓冲池结构buf_pool_t。实际的存储区紧随其后。Buf_pool_t包含参数检查标记、是否本地分配、存储区地址、分配时回调函数、释放时回调函数、回调函数变量。此时只设置存储区指针。
◆BufPoolCreate:创建缓冲池。参数为内存制止。缓冲区尺寸和个数,创建时回调函数、释放时回调函数、回调函数参数。 ①尺寸对齐。 ②调用bufPoolInitializeStorage初始化内存区和buf_pool_t结构。 ③用传入参数填充buf_pool_t结构。 ④将缓冲区添加到空闲链表中,*后的缓冲区在*前面。
◆BufPoolDestroy:删除缓冲池。参数为buf_pool_t指针。 ①检查缓冲池结构中的MAGIC字段是否被个性。 ②如果是本地分配的则翻放内存区。
◆BufPoolAlloc:从缓冲池中分配一个缓冲区,参数为缓冲池结构指针。如果存在空闲缓冲区,则从空闲链表中除并提供给调用者,执行创建时回调函数。如果回调函数返回错误,则将缓冲区返还给空闲链表。 ①检查缓冲池结构中的MAGIC标记是否完好。 ②从空闲链表中取出头一个节点。 ③如果节点不为空,清空节点,以其地址为参数调用回调函数。 ④如果回调函数返回错误,则将节点还给空闲链表。 ⑤返回得到空闲缓冲区地址。
◆BufPoolFree:将缓冲区返回给缓冲池。如果定义了回调函数,将在归还缓冲之间调用回调函数。参数为缓冲池结构和缓冲区指针。 ①缓冲池MAGIC标记是否完好。 ②如果定义回调函数、调用之。如果返回错误,则设置错误号。 ③将缓冲区添加到空闲链表中头部。 注意该函数有2点:①回调函数返回错误,照样归还缓冲区。②没有检查缓冲区是否二次释放,这一点与Intel的驱动程序不同。 另外,TMS的缓冲池没有BLOCK要领,不需要判断哪个CELL属于哪个BLOCK,简化 了操作。 5 小结 许多嵌入式应用在RTOS提供的malloc/free的基础上编写自己的内存管理方案。编写这样的内存管理方案,目的无非有两个:一是减少对malloc/free的依赖,从而避免由之带来的内存碎片、时间不确定等总是;另一个是增强程序的查错能力,送还内存使用错误。对于在嵌入式系统中广泛存在的数据库类型的内存需求,即分配多个固定尺寸的内存单元的要求,“一闪分配,多次使用”的方案无疑是一种很好的解决之道。文中介绍的2个例子很好地体现了它的优越性。

谈谈安卓的桌面小组件

看到 Android 12 居然更新了 widget api,就谈谈谷歌把整套 widget 设计的多失败:

  1. 布局难以预期。长宽数值完全取决于桌面 host 的实现,导致根本无法正常设计 ui 。想象一下,宽高都不知道,里面的控件怎么设置大小,不同桌面不同样子。指定 2×2 大小的 cell,桌面实际给你的宽高是长方形 ?
  2. 无法更新。用户不打开 app 无法刷新 widget 。updatePeriodMillis 在国内的手机上基本都被无视了,换定时任务刷新?国内老生常谈了,能按时唤醒算我输。
  3. 桌面带来的各种 bug 。。。AppWidgetProvider 查到的和实际桌面上的都对不上,这还是亲儿子的 pixel launcher 。

为什么 iOS 14 之后的 widget 质量普遍比安卓高,因为安卓这货就是个残废,没人能用好。本来都凉了的东西,反倒强行被苹果反哺续命。看了文档,基本还是修修补补,想让开发者适配系统主题色,痛点一个不解决。整个 Android 12 更新也是一言难尽,系统强制插闪屏、分区储存依然不强制、从苹果抄来的粗略位置被 iOS 甩开好远,属于抄都抄不好,不知道谷歌这一年在干嘛,有空开个帖子分条讲。

补条关于“粗略位置”的,就是把一直有的 ACCESS_COARSE_LOCATION 权限拆开可以单独授予了,相比 iOS 的主动偏移真实地址、降低更新频率,COARSE_LOCATION 只是不使用 GPS,实际网络定位的精度已经很准了,不知道怎么算是“保护隐私”。

2 条回复

Helsing
    1

Helsing   4 小时 27 分钟前 via iPhone

这东西多少年没更新了,真的是相当的难用,特别是刷新 UI 的时候
Michelangelono
    2

Michelangelono   4 小时 25 分钟前

android 的 api 的确是有很多问题。android 生态混乱 google 有很大责任。

Android 10 ,未授予任何权限,一些 App 会在某些二级目录创建文件

例如 Download 和 Music

那么

浏览器下载文件就可以不需要存储权限

App 能否读取其创建的文件,还是可以读取或修改所有数据,甚至创建次级目录

Android 目录有什么例外吗
第 1 条附言 · 5 天前
即使删除了 Music 目录,依然会在每次打开 App 时,建立 1 个由大小写字母、数字、字符组成,名称固定,大小不变但不足 2 kB 的 mp3 文件

shijianit 1
shijianit 5 天前
Android10 及以上,默认有外部存储公共目录写权限,如系统相册目录,读取相册列表需要外部存储读权限
ronman 2
ronman 5 天前
别说安卓 10 了,11 强制分区存储了不一样在公共目录拉屎吗。
BeautifulSoap 3
BeautifulSoap 5 天前 via Android
谷歌对 Android 的 app 随地拉屎问题毫不作为都这么多年了,即便是 Android11,只要你不 root 依旧没法管住 app 拉屎。想真正管住就 root 装存储重定向吧
dingwen07 4
dingwen07 5 天前 via iPhone ❤️ 1
创建的文件和目录别的 app 没存储权限就读不了,该 app 自己被重装之后也读不了
好像是这样的
liuidetmks 5
liuidetmks 5 天前
安卓为什么不学习 iOS,一个 app 一个目录
codehz 6
codehz 5 天前 via Android
@BeautifulSoap sr 管不住,rikka 还在研究新魔法呢
sky96111 7
sky96111 5 天前
@liuidetmks 一开始没考虑到,现在收拾包袱太大了。再加上大多数非国产程序没有这个问题,Google 也不太想管
JensenQian 8
JensenQian 5 天前
https://play.google.com/store/apps/details?id=moe.shizuku.redirectstorage
这个试下
JensenQian 9
JensenQian 5 天前
@JensenQian #8 20 刀有点贵
relieve56 10
relieve56 4 天前 via iPhone
@codehz sr 用了几年,每次下载新 app 或者有什么别的需求都要调半天,*后受不了换了果。。sr 重度用户真应该直接换 iOS,换了一身轻松

xmumiffy 11
xmumiffy 4 天前 via Android
换 iOS x
卸载文档管理器 ✓
beginor 12
beginor 2 天前
在根目录下建一个“我的文档”目录, 然后文档管理期默认就打开这个目录 ?
hu8245 13
hu8245 2 天前
@beginor 当真可行?创建的文件夹名称叫做 “我的文档”?
merpyzf 14
merpyzf 2 天前
如果在 Android10 的设备上应用不申请权限就可以随意在用户存储目录下读写文件的话那么这个 app 的 targetAp i 一定是低于 23 以下的。
Ga2en 15
Ga2en 2 天前
music 文件夹里面的东西基本都是 TX 游戏创建的,还有一些奇怪的 APP 船舰一系列从 a~z 的文件夹(特别是某家,自己编译了媒体存储,造成奇怪的文件夹层出不穷 mixiao ),已经换阵营了。
beginor 16
beginor 1 天前 via Android
@hu8245 应该 SD 卡根目录下创建,然后自己只看这个目录,其它可以无视
sw926 17
sw926 1 天前 ❤️ 1
Download 和 Music 是专有文件夹,Android 10 分区存储情况下 App 可以不申请权限在这些文件夹下创建文件,但是 App 只能访问自己创建的文件。对于一些图片、视频编辑软件来说,导入素材可以通过文件浏览器手动授权,编辑完可以直接导出到相册,对开发者来说不用动态申请权限了,对用户来说不用担心 App 会读取到全部的相册内容。道高一尺,魔高一丈,遇到流氓软件就直接把专有文件夹当额外存款空间了,不知道他们怎么想的,这些文件在 App 卸载了也不会删除,但是重装后就没有权限去读这些文件了。

为什么安卓手机不能看电池健康度?

是苹果设备有什么特殊硬件吗,安卓和 windows 好像都不能看电池*大容量,这个功能用来量化电池损耗还挺实用的。

Xusually
    1

Xusually   2 天前   ❤️ 3

其实参数也是有的,就是没有展示。

苹果的健康度出台背景大概楼主已经忘记了,当时苹果的更新降频,限制了 cpu 的性能,引起用户大面积不满,苹果把健康度搬出来为了给自己的“远程施法”解释。例如:
https://www.chongdiantou.com/wp/archives/22548.html
https://www.feng.com/post/11210169

安卓么,厂商貌似没这么干过。。。。。。

mygreens
    2

mygreens   2 天前

@Xusually “其实参数也是有的,就是没有展示。”

能查到么

westoy
    3

westoy   2 天前   ❤️ 1

早前有的, Accu​Battery 之类的, 2.x 时代的国民级 app, 还有怎么通过 recovery 重置电池容量缓存的教程

后来都上了 4000mah, 快充迭代又卷的嗨, 换个电池又便宜, 就没多少人关注了

haaro
    4

haaro   2 天前

https://developer.android.com/training/monitoring-device-state/battery-monitoring
Monitor the Battery Level and Charging State
ronman
    5

ronman   2 天前 via Android   ❤️ 1

Windows 的话用 powercfg /batteryreport /output “C:\battery_report.html” 有很详细的报告
mygreens
    6

mygreens   2 天前

@haaro 这个是当前电量吧 跟健康度什么关系
Xusually
    7

Xusually   2 天前

@Xusually 部分厂商有出 app 看状态,例如三星。
更多的厂商可以通过工程模式里的电池状态查看。
貌似也有些 app 可以读取,用的少就没办法推荐了。adb 也可以查看电池的参数,部分厂商给的返回信息里有。

crclz
    8

crclz   2 天前

安兔兔可以通过一次从低电量到高电量的充电估算电池实际容量。充电范围越大,估算的也越准确。
我猜这个电池健康度不是电池能够直接提供的一个信息,而是需要算法进行估算的。
Cheons
    9

Cheons   2 天前

有 没必要放到明面上,
本来就是损耗品不行就换
yukiww233
    10

yukiww233   2 天前

https://www.zhihu.com/question/53436383
tankren
    11

tankren   2 天前   ❤️ 10

要是能发明一种可以换电池的手机就好了:doge
mgrddsj
    12

mgrddsj   2 天前   ❤️ 1

Windows 上想看电池损耗的话,除了楼上说的 powercfg 命令,还可以用 BatteryInfoView 这个小软件,相当直观:
http://www.nirsoft.net/utils/battery_information_view.html
Muniesa
    13

Muniesa   2 天前 via Android

一加可以通过一加诊断来看 https://i.loli.net/2021/06/15/glhEoc7w3md9z4B.jpg
LiYanHong
    14

LiYanHong   2 天前

老版本安卓可以拨*#*#INFO#*#*看到电池信息,不知道从哪个版本去掉了
linchengzzz
    15

linchengzzz   2 天前

我的手机是拨号 *#*#7378423#*#* 可以看, 不知道其他手机能行不
vate32
    16

vate32   1 天前

MIUI 不是有的吗
TheEastWind
    17

TheEastWind   1 天前

一加在以前的时候,用 *#808# 进工厂测试模式,可以看到寿命百分比。

后来系统更新就取消了。

MaverickLee
    18

MaverickLee   1 天前

Accu​Battery
cuixiao603
    19

cuixiao603   1 天前

@LiYanHong #14 不懂就问啊 ,这个 info 怎么拨啊 九宫格吗
0747916
    20

0747916   1 天前

miui 可以看的吧
LiYanHong
    21

LiYanHong   1 天前

@cuixiao603 INFO 对应 4636 啊,国外的电话号码经常用字母,容易记,就是九宫格这样拨
Lightbright
    22

Lightbright   1 天前 via Android

/sys/class/power_supply/battery/ 在这个位置
OldDriverKing
    23

OldDriverKing   1 天前   ❤️ 1

我觉得不显示也挺好的,免的产生焦虑感。有的人看个剩余电量 99%就开始焦虑了
gdyong
    24

gdyong   1 天前

安卓这种便宜货,需要吗 手动狗头
dingwen07
    25

dingwen07   1 天前

国产安卓换电池便宜,觉得续航不行了就去换一块
linshixiong
    26

linshixiong   1 天前

需要硬件支持,目前红米 note 10 pro 支持
chonger
    27

chonger   1 天前

能看的话很多人就不敢买超级快充的机器了
liaojl
    28

liaojl   1 天前 via iPhone

@tankren 再发明一种手机电池充电器,可以根据不同电池正负*的距离调整充电器的接触金属片?
aabbcc112233
    29

aabbcc112233   1 天前

@liaojl 我已经给这个产品想好名字了, “万能充” , 准备去搞了, 一起吗
liaojl
    30

liaojl   1 天前 via iPhone

@aabbcc112233 idea 有了,就差投资商了
S179276SP
    31

S179276SP   1 天前 via Android

华为的话,客服可以远程检测电池寿命
Arrowing
    32

Arrowing   1 天前

@tankren 你说的这个是不是诺基亚 :doge
yousabuk
    33

yousabuk   1 天前 via iPhone

@liaojl

我已经做出了样品了,快找投资人。
@tankren
@liaojl
@aabbcc112233

luoyebuyu
    34

luoyebuyu   1 天前

大法的手机可以
cweijan
    35

cweijan   1 天前

没必要.
Maiiiiii
    36

Maiiiiii   1 天前

以前上高中住校,用的三星,七块电池一天一块,周末出去外面找万能充
Vincentcow
    37

Vincentcow   19 小时 7 分钟前

accu battery
没拼错吧通过检测充电时长和电流判断容量区间

msaionyc
    38

msaionyc   18 小时 5 分钟前 via iPhone

@tankren 那也太牛了吧
searene
    39

searene   16 小时 15 分钟前

感觉手机不能换电池就是技术的倒退
RainbowCandy
    40

RainbowCandy   58 分钟前 via Android

感觉电池越来越不耐用,但你就是不知道电池究竟是真不行了还是系统更新恶意耗电逼迫用户换电池换机。电池也不算贵,闪充当道,加上“*励自己”的心理,直接就换机了。对于电池寿命这块,应该让用户心里有数。现实是大部分人真的不在乎换电池的那点钱,管他到底啥原因,感觉不耐用换就完了

Oracle中复杂数据类型–集合

集合是用来处理多行单列的数据,记录是用来处理单行多列,变量处理单行单列数据,PL/SQL记录表处理多行多列数据
1.索引表
下标可以为负数,并且元素的个数没有限制,只能作为PL/SQL复合数据类型使用.
TYPE type_name IS TABLE OF element_type
[NOT NULL] INDEX BY key_type;
identifier type_name;

type_name用于指定用户自定义数据类型的名称(IS TABLE .. INDEX表示索引表),element_type用于指定索引表元素的数据类型.NOT NULL表示不能引用NULL元素.
key_type用于指定索引表下标的数据类型(BINARY_INTEGER, PLS_INTEGER, VARCHAR2),identifier定义索引表变量
DECLARE
TYPE ename_table_type IS TABLE OF emp.ename%TYPE
INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
BEGIN
SELECT ename INTO ename_table(-1) FROM emp
WHERE empno=&no;
dbms_output.put_line(‘雇员名:’||ename_table(-1));
END;
其中ename_table(-1)表示下标是-1的元素.

DECLARE
TYPE ename_table_type IS TABLE OF NUMBER
INDEX BY VARCHAR2(10);
ename_table ename_table_type;
BEGIN
ename_table(‘北京’) := 1;
END;

2.嵌套表
元素下标从1开始,元素个数没有限制,值可以是稀疏的.可以作为表列的数据类型使用.
TYPE type_name IS TABLE OF element_type
identifier type_name;
type_name用于指定嵌套表的名字,element_type指定嵌套表元素的数据类型.在使用时,必须先使用构造方法先初始化构造表
(1)在PL/SQL块中使用嵌套表
DECLARE
TYPE ename_table_type IS TABLE OF emp.ename%TYPE;
ename_table ename_table_type
BEGIN
ename_table:=ename_table_type(‘MARY’,’MARY’,’MARY’);
SELECT enmae INTO ename_table(2) FROM emp
WHERE emp_no=&no;
dbms_output.put_line(‘雇员名:’||ename_table(2));
END;
(2)在表列中使用嵌套表
必须先使用CREATE TYPE命令来建立嵌套表类型,当使用嵌套表类型作为表列的数据类型时,必须为嵌套表指定专门的存储表
CREATE TYPE phone_type IS TABLE OF VARCHAR2(20);

CREATE TABLE employee(
id NUMBER(4), name VARCHAR2(10),sal NUMBER(6,2),
phone phone_type)NESTED TABLE phone STORE AS phone_type;

经过上面的定义后,就可以在建立employee的时间使用这个嵌套类型了.
BEGIN
INSERT INTO employee VALUES(1, ‘SCOTT’, 800, phone_type(‘123456′,’13245641234’));
END;

3.变长数组(VARRAY)
下标从1开始,元素的*大个数是有限制的.
TYPE type_name, IS VARRAY(size_limit) OF element_type[NOT NULL];
identifier type_name;
使用的时间必须要用构造方法进行初始化,例如:
DECLARE
TYPE ename_table_type IS VARRAY(20) OF emp.ename%TYPE;
ename_table ename_table_type:=ename_table_type(‘A’,’A’);
BEGIN
SELECT ename INTO ename_table(1) FROM emp
WHERE empno=&no;
dbms_output.put_line(‘雇员姓名:’||ename_table(1));
END;

VARRAY也可以作为列的数据类型使用,在表中引用此数据类型必须先create type
CREATE TYPE phone_type IS VARRAY(20) OF VARCHAR2(20);
CREATE TABLE employee(
id NUMBER(4),
name VARCHAR2(20),
sal NUMBER(6,2),
phone phone_type);

搜索引擎收录提交链接大全

谷歌网站收录提交http://www.google.com/intl/zh-CN/add_url.html

谷歌新闻源收录提交http://www.google.com/support/news_pub/bin/request.py?contact_type=suggest_content&hl=cn

谷歌博客收录提交http://blogsearch.google.com/ping?hl=zh-CN

谷歌网站管理员工具http://www.google.com.hk/intl/zh-CN/webmasters/点击这里查看详细操作步骤。

百度网站收录提交http://www.baidu.com/search/url_submit.html

百度博客收录提交http://utility.baidu.com/blogsearch/submit.php

百度站长平台http://sitemap.baidu.com/

百度搜索开放平台http://open.baidu.com/

微软bing网站收录提交http://cn.bing.com/docs/submit.aspx

微软bing站长工具http://cn.bing.com/toolbox/webmasters/

搜狗网站收录提交 http://www.sogou.com/feedback/urlfeedback.php

搜狗博客收录提交 http://www.sogou.com/feedback/blogfeedback.php

SOSO网站收录提交http://www.soso.com/help/usb/urlsubmit.shtml

SOSO博客收录提交 http://blog.soso.com/join.html

有道网站收录提交 http://tellbot.yodao.com/report?type=web

有道博客收录提交 http://tellbot.yodao.com/report?type=BLOG

雅虎中国网站收录提交 http://search.help.cn.yahoo.com/h4_4.html

Dmoz网站登录入口 http://www.dmoz.com/World/Chinese_Simplified

Alexa网站登录入口 http://www.alexa.com/help/webmasters

 

Tips:

如何知道自己的网站是否已经被搜索引擎收录?只要在搜索引擎中输入“site:yoursite”然后搜索(注:yoursite是网站域名,例如site:xxx.net是查询博客是否已经被收录),如果有搜索结果则证明已经成功收录了。

[poll id=”2″]

数据库PL/SQL快捷键设置

Oracle数据库中,PL/SQL设置快捷键的方法是本文我们主要要介绍的内容,了解了这些设置可以是我们更效率地使用Oracle数据库,接下来就让我们一起来了解一下这部分内容吧。

1、登录后默认自动选中My Objects

默认情况下,PLSQL Developer登录后,Brower里会选择All objects,如果你登录的用户是dba,要展开tables目录,正常情况都需要Wait几秒钟,而选择My Objects后响应速率则是以毫秒计算的。

设置方法:

Tools菜单 –> Brower Filters,会打开Brower Folders的定单窗口,把”My Objects”设为默认即可。

Tools菜单–Brower Folders,中把你经常点的几个目录(比如:Tables Views Seq Functions Procedures)移得靠上一点,并加上颜色区分,这样你的平均寻表时间会大大缩短,试试看。

 2、记住密码

这是个有争议的功能,因为记住密码会给带来数据安全的问题。 但假如是开发用的库,密码甚至可以和用户名相同,每次输入密码实在没什么意义,可以考虑让PLSQL Developer记住密码。

设置方法:菜单Tools –> Preferences –> Oracle –> Logon History –> Store With Password

3、双击即显示表数据

鼠标双击表或者视图时的默认响应实在让我感到失望,因为我*关心的是表结构和数据,但是双击后这两件事情都没有发生,也许默认响应是高手们需要的,但对我来说查看数据和表结构是*主要的,其他的我不关心。不过好的是这是可以设置的,你可以给鼠标双击和拖放绑定需要的事件,比如:双击编辑数据,拖放显示表结构,Yeah!

设置方法:菜单Tools –> Preferences –> Browser,在右侧,为不同的Object Type绑定双击和拖放操作。

4、SQL语句字符全部大写

自认为这是个好习惯,信息系统的核心是数据库,系统出问题时*先要查的就是SQL语句,怎样在浩瀚的日志中快速找到那条SQL语句是件比较痛苦的事情。 SQL语句全部大写并不能彻底解决这一问题,但在一堆代码中间找一行全部大写的字符相对容易些,你的眼睛会感谢你。

设置方法:菜单Tools –> Preferences –> Editor –> Keyword Case –> Uppercase

5、特殊Copy

在SQL Window里写好的SQL语句通常需要放到Java或者别的语言内,就需要转成字符串并上加上相应的连字符,这一个事不需要再重复做了,在写好的SQL上点右键,使用特殊Copy即OK!

设置方法:鼠标右键 –> Special Copy

6、自定义快捷键

PLSQL Developer里预留了很多键让用户自定义,这是件很Hight的事情。不像霸道的Word,基本上所有的键都已预定义了功能,修改起来很是头疼。 通常情况下,打开PLSQL Developer后,*经常干的事就是打开SQL Window和Command Window,就给这两个操作定义了快捷键,ALT+S和ALT+ C,这样拿鼠标点三下的事情只需要按一下键。

设置方法:菜单Tools –> Preferences –> Key Configuration

7、SQL Window中根据光标位置自动选择语句

设置方法:Preferences –> Window Types –> SQL Window,将AutoSelect statement选中即可。注意,每条语句后面要加分号。

8、自动替换

快捷输入SQL语句,例如输入s,按下空格,自动替换成SELECT;再例如,输入sf,按下空格,自动替换成SELECT * FROM,非常方便,节省了大量的时间去编写重复的SQL语句。

设置方法:菜单Tools –> Preferences –> Editor –> AutoReplace. –> Edit

关于Oracle数据库PL/SQL设置快捷键的方法就介绍到这里了,希望本次的介绍能够对您有所收获!