Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
好记性不如烂笔头,今天来分析一下Handler的源码实现 Handler机制是Android系统的基础,是多线程之间切换的基础。下面我们分析一下Handler的源码实现。 Handler消息机制有4个类合作完成,分别是Handler,MessageQueue,Looper,Message Handler : 获取消息,发送消息,以及处理消息的类 MessageQueue:消息队列,先进先出 Looper : 消息的循环和分发 Message : 消息实体类,分发消息和处理消息的就是这个类 主要工作原理就是: Looper 类里面有一个无限循环,不停的从MessageQueue队列中取出消息,然后把消息分发给Handler进行处理 先看看在子线程中发消息,去在主线程中更新,我们就在主线程中打印一句话。 第一步: 在MainActivity中有一个属性uiHandler,如下: Handler uiHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(msg.what == 100){ Log.d("TAG","我是线程1 msg.what=" + msg.what + "…
Groovy对文件的操作 对文件的遍历 假设文件的原始内容为: hello,world 这里是北京 andorid and ios are good system 第一种方法:使用 eachLine() new 一个File def file = new File(filepath) groovy对文件的遍历 file.eachLine { //打印每一行内容 line -> println line } //输出 hello,world 这里是北京 andorid and ios are good system…
WorkManager 是一个 Android Jetpack 扩展库,它可以让您轻松规划那些可延后、异步但又需要可靠运行的任务。对于绝大部分后台执行任务来说,使用 WorkManager 是目前 Android 平台上的最佳实践。 WorkManager Android Jetpack 在这篇文章中,我们将讨论: 在 Kotlin 中如何使用 WorkManager CoroutineWorker 类 如何使用 TestListenableWorkerBuilder 测试您的CoroutineWorker 类 CoroutineWorker TestListenableWorkerBuilder Kotlin 版的 WorkManager 本文的示例代码是用 Kotlin 编写的并使用了 KTX 库 (Kotlin Extensions)。KTX 版的…
gradle脚本是基于groovy语言开发的,想要学好gradle必须先要对groovy有一个基本的认识 1. Groovy特点 groovy是一种DSL语言,所谓的DSL语言,就是专门针对某一特定领域的语言,专精而不专广 是一种基于JVM的开发语言,也是编译成class字节码文件 结合和Python,Ruby,PHP等语言的特性,写脚本非常强大 Groovy可以与Java完美结合,而且可以使用Java所有的类库 语法上支持动态类型,闭包等新语言的特性 支持面向过程和面向对象编程 2. Groovy语法精讲 1 变量的类型和定义 -变量的类型分两种 基本类型:和java的基本类型一样,int,long,double,float,boolean,byte,String等 注意Groovy中,这些基本类型实际上都会被系统装箱为对应的对象类型,比如int就会被自动装箱为Integer 对象类型:和Java的一样 – 变量的定义 强类型定义:如 int a=10 ,指定变量的类型 弱类型定义:如 def b = 5,系统根据后面的值自动判断b是什么类型 – Groovy语法小点 语句后面可以不带分号,也可以带分号,如定义一个变量 int a = 10 输出一句话,直接println就行了,圆括号也可以省略,如 println "hello,world" 定义变量或者函数可以使用关键字def ,也可以按照Java的语法格式定义,如def…
1 Gradle的Task详解 1 Task定义和配置 2 Task的执行 3 Task的依赖和执行顺序 4 Task类型 5 Task结合gradle的生命周期 6 Task实战 1.1 Task定义和配置 1.1.1 查看所有的task ./gradlew tasks 输出 > Task :tasks ———————————————————— All tasks runnable from root project ———————————————————— Android tasks ————- androidDependencies – Displays the Android…
前言 由于近期项目中要用到插件,所以特地去翻找资料学习了一番,现在在这里分享我所学到的东西给大家,有什么错误的希望能给我指出来,文章有点长,希望大家能认真读完。 近些年来,插件化可谓是特别的火热,就拿支付宝美团等软件来说,都是使用这个技术来支撑他们的产品。但是什么是插件化呢,插件化到底有什么好处呢? 插件化也就是运行的APP(宿主APP)去加载插件APP(没有安装的APP),这就是所谓的插件化开发。 插件化到底运行在什么场景下呢?其实插件化使用的场景有很多,这里就比如下图的支付宝或者美团等APP,点击某个相应的item,就会跳转到相应的页面当中,其实这个页面是插件apk中的页面,但是它到底怎么做到的呢?怎么做到不安装apk而加载插件中的页面呢? 下面我们就来探索探索不用安装插件apk是怎么去加载里面的Activity、Service、BroadCastReceiver等这些组件的。本篇文章所提的是占位式(插桩式)插件化。 由于插件apk是没有安装的,也就是插件apk没有组件的一些环境,比如context上下文对象之类的,如果要用到这些环境就必须依赖宿主的环境运行。所以我们就要宿主跟插件之间定义一个标准。用来传递宿主中的环境给插件。 加载插件中的Activity 第一步: 首先我们先定义一个标准,让插件实现我们的标准来传递宿主APP的环境,下图是定义Activity类的标准,下面我们从加载插件中的Activity开始讲起。 首先我们要在插件中实现刚才我们定义的标准,由于插件都需要宿主APP的环境,所以我们就定义一个基类来实现该标准,然后让我们的插件的Activity来继承该基类,该Activity就具有了宿主的环境了。如图所示。 第二步: build工程,得到插件apk,命名为 plugin.apk 并把它放到我们的sd目录下。让宿主APP来加载插件。 首先我们要加载插件apk中的类,就需要用到DexClassLoader这个类,下面是用该类来加载插件apk的方法。 File file = new File(path); File pluginDir = context.getDir("plugin", Context.MODE_PRIVATE); //加载插件的class dexClassLoader = new DexClassLoader(path, pluginDir.getAbsolutePath(), null, context.getClassLoader()); 参数说明: path:插件所存放的目录(plugin.apk存放的目录) pluginDir.getAbsolutePath():插件apk解析后dex文件所存放的路径 null:该参数是so库存放的路径,由于插件里没有so库,所以为null。 context.getClassLoader():类加载器 获取到了DexClassLoader的对象,我们就可以拿到插件中的类了,接下来我们要获取插件apk中的资源对象,也就是…
译文的GitHub地址:RecyclerView之ItemDecoration由浅入深 译者注:RecyclerView第一篇,希望后面坚持下来 RecyclerView没有像之前ListView提供divider属性,而是提供了方法 recyclerView.addItemDecoration() 其中ItemDecoration需要我们自己去定制重写,一开始可能有人会觉得麻烦不好用,最后你会发现这种可插拔设计不仅好用,而且功能强大。 ItemDecoration类主要是三个方法: public void onDraw(Canvas c, RecyclerView parent, State state) public void onDrawOver(Canvas c, RecyclerView parent, State state) public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) 官方源码虽然都写的很清楚,但还不少小伙伴不知道怎么理解,怎么用或用哪个方法,下面我画个简单的图来帮你们理解一下。 ItemDecoration 图画的丑请见谅,首先我们假设绿色区域代表的是我们的内容,红色区域代表我们自己绘制的装饰,可以看到: 图1:代表了getItemOffsets(),可以实现类似padding的效果 图2:代表了onDraw(),可以实现类似绘制背景的效果,内容在上面 图3:代表了onDrawOver(),可以绘制在内容的上面,覆盖内容 注意上面是我个人从应用角度的看法,事实上实现上面的效果可能三个方法每个方法都可以实现。只不过这种方法更好理解。 下面是我们没有添加任何ItemDecoration的界面…
免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作! 注:本教程由北方和我本人合作翻译。 教程截图: 当我检查其他开发人员的代码时,似乎最常见的错误总是围绕在以Object-C中的内存管理为中心。如果您使用的语言是java或C#,它们会自动为您处理内存管理,但这也会使你对于手工内存管理工作更加迷惑。因此,在本教程中,您将通过一些实践来学习Object-C中的内存管理是如何工作的。我们将讨论引用计数如何工作,并通过学习内存管理的所有关键点来构建一个真实世界的例子——一个关于您喜爱的寿司类型的应用程序。 本教程是针对初学者的iOS开发人员或者时关注这个主题的中级开发人员。废话就少啰嗦了,开始编码。 开始 在xcode开发环境中,打开FileNew Project,选择iOSApplicationNavigation-based Application,并将新项目命名为ProMemFun,执行BuildBuild and Run, 在模拟器中你会看到一个如下空表视图: 比方说,我们希望在这个列表中填入我们喜爱的寿司类型。最简单的方法是创建一个数组来容下每一种寿司类型的字符串名称,然后每次我们显示一行,从数组中放入合适的字符串到表格中。在rootViewController.h中为寿司类型声明一个实例变量,代码如下: #import <UIKit/UIKit.h> @interface RootViewController : UITableViewController { NSArray * _sushiTypes; } @end 通过这个声明,每个RootViewController实例对象将有空间来存储一个指向NSArray数组的指针,这是一个Object-C类,使用这个数组初始化后就不能改变它。如果你需要更改一个初始化后的数组(例如,添加一项后),你应该使用NSMutableArray替代。 也许你会奇怪,为什么我们在命名的变量前面添加一个下划线?这恰好是我喜欢做的事情,这样做有些事情会变得更容易。在后续的关于Objec-C教程中我将讨论我为什么喜欢这么做,但是现在请注意,到目前为止,我们所作的是仅仅添加了一个实例变量,没有做与属性相关的东东,我们把它命名为“以下划线开头”,这只是一个个人的喜好问题,其实它没有做特别的东西。 现在,打开RootViewController.m文件,注释viewDiaLoad,然后设置以下代码: – (void)viewDidLoad { [super viewDidLoad]; _sushiTypes = [[NSArray alloc] initWithObjects:@"California Roll", @"Tuna Roll", @"Salmon Roll", @"Unagi…
1、简述 有段时间没写博客了,写博客的习惯还是应该保持的。 写在前面,要很好的理解SP的工作机制,请一定要先看QueuedWork介绍文章,先了解QueuedWork的工作机制。 本片博客主要是对Android的一个常用组件SharedPreferences(以下简称SP)进行分析,首先分析SP日常使用步骤中,每一步的源码,看看后面发生了什么,然后对SP存在的问题进行分析和寻找解决。 首先提几个问题,如果都能给出答案的同学就可以不用看了,如果还有不知道的,看了文章之后能找出答案并会有所收获。 问题: SP是什么时候读取磁盘的数据?是打开APP的时候还是第一次使用SP的时候?从磁盘读取数据是一次全部xml文件的数据都读出来还是只读当前SP操作的xml。 对于当前SP操作的xml,每次commit/apply提交数据,只是将修改的数据写到磁盘还是将所有的都要写到磁盘。 我们提交的数据有可能还未保存,程序就退出,导致数据丢失吗? SP为什么会有可能造成 “卡顿” 呢?使用apply()的方式修改数据就不会卡顿了吗? 假设一个场景:对于当前SP操作的xml,先使用commit提交一个需要耗时10ms的任务,记为任务1,立即再使用apply提交一个需要耗时5ms的任务,记为任务2。那么任务2一定会在任务1前执行完的结论,对不对? 接下来我们就带着问题,开始源码的分析。 对于SP,我们一般是按如下步骤使用的: //获得SP SharedPreferences sp = getSharedPreferences("test", Context.MODE_PRIVATE); //获得Editor SharedPreferences.Editor editor = sp.edit(); //设置数据 editor.putString("key", "value"); //提交 editor.commit(); //or editor.apply(); 接下来会分析每一步的源码。 在分析源码之前,先看看类的组织关系: public interface SharedPreferences { //监听SP的改变…
本文将会通过具体的业务场景,由浅入深的引出Kotlin的一个bug,并告知大家这个bug的神奇之处,接着会带领大家去查找bug出现的原因,最后去规避这个bug。 现实开发中,我们经常会有将Json字符串反序列化为一个对象问题,这里,我们用Gson来写一段反序列代码,如下: fun <T> fromJson(json: String, clazz: Class<T>): T? { return try { Gson().fromJson(json, clazz) } catch (ignore: Exception) { null } } 以上代码,仅适用于不带泛型的类,对于带泛型的类,如List<T>,我们就要再改造一下,如下: fun <T> fromJson(json: String, type: Type): T? { return try { return Gson().fromJson(json, type) } catch…