详情

全站展示位

解决 golang IDEA中不能debug问题 |

IDEA是2018-01版本,Golang是go-1.12.1,IDEA在Plugins中安裝的Go插件,我在运行go程序時是正常的,但是提示could not launch process: decoding dwarf section info at offset 0x0: too short 解決方案: 1:在终端运行 go get -u github.com/derekparker/delve/cmd/dlv。 2:运行上面的命令之后运行环境中就有dlv了。替换IDEA go 插件中的dlv macOS中的插件地址是:/Users/用户名 /Library/Application Support/IntelliJIdea2018.1/intellij-go/lib/dlv/mac 替换之后就正常了。。。。

推荐

琥珀之月,空谷之兰,皆是孤芳,既是孤芳,但求自赏便罢!

30字的完美简历[转载] |

这个世界上,总有很多人很自以为是地以为若是他们做不到的事情,别人做到了,必定不是什么光彩的正道,必定不是靠自己的实力。包括我。 曾经看到托福GMAT拿满分的人,就会想着:“怎么可能!这个人肯定是小时候在国外生活过吧!” 看到保养地特别好的中年女人,就会撇嘴:“肯定是花重金打玻尿酸啊这针那针啊!” 看到年纪貌美的女孩开着豪车经过,就会想着:“肯定是二奶呀!” 看到年纪轻轻上了富豪榜的青年才俊,就会揣测:“肯定是家族企业啊!” 看到年少成名靠参加选秀红遍大江南北的歌手明星,就会怀疑人家:“估计是被潜规则了。” …… 这样的例子几乎每天都发生着,我也曾一度全然不觉自己在这样的渊里越堕越深。 直到大四有一次去参加一个牛逼公司的面试,面试通知邮件里最后有一条是:请携带不超过30字的Personal Statement(简称PS,个人陈述)。 我一看,疯了吧?30字?!我挨个把自己工作实习过的公司名字和读过书的学校名字列一遍都不止30个字了啊?!我想了想,绝对不可能!应该是他们漏写了个0吧?于是便也不去多想了。 等到面试那天,我带了份自认为已经是非常简洁的PS过去,一路上都觉得真是憋屈啊,很多东西没写进去呢实在没有发挥我洋洋洒洒的特点,都没充分展示我的闪光点呢!但是没办法还是尽量符合这个公司简洁精准的办事风格来吧。 到了公司,我递交上我的PS后,三个面试官不约而同皱起了眉头,一个头发花白的外国男人问我:“你这个字数超过30字了,起码得有400字吧,为什么不按我们的要求做?” 我愣了一下,什么?真的是30字?不是逗我玩? 我有点怀疑地说:“30字?30字写一篇PS根本是不可能做到的呀!这字数也太少了吧!” 一个女面试官很凌厉的口气说:“不可能?不可能的事情我们怎么会要求你做?”她说着把一叠PS亮在我面前,“他们都可能,为什么只有你不可能?” 我刷地一下脸就红了,支吾着说不出话。这是我唯一一次期待着面试官赶紧说:“好了可以了,请你出去吧。” 但是试场里出现里几秒钟的沉默,这几秒钟对我来说,竟然跟失眠的夜晚一样难熬。 那花白头发面试官又开口了:“你觉得这个世界上不可能的事情,是因为你没有试着去做。” 我犹豫了一下说:“谢谢您。我知道我的问题出在哪里了。不知道是否方便让我看一眼其他人的PS,我想知道自己的差距有多大。” 他们几个互相望了一下,点头示意后将一沓PS递给我。 我在拿过来的一瞬间已经被最上面的一份震惊到了。 那整张纸上画了一个应该是以面试者自己为原型的卡通人物,最上面是他的名字,然后是一个巨大的脑袋,脑袋顶部是开放的,用一大片电脑芯片画成了原始森林的样子,旁边写着“computerized mind”,左手拿着画板,写着“Photoshop Skiller ”,右手举着一叠报告,写着“Reportexpert”, 中间的领带处别着个话筒,上面写着“Good Presenter”,心脏的位置画了一颗奇形怪状的心,写着“Creative heart”,脚踩锃亮的皮鞋,穿着毫无褶皱的西裤,旁边写着“Detail-cared”…… 我一边看,一边手心出汗。 这样一份不超过20个单词的PS,我在看完四年后的今天还能够一字不差地回想起来,并且画面栩栩如生,你可以想象它当时带给我的震惊,以及给面试官们带来的印象有多深刻。 接下来的一沓PS里,有画一个大转盘,写出自己的几个特质的;有在一条竖直的时间轴上写了自己做成的几件大事的;还有剪切了几幅自己参加过的作品粘上去的…… 总之没有一个是多于30个字的! 但是每一份PS我看完都如同看到了一个活生生的人站在我面前,我知道他的个性如何,特长是什么,有过什么值得称赞的荣誉。 而我那张全是字的白纸,恐怕人家连看都不想看,即使看了,也不会留下任何印象。 我很不好意思地将一摞纸还给面试官,很诚恳地鞠了一躬,“很抱歉浪费了你们的时间,在来这里之前,我总觉得有些事我做不到,就是不可能做的到的。谢谢你们让我知道我的想法有多愚蠢。谢谢。” 我关上身后那扇门的时候,长长地吁了一口气。 回去的一路,都走的很慢。 我不是在难过失掉了这么一个工作机会,而是在难过地回想在过去的十几年光阴里我究竟失掉了多少次机会?让本该存在的可能,成了我嘴里的不可能。 我明白了一个让人很恼火去承认的事实就是: 那些我觉得不可能的事情,其实根本不是不可能,只是我认为不可能而已。 对一个根本不会去思考去想办法的庸人来说,很多事情都会成为不可能! 后来我试着去做一份字数在30字以内的简历,用了四个晚上后,真的也做出来了。 后来我试着再去做另一份简报似的简历,在用了三个晚上后,同样也真的做出来了。 而在之前,我认为简历就该是白纸黑字,从教育背景到工作经验到兴趣爱好,但其实它充满了那么多的可能性! 可是真的该如此理所当然吗? 我们自己不可能做到,真的是因为我们无能,还是我们根本没有尝试去做? 托福考满分的同学,说不定我们没看到的是,人家起早摸黑悬梁刺股每天练口语练到喉咙发炎; 开着豪车的美女,说不定我们没看到的是,姑娘辛苦打拼几年每天工作累得像狗辛苦攒钱; 保养的很好的中年女人,说不定我们没看到的是,她们每天下班后还去健身房睡觉一定不趴着睡,每晚一定做面膜,十几年如一日; 优秀的青年企业家们,说不定我们没看到的是,他们无数个不眠不休的夜晚,付出比我们这些在睡梦中的人多的多的努力; 那些一朝红遍全国的明星,说不定我们没看到的是,人家之前十几年的默默无闻用心苦练基本功…… 我们什么都没看到,就说别人不可能;我们什么都没去尝试,就说这事不可能。 其实,我们觉得不可能做到的事情,别人真的可以做到。对一个根本不敢去做的人来说,一切都是不可能。 想是问题,做是答案,有时候答案就藏在问题后面!

