1.安卓手机如何打开.db文件
2.安卓 src是安卓什么意思?
3.使用Copyonwrite改造本地缓存
安卓手机如何打开.db文件
安卓手机打开db文件的方法是:
1、首先在电脑安装SQLiteDeveloper,使用数据设置安装后在桌面生成图标,本地点击图标打开程序。库源
2、码安打开程序后,卓使.net源码解析可以看到程序左边的用本源码“数据库列表”。展开可以查看到所有打开过的地数数据库。
3、据库点击一个db文件,安卓把这个db直接拖拉进程序窗口。使用数据设置
4、本地显示“注册数据库”,库源点击确定,码安就可以用SQLiteDeveloper管理这个db文件了。卓使
5、展开左边数据库列表,找到刚才注册的db文件。点击右键菜单的求购阿拉德之怒源码打开数据库。
6、打开数据库后可以看到这个db文件中有很多的数据表,选择其中一个,右键点击查询数据即可。
安卓(Android)是一种基于Linux的自由及开放源代码的操作系统。主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。Android操作系统最初由AndyRubin开发,数字党建大屏源码下载主要支持手机。年8月由Google收购注资。
年月,Google与家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。随后Google以Apache开源许可证的授权方式,发布了Android的源代码。第一部Android智能手机发布于年月。Android逐渐扩展到平板电脑及其他领域上,上门口令雷源码搭建如电视、数码相机、游戏机、智能手表等。年第一季度,Android在全球的市场份额首次超过塞班系统,跃居全球第一。年的第四季度,Android平台手机的游戏号登号器源码全球市场份额已经达到.1%。年月日谷歌开发的操作系统Android在迎来了5岁生日,全世界采用这款系统的设备数量已经达到亿台。
安卓 src是什么意思?
安卓 src指的是安卓系统中的源代码,也就是android project工程文件中的java代码以及资源(如,布局文件等)所在的目录。通常情况下,安卓应用程序的开发者需要使用src目录来编写Java代码,这些代码将被编译成可执行程序。可以理解为src目录是安卓程序的核心所在。
安卓 src的作用主要在于提供程序的运行逻辑、处理用户交互行为、数据存储与处理等组成部分的代码。在开发安卓应用程序时,开发人员会在src目录下创建多个Java类,这些Java类被用于实现应用程序中的各种功能。此外,src目录中也包含应用程序本身的AndroidManifest.xml文件,这是应用程序信息的配置文件,其中包括应用程序的名称、版本号、图标、权限等信息。
在安卓应用程序的开发过程中,编写Java代码几乎是不可避免的,这些代码通常存放在src目录下,通过Android Studio(或其他类似的开发工具)来编写、查看和修改代码。开发者可以利用Java编程语言实现应用程序的逻辑,并借助各种Android SDK提供的API实现各种常见的功能,如网路请求、数据库操作、UI布局等。除了Java代码,开发人员还需要在res目录下创建各种资源文件,如、布局文件、颜色值文件等,这些资料也会被src目录中的Java代码使用。
使用Copyonwrite改造本地缓存
背景
周四下午正在吃的下午茶,偷闲刷了一会手机(光明正大的),突然就有客服中心的**姐找上门来说xxx操作又出现失败了,但是多点几次又没问题了(之前也出现过,可是代码中没有任何异常处理和日志的输出很难排查,没办法老代码,前任写的我也没办法,只能加上等复现的时候再看看),看着**姐焦急的表情,下午茶瞬间就不香了,找bug去!
产生原因定位在rancher上输入账号找到对应的服务,根据关键字找到相关日志映入眼帘的是java.lang.NullPointException跟随报错的行数找到了相关代码块:
if(StringUtils.isNotEmpty(feeSetting.getFileId())){ returnschoolService.deal(sysConfigService.getString("url"));}其中报错的是
schoolService.deal(sysConfigService.getString("url"));定位问题,应该是调用StringgetString(Stringkey);空指针导致的.
分析相关代码:
publicStringgetString(Stringkey){ if(configs==null){ initConfig();}returnconfigs.get(key);}其中initConfig()的实现:
privatevoidinitConfig(){ synchronized(lock){ if((configs==null)||configs.isEmpty()){ configs=newHashMap<String,String>();//从db中加载到configsloadSysConfig();}}}其中configs是个成员变量
privatestaticMap<String,String>configs=null;复制代码查了一下数据库,有对应的数据存在,不是数据的问题
getString(Stringkey)接口内部没报错,说明这个程序没报错
抓了抓头(有点意思),只有Map中没有相应的数据才有可能报空指针,查找了相关方法,找到了如下代码:
publicvoidreload(){ if((configs!=null)&&!configs.isEmpty()){ configs.clear();this.initConfig();}}只有一处调用该方法
@ComponentpublicclassSysConfgMQListenerimplementsMessageListenerConcurrently{ protectedfinalLoggerlog=LoggerFactory.getLogger(SysConfgMQListener.class);@AutowiredprivateISysConfigServicesysConfigService;@OverridepublicConsumeConcurrentlyStatusconsumeMessage(List<MessageExt>msgs,ConsumeConcurrentlyContextcontext){ log.info("SysConfgMQListenerretrieving...");for(MessageExtmsg:msgs){ log.info("messageExt,body:{ }",newString(msg.getBody()));this.sysConfigService.reload();}returnConsumeConcurrentlyStatus.CONSUME_SUCCESS;}}这是RocketMq的消费者这里调用了,而且还是广播模式,所有节点都能消费,这个Mq的生产者是在后台触发刷新时候产生的.
真相只有一个首先触发Mq的消费,导致Map刷新,重新加载调用reload()
当执行configs.clear();之后Map就是一个空对象,没有任何数据
如果这个时候是有多个线程访问getString(Stringkey)获取到的值就是null
改造第一个想到的是用Redis来替换,但是很快就自我否定了,这个接口在没有触发刷新机制的前提下运行了几年是好好的,而且基础配置放Redis的话过期时间的设置不好判断,并且还要多个IO的传递,性能没有本地的Map好.
第二个想到的方案就是在getString(Stringkey)方法中加锁,这只能当做下下策
正在一筹莫展的时候,突然灵光一闪,这不是跟注册中心很像吗?各个客户端去拉取数据,而nacos为了高性能就是用了Copyonwrite的思想来实现的,越想越行,干!
代码改造如下:
publicvoidreload(){ if((configs!=null)&&!configs.isEmpty()){ //先清除再加载会出现,在两个操作之间请求的接口获取都为空//configs.clear();//this.initConfig();this.reloadForConfigs();}}其中this.reloadForConfigs();
privatevoidreloadForConfigs(){ Map<String,String>newConfigs=newHashMap<>();try{ List<Config>datas=configDao.listConfigs();if(datas!=null){ for(Configcf:datas){ newConfigs.put(cf.getKey(),cf.getValue());}}}catch(Exceptione){ LogUtil.exception(log,e);}if(CollectionUtil.isNotEmpty(newConfigs)){ //替换旧的this.configs=newConfigs;}}这改造完上线之后,跟踪了一段时间日志中也没发现空指针(**姐也不来找我了-_-,不开森),有那么一点点的成就感.
总结开发的时候要考虑多线程和并发场景
遇到问题别慌,认真分析
好的方案不是一蹴而就的
多读好的代码如框架源码,不断的积累,现在用不上,某一时刻就用上了
作者:董懂