Android Jetpack Compose 超快速上手指南 |

Compose 介绍 Jetpack Compose发布也快有一年的时间了,虽然目前仍是DEV阶段,但是距离可用已经不远了。Compose库是用响应式编程的方式对View进行构建,可以用更少更直观的代码,更强大的功能,能提高开发速度(可以参考几乎一模一样的Flutter,开发速度确实很快)。 Jetpack Compose对于没有接触过声明式UI的小伙伴可能会学习曲线有点陡峭,对于已经能熟练开发Flutter应用的小伙白来说几乎没有难度。(Compose就是参考flutter的模式开发的,代码中还可以看到Flutter的相关注释) 这篇文章不回去解释过多的原理与技巧,只要是让你能够快速上手开发项目。 Compose 如何使用 因为目前(2020年09月27日)Compose仍处于开发阶段,所以需要使用最新 Canary 版的 Android Studio 预览版。 可以选择直接创建Empty Compose Activity来创建一个全新的Compose应用,或者可以选手动修改gradle的方式来创建Compose应用 修改Gradle 在模块的build.gradle文件中新增: android { ... kotlinOptions { jvmTarget = '1.8' useIR = true } buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion compose_version kotlinCompilerVersion '1.4.0' } } dependencies中新增: implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.material:material:$compose_version" implementation "androidx.ui:ui-tooling:$compose_version" 目前最新的Compose版本是1.0.0-alpha03 使用Compose最低的buildTools版本要求为29 使用 @Compose 所有关于构建View的方法都必须添加@Compose的注解才可以。并且@Compose跟协程的Suspend的使用方法比较类似,被@Compose的注解的方法只能在同样被@Comopse注解的方法中才能被调用

解决 golang IDEA中不能debug问题 |

IDEA是2018-01版本,Golang是go-1.12.1,IDEA在Plugins中安裝的Go插件,我在运行go程序時是正常的,但是提示could not launch process: decoding dwarf section info at offset 0x0: too short 解決方案: 1:在终端运行 go get -u github.com/derekparker/delve/cmd/dlv。 2:运行上面的命令之后运行环境中就有dlv了。替换IDEA go 插件中的dlv macOS中的插件地址是:/Users/用户名 /Library/Application Support/IntelliJIdea2018.1/intellij-go/lib/dlv/mac 替换之后就正常了。

心灵鸡汤

003、《金子与泥巴》

一块金子与一块泥巴相遇。金子不屑地对泥巴说:“你看你,灰不溜秋的,你有我闪亮的光芒吗?”

  泥巴摇摇头。

  “你看你,总是卧在最低层,你有我高贵的身价吗?”金子高傲地说。

  泥巴还是摇了摇头,然后问:“金子啊,你虽然如此荣耀和高贵,但你能生出金子吗?”

  “当然不能。而你又能生出什么呢?”金子一脸的不屑。

  “我能生出花、生出果、生出草、生出树木、生出庄稼、生出万物。”泥巴说。

  在朴实的泥巴面前,金子终于沉默了下来。

列表展示

主站展示位

使用 Rust 开发 Android 底层库,并简化 Java 与 Rust 相互操作 |

前言 提到JNI,大家都会想到C,C++.不过如今Rust又给我们增加了一个选项,借助rust的jni库( 关于 Rust 环境搭建、配置 Rust Android targets、linker,以及如何在 Android 上如何直接运行 Rust 代码,可以看上篇文章 将 Rust 编译为可在 Android 上使用的二进制文件 本文主要介绍如何使用 Rust 借助 J4RS 方便快捷的编写 Android Jni: 阅读本文,你需要具备、了解一下知识: Android 编写 JNI 的基本流程 Rust 代码基本的阅读能力 Android 开发的基本流程 Android 集成 Rust 配置 Rust Android Gradle Plugin Rust Android Gradle Plugin 这个 Gradle 插件的主要功能是帮你自动配置 Rust-Android 交叉编译,并将编译产物自动添加到 Android 项目。 这并不是必须的,你同样可以手动 build rust 项目。然后手动复制到 Android Studio 中使用。 因为我使用的是最新版本的 gradle , 采用 Kotlin kts 编写。在语法上稍有不同,旧版本写法可以在项目的 README 查看

慧极必伤,情深不寿,强极则辱,谦谦君子,温润如玉 |

慧极必伤,情深不寿,强极则辱,谦谦君子,温润如玉: 这是金先生<书剑>里,乾隆送陈家洛佩玉上的刻字。大意:一个人太聪明智慧便会对自己有损伤,过于沉迷和执着的感情不会持续长久,过于突出的人势必会受到屈辱,君子应该如玉一般的温润沉稳,含蓄坚毅,不张扬,却自显价值。 金庸在《书剑恩仇录》中,借乾隆送陈家洛佩玉上之刻字,道出自己人生特别推崇的境界,正是这四句十六字。 但很有意思的是,如此佳句居然没有人能查其出处(人们都认为其境界颇深定有出处)。有人查遍孔孟老庄,以及四书五经,均无所获,故将此难题贴于网上,一年多来终无所获,故被称为“武侠与国文的一个绝题”。其中,最接近的答案是《国风·秦风·小戎》里有“言念君子,温其如玉。”,《易经》第十五卦中有“谦谦君子”,但仅此而已。 金庸“谦谦君子,温润如玉”之说不知其出处,但从《书剑》所蕴涵的他早期的人生 理想来看,这似乎是金庸所推崇的一种人生境界。 飞扬跳脱的个性不属于谦谦君子,因为,玉的光芒是凛于内而非形于外的。雍容自若的神采,豁达潇洒的风度,不露锋芒,不事张扬,无大悲大喜,无偏执激狂,生命的状态在这里呈现出一种成熟的圆润。 佛家有一个词,圆融,是跟这种成熟的圆润颇为相似的境界。是以佛家讲求戒嗔、戒痴、戒贪,无欲无求,尔后能不动声色、不滞于心。谦谦君子的圆润亦同此理。 而要达到这种境界是需要修炼的。修炼是一个很奇妙的词语,人生在世实质上就是一个修炼的过程,只不过并不是人人都可以修成正果。 修成佛、修成仙是尘世之人遥不可及的梦想,但磨去棱角、收敛光华、修成谦谦君子却并非太难的事情。容人之量是修成谦谦君子的前提。斤斤计较、小肚鸡肠修不成君子,开阔的心胸、通透的眼光,才是君子的气量。 于是,我们常常可以看到这样的人,荣损得失面前,总能一笑置之。正所谓,宠辱不惊,闲看庭前花开花落;去留无意,漫随天外云卷云舒。 剑有双刃,谦谦君子亲切柔和,少了无拘无束的冲动莽撞,却也少了率性率真的刚猛豪放。正如一个人磨砺的过程一样,成熟的获得是以天真童趣的无可追回为代价的。 当然,“情深不寿,强极则辱”的背后,似乎也透着一种淡淡的无奈。试想,人活一世,谁人不想追求恒久?只是恒久不可强求,于是退一步海阔天空。这何尝不是一种迂回的战术、以求得宛转的余地?谁能说这种淡淡的无奈不是一种生存的智慧。

RecyclerView里notifyItemRemoved的坑 |

RecyclerView很多时候是展示静态的数据,并不会有删除的操作,讲到RecyclerView时,会提到它提供了一个很好的展现删除操作动画的函数,代码片段一般是这样的 @Override public void onBindViewHolder(final CommonViewHolder holder, final int position) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { contentList.remove(position); notifyItemRemoved(position); } }); } 这样写的话,很快会产生数据删除错乱和超出索引异常导致崩溃。 原因是函数里面的传入的参数position,它是在进行onBind操作时确定的,在删除单项后,已经出现在画面里的项不会再有调用onBind机会,这样它保留的position一直是未进行删除操作前的postion值。 对于尚未进入画面的单项来说,它会使用新的position值,这个值是正确的,如果在单项里加上下面的代码 holder.textView.setText(contentList.get(position) + "#" + String.valueOf(position)); 在删除第一屏的一项后,向上滚动,会发现新滚上来的一行和它上面的一行的textview显示是一样的。 解决办法也很简单 先remove,再notifyItemRemoved, 最后再notifyItemRangeChanged remove:把数据从list中remove掉, notifyItemRemoved:显示动画效果 notifyItemRangeChanged:对于被删掉的位置及其后range大小范围内的view进行重新onBindViewHolder

Flutter中嵌入Native组件 |

Flutter官方提供的控件AndroidView、UiKitView就是一种比较优雅的解决方案了。这里做了一个简单的嵌入TextView的demo(使用这种方式会增加性能上的开销,应该尽量避免使用) 使用方式 native端 跟MethodChannel的使用方法类似,在native侧,我们实现一个PlatformViewFactory(iOS是FlutterPlatformViewFactory),在create方法中,使用平台方法创建View返回。 override fun create(context: Context?, i: Int, any: Any?): PlatformView { return object : PlatformView { override fun getView(): View { val text = TextView(context) text.layoutParams = ViewGroup.LayoutParams(SizeUtils.dp2px(200f), SizeUtils.dp2px(200f)) text.apply { setText("Android View") setTextColor(Color.BLUE) setBackgroundColor(Color.RED) } return text } override fun dispose() { } } } func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?

Android ListView 与 RecyclerView 对比浅析—缓存机制 |

一,背景 RecyclerView是谷歌官方出的一个用于大量数据展示的新控件,可以用来代替传统的ListView,更加强大和灵活。 最近,自己负责的业务,也遇到这样的一个问题,关于是否要将ListView替换为RecyclerView? 秉承着实事求是的作风,弄清楚RecyclerView是否有足够的吸引力替换掉ListView,我从性能这一角度出发,研究RecyclerView和ListView二者的缓存机制,并得到了一些较有益的”结论”,待我慢慢道来。 同时也希望能通过本文,让大家快速了解RecyclerView与ListView在缓存机制上的一些区别,在使用上也更加得心应手吧。 PS:相关知识: ListView与RecyclerView缓存机制原理大致相似,如下图所示: 过程中,离屏的ItemView即被回收至缓存,入屏的ItemView则会优先从缓存中获取,只是ListView与RecyclerView的实现细节有差异.(这只是缓存使用的其中一个场景,还有如刷新等) PPS:本文不贴出详细代码,结合源码食用更佳! 二. 正文 2.1 缓存机制对比 层级不同: RecyclerView比ListView多两级缓存,支持多个离ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。 具体来说: ListView(两级缓存): RecyclerView(四级缓存): ListView和RecyclerView缓存机制基本一致: 1). mActiveViews和mAttachedScrap功能相似,意义在于快速重用屏幕上可见的列表项ItemView,而不需要重新createView和bindView; 2). mScrapView和mCachedViews + mReyclerViewPool功能相似,意义在于缓存离开屏幕的ItemView,目的是让即将进入屏幕的ItemView重用. 3). RecyclerView的优势在于a.mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无须bindView快速重用;b.mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpaper+多个列表页下有优势.客观来说,RecyclerView在特定场景下对ListView的缓存机制做了补强和完善。 缓存不同: 1). RecyclerView缓存RecyclerView.ViewHolder,抽象可理解为: View + ViewHolder(避免每次createView时调用findViewById) + flag(标识状态); 2). ListView缓存View。 缓存不同,二者在缓存的使用上也略有差别,具体来说: ListView获取缓存的流程: RecyclerView获取缓存的流程: 1). RecyclerView中mCacheViews(屏幕外)获取缓存时,是通过匹配pos获取目标位置的缓存,这样做的好处是,当数据源数据不变的情况下,无须重新bindView: 而同样是离屏缓存,ListView从mScrapViews根据pos获取相应的缓存,但是并没有直接使用,而是重新getView(即必定会重新bindView),相关代码如下: //AbsListView源码:line2345 //通过匹配pos从mScrapView中获取缓存 final View scrapView = mRecycler.getScrapView(position); //无论是否成功都直接调用getView,导致必定会调用createView final View child = mAdapter.getView(position, scrapView, this); if (scrapView != null) { if (child != scrapView) { mRecycler.

不使用第三方软件实现Obsidian多平台实时同步 |

这篇文章涉及服务器配置、docker 技术,当然都是很初级的使用 相信很多人跟我一样,不喜欢使用第三方软件来同步 Obsidian 。每次要打开两个软件,很麻烦。这种情况在手机上最为明显。 这也是我为什么从 9 月多就接触了 Obsidian 但是一没有最为主力的原因。虽然印象笔记已经非常的不好用,但是他的同步真的非常的方便。 直到最近在翻看 Obsidian 的插件的时候接触到了这个插件 Self-hosted LiveSync(虽然也有一款支持 WebDav 的插件,但是试了一下连不上服务器,作者说目前 WebDav 还在测试中)这个插件真的非常的棒 👍🏻。实现了无感同步,甚至可以多平台实时同步。 引用一张作者的图: 搭建服务器端 Self-hosted LiveSync 使用的是CouchDB数据库,这是一个开源的具有版本控制的文档数据库。 你可使用 IBM 提供的 CouchDB 数据库,这里有作者写的教程 我们这里还是直接自己搭建,我是在家里的群辉 NAS 上搭建的,如果你没有 NAS 也可以在腾讯云、阿里云等云服务上搭建。优先推荐在 NAS 上搭建。 安装 docker 群辉直接再套件商店安装。云服务器用户使用下面的命令 docker version > /dev/null || curl -fsSL get.docker.com | bash service docker restart 安装数据库 首先创建配置文件 local.ini [couchdb] single_node=true [c

Java服务器端的Servlet的生命周期 |

servlect生命周期,核心与接口: servlect生命周期的主要阶段: 1.创建servlect对象的创建 servlect岁创建的?什么时候创建的? servlect由web创建,默认在请求第一次到达servlect时创建。若请求在次访问该servlect,tomcat不会新创建servlect对象,还是使用第一次创建的servlect方法去执行该业务。所以servlect是单例的。每一个请求使用的servlect都是同一个。所以会出现线程并发的安全问题。servlect是线程非安全的。

已经有女朋友了,又遇到更喜欢的对象怎么办? |

在知乎上开到这个问题,我只能说提问题的人,你还搞不懂“喜欢一个人”和“对一个人有感情”之间的区别。 我举两个不恰当的例子。比如说养狗,虚构两个情景。 情景一:  某天你去宠物市场闲逛,发现有一只泰迪很可爱,伶俐活泼聪明漂亮,还特别粘着你。你当时就动心了,打算买下它。  一问价格,要1500块钱。你身上没带这么多钱,也没带银行卡。当时是下午了,宠物市场马上要关门了。你只能第二天来买了。  于是你嘱咐店主千万不要卖给别人。一定要等你明天早上过来卖给你。店主答应了。 可你回家了还是不放心。晚上在床上都睡不着觉。生怕店主不守信用,把这狗狗卖给别人了。那感觉,就像是爱上了一个姑娘一样。  第二天一早,你就揣了1500块钱奔向宠物市场。  这次,你是从市场的另外一个门进去的,还没有走到昨天那个摊位,你突然发现了另外一只泰迪,比昨天那只更漂亮,更聪明,更可爱,更粘你,价格还更便宜,只要1200元。  我相信,只要你智商正常,你都会选择买1200的这一只。虽然,你为了1500的那一只牵挂了一晚上。但那又如何,遇上更好的,你立刻就移情别恋了。 我们都是这样的人。 因为,我们对那只泰迪,没有感情。 情景二:  某雨天你下班回家,看到一只流浪的小狗趴在你的家门前瑟瑟发抖。你一下子恻隐之心上来了,把它抱回家,给它洗澡,给它喂食,让它睡在毛毯子上。  从此,它就成了你的家人。  接下来的一年,每天早上是它叫你起床。每天你疲惫的下班回到家中,是它在门口等着你。你出去逛街,它走在你前面。有小偷偷你的包,它疯狂吠叫。你看电视,它就睡在你腿上。你上网,它就趴在你脚尖。 它已经成为了你生活的一部分。  一年后。有一个人,也不知道脑子怎么进水了,想要拿一只名贵的纯种狗狗来换你这只不值钱的收养的流浪狗。 你会换吗? 如果是我,当然不换。 因为我对它有感情了。 这就是感情。

⾃定义布局流程 |

⾃定义布局流程 布局过程 确定每个 View 的位置和尺⼨ 作⽤:为绘制和触摸范围做⽀持 绘制:知道往哪⾥绘制 触摸反馈:知道⽤户点的是哪⾥– 流程 从整体看 测量流程:从根 View 递归调⽤每⼀级⼦ View 的 measure() ⽅法,对它们进⾏测量 布局流程:从根 View 递归调⽤每⼀级⼦ View 的 layout() ⽅法,把测量过程得出的⼦ View 的位置和尺⼨传给⼦ View,⼦ View 保存 为什么要分两个流程? 从个体看,对于每个 View: 运⾏前,开发者在 xml ⽂件⾥写⼊对 View 的布局要求 layout_xxx ⽗ View 在⾃⼰的 onMeasure() 中,根据开发者在 xml 中写的对⼦ View 的要求,和⾃⼰的可⽤空间,得出对⼦ View 的具体尺⼨要求

Android 自定义相机自动对焦、二次对焦处理 |

由于android碎片化严重,而且各大厂商极有可能去修改相关API的实现,其中遇到了不少坑,包括实时相机高斯模糊,自动对焦的兼容问题,以及一系列性能问题。换过很多搜索引擎,访问过很多网站,访问过很多网站,拜读过很多代码,没有发现对于相机实时自动对焦特别完美的实现方式。现对相机的自动对焦问题单独做一个记录,算是对这部分的一个总结。也希望后人在这部分能够快速地解决问题,不必浪费过多的时间。测试手机包括:MX4 pro,小米4,华为荣耀3C等等。

android 10 [API 29]适配指南 |

Android 11[API 30]已经发布正式版,来看看全新的 android 11 [api 30] 适配指南 非SDK接口 google 针对非SDK接口的限制 非SDK接口检测工具 官方给出了一个检测工具,下载地址:veridex veridex使用方法: appcompat.sh --dex-file=apk.apk blacklist、greylist、greylist-max-o、greylist-max-p含义 以上截图中,blacklist、greylist、greylist-max-o、greylist-max-p含义如下: blacklist 黑名单:禁止使用的非SDK接口,运行时直接Crash(因此必须解决) greylist 灰名单:即当前版本仍能使用的非SDK接口,但在下一版本中可能变成被限制的非SDK接口 greylist-max-o: 在targetSDK<=O中能使用,但是在targetSDK>=P中被禁止使用的非SDK接口 greylist-max-p: 在targetSDK<=P中能使用,但是在targetSDK>=Q中被禁止使用的非SDK接口 设备ID 从Android 10开始已经无法完全标识一个设备,曾经用mac地址、IMEI等设备信息标识设备的方法,从Android 10开始统统失效。而且无论你的APP是否是配过Android 10。 IMEI等设备信息 从Android10开始普通应用不再允许请求权限android.permission.READ_PHONE_STATE。而且,无论你的App是否适配过Android Q(既targetSdkVersion是否大于等于29),均无法再获取到设备IMEI等设备信息。 受影响的API Build.getSerial(); TelephonyManager.getImei(); TelephonyManager.getMeid(); TelephonyManager.getDeviceId(); TelephonyManager.getSubscriberId(); TelephonyManager.getSimSerialNumber(); targetSdkVersion<29 的应用,其在获取设备ID时,会直接返回null targetSdkVersion>=29 的应用,其在获取设备ID时,会直接跑出异常SecurityException 如果您的App希望在Android 10以下的设备中仍然获取设备IMEI等信息,可按以下方式进行适配: <uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="28" /> Mac地址随机分配 从Android10开始,默认情况下,在搭载 Android 10 或更高版本的设备上,系统会传输随机分配的 MAC 地址。(既从Android 10开始,普通应用已经无法获取设备的真正mac地址,标识设备已经无法使用mac地址) 唯一ID的替代 Google给出的解决方案是:如果您的应用有 追踪非登录用户重装 的需求,可用ANDROID_ID来标识设备。 ANDROID_ID的生成规则为:签名+设备信息+设备用户 ANDROID_ID重置规则:设备恢复出厂设置时,ANDROID_ID将被重置 String androidId = Settings.

Flutter |

琥珀之月,空谷之兰,皆是孤芳,既是孤芳,但求自赏便罢!

Android将汉字转换成拼音 |

采用了单利的模式,可以查看里面的注释 /** * Java汉字转换为拼音 * */ public class CharacterParser { private static int[] pyvalue = new int[] {-20319, -20317, -20304, -20295, -20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036, -20032, -20026, -20002, -19990, -19986, -19982, -19976, -19805, -19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741, -19739, -19728, -19725, -19715, -19540, -19531, -19525, -19515, -19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275, -19270, -19263, -19261, -19249, -19243, -19242, -19238, -19235, -19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006, -19003, -18996, -18977, -18961, -18952, -18783, -18774, -18773, -18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697, -18696, -18526, -18518, -18501, -18490, -18478, -18463, -18448, -18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201, -18184, -18183, -18181, -18012, -17997, -17988, -17970, -17964, -17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752, -17733, -17730, -17721, -17703, -17701, -17697, -17692, -17683, -17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427, -17417, -17202, -17185, -16983, -16970, -16942, -16915, -16733, -16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470, -16465, -16459, -16452, -16448, -16433, -16429, -16427, -16423, -16419, -16412, -16407, -16403, -16401, -16393, -16220, -16216, -16212, -16205, -16202, -16187, -16180, -16171, -16169, -16158, -16155, -15959, -15958, -15944, -15933, -15920, -15915, -15903, -15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659, -15652, -15640, -15631, -15625, -15454, -15448, -15436, -15435, -15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369, -15363, -15362, -15183, -15180, -15165, -15158, -15153, -15150, -15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121, -15119, -15117, -15110, -15109, -14941, -14937, -14933, -14930, -14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902, -14894, -14889, -14882, -14873, -14871, -14857, -14678, -14674, -14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429, -14407, -14399, -14384, -14379, -14368, -14355, -14353, -14345, -14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135, -14125, -14123, -14122, -14112, -14109, -14099, -14097, -14094, -14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907, -13906, -13905, -13896, -13894, -13878, -13870, -13859, -13847, -13831, -13658, -13611, -13601, -13406, -13404, -13400, -13398, -13395, -13391, -13387, -13383, -13367, -13359, -13356, -13343, -13340, -13329, -13326, -13318, -13147, -13138, -13120, -13107, -13096, -13095, -13091, -13076, -13068, -13063, -13060, -12888, -12875, -12871, -12860, -12858, -12852, -12849, -12838, -12831, -12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556, -12359, -12346, -12320, -12300, -12120, -12099, -12089, -12074, -12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798, -11781, -11604, -11589, -11536, -11358, -11340, -11339, -11324, -11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041, -11038, -11024, -11020, -11019, -11018, -11014, -10838, -10832, -10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533, -10519, -10331, -10329, -10328, -10322, -10315, -10309, -10307, -10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254}; public static String[] pystr = new String[] {"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "ceng", "cha", "chai", "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "lv", "luan", "lue", "lun", "luo", "ma", "mai", "man", "mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", "niu", "nong", "nu", "nv", "nuan", "nue", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi", "pian", "piao", "pie", "pin", "ping", "po", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen", "seng", "sha", "shai", "shan", "shang", "shao", "she", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", "zhe", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo"}; private StringBuilder buffer; private String resource; private static CharacterParser characterParser = new CharacterParser(); public static CharacterParser getInstance() { return characterParser; } public String getResource() { return resource; } public void setResource(String resource) { this.

Typecho to Hugo |

这两天正式把博客从 typecho 转到 hugo 了。更准确的说应该是从动态博客转到了静态博客。 以前我是很抵制静态博客的。主要是感觉: 更新麻烦(现在仍然是这种感觉) 放在 github pages 上访问速度也不快,为了加速还需要套个 CDN。(同样是花钱,打折期间买个国内云服务器,速度不慢,还能干其他的) 配置真的很麻烦 这次换到 hugo 的起因是一个域名要备案,博客所在的域名要关闭评论系统,备案完后,打开评论发现,只要有评论的文章就卡死,然后 502。懒得折腾,直接关闭评论功能,发现关了后台也会卡死。索性转移到了 Hugo Hugo 如何安装配置网上很多这里不再赘述,主要说一下我是如何转换的。 部署在哪里 本来打算部署在腾讯对象存储 COS 上的,不过最后还是放弃了。 域名备案,内容审查。 不方便自动化处理,虽然通过github action + 云函数 + hook 可以做到更新仓库后自动构建,下载到 COS 但还是略显麻烦。需要配置好几个地方。 最终选择了部署在 在文章前面可以加很多参数的比如 --- title: "Typecho to Hugo" slug: "typecho-to-hugo" date: 2022-03-11T10:49:59+08:00 categories: [岁月如歌] tags: [Typecho,Hugo] showToc: true TocOpen: true draft: false # description: "Desc Text.

我问佛 |

我问佛:为何不给所有女子羞花闭月的容颜? 佛曰:那只是昙花的一现,用来蒙蔽世俗的眼,没有什么美可以抵过一颗纯净仁爱的心,我把它赐给每一个女子,可有人让它蒙上了灰。 我问佛:世间为何有那么多遗憾? 佛曰:这是一个婆娑世界,婆娑即遗憾,没有遗憾,给你再多幸福也不会体会快乐。 我问佛:如何让人们的心不再感到孤单? 佛曰:每一颗心生来就是孤单而残缺的,多数带着这种残缺度过一生,只因与能使它圆满的另一半相遇时,不是疏忽错过,就是已失去了拥有它的资格。

禁止ScrollView的childview自动滑动到底部 |

问题描述: 一个ScrollView中包含了好几个childView,有一个childview很大,一个屏幕显示不完,每个childview都能获取focus。当那个很大的chilvView获取焦点时,由于一屏显示不完,它就会自动滑动到最后(就是该childView的底部)。 问题原因以及解决方案分析: 由于该childView超过屏幕大小,并且有获取焦点的能力,所以造成了该问题。由于不能改变其大小,只能阻止其获取焦点。基本思路有,取消它获取焦点的能力,让ScrovView截获它的焦点等。以下是具体方法: 方法一:简单,方便,快捷,直面关键问题 将可能自动滑动的childview的focus禁掉,防止它自动滑动 mContentTextBox.setFocusable(false); 恢复默认状态,允许childview的focus,使它可以自动滑动 mContentTextBox.setFocusableInTouchMode(true); mContentTextBox.setFocusable(true); 这里要注意,仅仅setFocusable为true是不够的,需要设置setFocusableInTouchMode。 方法二: 绕了一点,副作用不大(推荐) 让ScrollView优先获取focus,这样childview获取不到focus,就不会滑动 private void disableAutoScrollToBottom() { mScrollView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); mScrollView.setFocusable(true); mScrollView.setFocusableInTouchMode(true); mScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { v.requestFocusFromTouch(); return false; } }); } 恢复默认状态,禁掉scrollview的focus,这样就允许childview自动滑动 private void enableChildAutoScrollToBottom() { mScrollView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mScrollView.setFocusable(false); mScrollView.setFocusableInTouchMode(false); mScrollView.setOnTouchListener(null); } 方法三:这个方法比较死板,不太灵活,虽然能满足基本需求,副作用很大 @Override protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { return true; } 方法四:和方法三类似 @Override protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) { return 0; }

Flutter和原生Android控件对比 |

Flutter和原生Android控件对比: Flutter控件 Android控件 AppBar ActionBar/ToolBar ListView ListView/RecyclerView Text TextView Center ViewGroup FloatingActionButton FloatingActionButton(design库里面的) BottomNavigationBar BottomNavigation(design库里面的) RaisedButton/Button Button Column LinearLayout的android:orientation=“vertical” Row android:orientation=“horizontal” DecorationImage ImageView Image ImageView Stack FrameLayout/RelativeLayout Container RelativeLayout CustomMultiChildLayout RelativeLayout Algin alginParentXXX属性 resizeToAvoidBottomPadding android:windowSoftInputMode=”adjustResize属性 SingleChildScrollView ScrollView CustomScrollerView Recyclerview Image里面的BoxFit参数介绍:(相当于Android的ImageView的scaleType参数)

Flutter 基础 | Dart 语法 mixin |

假设有这样一种场景:小明和小方都是程序员。其中小方会跳舞,当然它们都会编程。 用面向对象的方法可以建模如下: 因为小明和小方都会写编程,为了复用这个行为,提取了超类 Programmer,它包含所有程序员共用的行为 code()。这样一来,Ming 和 Fang 就能复用编程行为,而不是各自重新实现一遍相同的逻辑。(继承复用了行为) 小慧是一个舞者,再用面向对象的方法建模如下: 这样的继承关系违反了 DRY 原则,即 Don’t repeat yourself. 因为小慧并未复用小方的跳舞行为,所以同样的跳舞逻辑出现了两次。 那把跳舞行为上提到它们公共的基类 Human 中,是不是就解决问题了?的确,但这不是强迫所有程序员都必须会跳舞吗。。。 那让小方同时继承 Programmer 和 Dancer 能解决问题吗?能!但多重继承容易出事情,比如 “Diamond Problem”: 假设 Human 类中有 eat() 方法,且 Programmer 和 Dancer 都重写了它,此时 Fang 会发生编译报错。因为它不知道自己的 eat() 方法该采用哪一个父类的实现。上面的类图就好像一个钻石的形状,所以称为Diamond problem。 Dart 禁用了多重继承,而是引入了mixin来解决这个问题。 mixin 是一个特殊的类,它的属性和行为可以被其他类复用,而且不需要通过继承。 语法 如果希望一组属性和行为能够复用于多个类,碰巧这些类不在一条继承链路上,此时就应该使用mixin: mixin DanceMixin { void dance() {} } 这是声明 mixin 的方式,几乎和声明 class 一模一样,就是把 class 换成 mixin 而已。 还可以通过 on 限定 mixin 适用范围:

博客寄语:

    从14年开始写博客,到现在再有2年就10年了。

实时播报:

博客号-学习成长

相信每一分耕耘都有每一分收获,致力帮助博客主所创作的博客能更快的被收录! 如果有其它需求,可联系下方邮箱。