自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(49)
  • 资源 (17)
  • 收藏
  • 关注

原创 Android统计方法耗时之:内存控制

原因调查因为每个方法都被插桩, 所以每个方法的前后调用关系都做成MethodNode被存到了堆栈中,所以随着使用时间的增长, 所有方法关系都存进了堆栈中, 不被清理, 就撑爆了内存.设计方案这个问题实际上是个OOM问题. OOM从技术角度看, 是因为改释放的内存不被释放.但是要解决OOM问题, 却需要从具体业务入手, 因为只有通过业务关系梳理, 才知道那些内存应该释放.针对这次的问题, 就是要减少方法关系的存储.所以做如下设计:过滤掉重复的方法调用关系MethodNode. 只保存精简方法关

2020-08-31 21:08:41 663

原创 掌握 binder 机制?别想绕开 binder 驱动源码分析!

作者:Android面试官binder 是 Android 系统的进程间通信机制,是了解 Android 运行机制必须要掌握的一个知识点,更是一线企业面试必问的知识点!比如:binder 有什么优势?(字节)binder 一次拷贝原理?(腾讯)Intent 传递大数据限制?(阿里)AIDL 原理?(字节)谈谈你对 binder 驱动的了解?(字节)你都能回答上来吗!?到底怎样才能彻底掌握 binder 机制、游刃有余的应对 binder 面试问题,让面试官对你刮目相看,斩获高薪 .

2020-08-31 20:35:26 386

原创 Android岗高频面试题二集,看你能答出几题?(含答案)

Android设计模式面试题1、你所知道的设计模式有哪些?参考回答:创建型模式,共五种: 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种: 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式,共十一种: 策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录 模式、状态模式、访问者模式、中介者模式、解释器模式。2、谈谈 MVC、MVP 和 MVVM,好在哪里,不好在哪里 ?3、封装 p 层之后.如果 p

2020-08-30 22:31:42 514

原创 互联网公司(Android岗)高频面试题一集,看你能答出几题?

前言面试季黄金时期来袭,想必许多朋友在这时有找工作、换工作、跳槽涨薪等想法,但你们都有一个相同的过程那就是面试。大家肯定想知道面试时都问那些面试相关问题,所以就去网上查找题去刷题,为了省去大家找题的时间,小编特此整理在下方。面试题Java 基础高频面试题1、java 中==和 equals 和 hashCode 的区别?2、int 与 integer 的区别?3、谈谈对 java 多态的理解?4、String、StringBuffer、StringBuilder 区别?5、什么是内部类?内

2020-08-30 22:25:51 526

原创 我们各自来谈一谈艰辛的面试之旅吧!!!

作者:小帅特么笔试/面试机会也不给?记得去年的这个时候,小编基本每天都在做各大公司的笔试题,很多笔试题,是真的难,为此我也写了一篇文章:含泪狂刷Android面试100题,面试时吊打面试官????有些人,手里已经好几个 offer 了,而有些人,笔试受挫,面试受挫,自己明明复习了那么久,学习了那么多,特么在笔试就被刷了,有些甚至连笔试都不给,好不容易进入面试环节,自己明明每个问题都回答出来了,但一查状态,才发现自己进了人才库…有人可能忍不住会问,双非本科还有机会拿到大厂 offer

2020-08-27 22:06:29 455

原创 【性能优化】内存泄漏知多少

其中内存泄漏产生的原因在Android中大致分为以下几种: 单例(由于单例是全局的,生命周期跟app一样长,如static成员引用activity) 静态变量(静态集合对象强引用没有清理) 匿名内部类/非静态内部类(由于内部类会持有外部类的引用,解决方法是改成静态内部类和使用弱引用) 资源未关闭(cursor,file,bitmap) 接收器或监听器注册没有取消(broadcastReceiver,eventbus) handler 由于在Handle

2020-08-27 22:02:21 275

转载 Android |《看完不忘系列》之Retrofit

预备Retrofit使得网络调用可以像RESTful设计风格一样简洁,如:interfaceWanApi{//用注解标记网络请求方式get、post,参数path、query等@GET("article/list/{page}/json")Call<WanArticleBean>articleList(@Path("page")intpage);}又如,后端的Spring Boot框架通过约定大于配置思想省去了很多配置,其在网络接口Res...

2020-08-27 21:52:38 231

原创 Android岗常见40道面试题,面试前必须了解的知识点!!!

Android常见原理性面试专题1. Handler机制和底层实现2.Handler、Thread和HandlerThread的差别1) Handler线程的消息通讯的桥梁,主要用来发送消息及处理消息。2) Thread普通线程,如果需要有自己的消息队列,需要调用Looper.prepare()创建Looper实例,调用loop()去循环消息。3) HandlerThread是一个带有Looper的线程,在HandleThread的run()方法中调用了Looper.prepare()创

2020-08-25 22:24:42 340

原创 含泪狂刷Android面试100题,面试时吊打面试官

每日一分享,阅读十分钟,和您一起学习????Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。这里会不断收集和更新Android基础相关的面试题,目前已收集100题。1.Android系统的架构应用程序Android会同一系列核心应用程序包一起发布,该应用程序包包括Email客户端,SMS短消息程序,日历,地图,浏览器,联系人管理程序等。所有的应用程序都是使用JAVA语言编写的。应用程序框架开发

2020-08-24 22:02:43 8267

原创 Android敏感数据泄露引发的思考

1.事件始末一个平淡的午后,我还悠哉悠哉的敲着代码品着茶。突然服务端同事告诉我,关注接口正在被机械式调用,怀疑是有人在使用脚本刷接口(目的主要是从平台导流)。纳尼?不会吧,因为据我所知接口请求是做了加密处理的,除非知道加密的密钥和加密方式,不然是不会调用成功的,一定是你感觉错了。然而当服务端同事把接口调用日志发给我看时,彻底否定了我的侥幸心理。接口调用频率固定为1s 一次 被关注者的id每次调用依次加一(目前业务上用户id的生成是按照注册时间依次递增的) 加密的密钥始终使用固定的一个(正常的是

2020-08-21 22:02:45 428

原创 字节跳动提前批Android客户端(四面+HR面),最终Offer等到手,我也太难了吧

前言今年的金三银四来得比以往要晚一些,导致有些想换工作和找工作的人错过时机,但这次的“金九银十”的季节快到了,希望大家不要在错过这次机会了。 每年一到面试季的时候,总人很多人去寻找名叫“面经”一样的东西,其实就是一个个具体的题目,然后临阵磨枪,去“背”答案,如果一直是这样的话,我相信你的能力不会有任何提高,即使工作三年五年也达不到高级工程师的水平,事实证明这类“程序员”占大多数。而且我认为一个“面经”...

2020-08-21 21:31:46 728 2

原创 Android AutoService 组件化

1.前言 随着 App 的业务增加、版本迭代以及冗余的 “远古时期” 代码,App 代码变得臃肿增量叠加、开发者需要了解各个功能、单测功能编译时长、没有统一快速开发框架,代码复用性低,组件化开发就很有必要。2.组件化架构 1).组件化架构的思想 组件化开发框架可以细化为不同的部分,包括 Android UI、网络请求、数据库持久化、图片处理、View、工具类、sdk、内部统一风格组件等;框架包括但不限于通用功能,如果是部门内部项目中通用的功能,也可以独立出来成为一个通...

2020-08-21 21:01:57 2711 2

原创 互联网公司不招35岁以上程序员的真相

今天在知乎上看到一个问题,说:为什么很多公司都不招大龄码农?“本人 36,最近联系猎头找个工作,猎头说只能找技术管理类的了,纯开发的一般公司 32 岁的就不招了。” 一位36岁被裁的甲骨文员工在事后接受采访时说到:"裁员期间,很多企业前来摆摊招聘,但那些写在牌子上的岗位要求,看起来有点刺眼:32岁或35岁以下。有同事专门建了一个离职群,里面都是35岁以上的同事。目前这个群里有226人,绝大部分人的下一份工作还没有落定。"在我们的印象里...

2020-08-19 22:04:22 2521

原创 网易云面试(Android岗)之旅,差点被这些基础题绊了跟头。

作者:黑凤梨本人是二本渣院毕业,从事Android开发4年了,之前在一家小型公司上班。离职的原因是因为天天加班,工资少,没有什么提升空间。所以想找一家工资高,对自己有提升的大公司。在网上找工作的时候,正好看见网易正在招人,于是大胆的尝试一下就投了简历,没想到过了几天接到电话通知我去面试。为这次面试,我准备的是 算法,框架源码,framework源码等一些资料复习,准备装一波逼。 emmmmm…后来发现没用。根本就没问。简历都没怎么问,项目也没问。问的大多是基础,被虐的很惨。也不知道网易到底看.

2020-08-18 22:38:50 787 3

原创 Android开发:从创业小公司跳槽进阿里,需要做到什么?

听上去好像挺厉害,挺光鲜,但是实际上并不那么容易,在这背后有很多我自己摸索和努力的故事。在这里我想分享一些我的经验,送给那些跟我一样,没名校背景没大厂背景,但是想进阿里(或其他大厂),又有点迷茫不知该如何前进的人。其实在进阿里之前,我也挺迷茫,内心有一些谜团一直困扰着我,比如阿里招人标准是什么?,自己距离这个标准有多少差距?那时候一直不知道,就好像置身于沙漠之中,却不知道往哪里走。这时候,找到方向最为关键。(很多人跟我那时候一样迷茫,因为不少人问过我,到底怎么样才能加入阿里。)当时我问了几个在

2020-08-17 22:34:12 400

原创 Android技术背后涉及到了多少知识点?

我们开发时常常要考虑的一些问题。开发上线的版本能保证不存在Bug么? 修复后的版本能保证用户都及时更新么? 如何最大化减少线上Bug对业务的影响?热修复技术帮助我们解决了很多问题,带来的优势不言而喻。不知道各位对于热修复技术掌握如何?热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷。本文将从以下方面为大家详解热修复技术:什么是热修复?热修复的优势和不足?热修复框架分类技术原理及特点实际案例解析热修复技术选择

2020-08-17 22:30:52 528

原创 Android前景怎么样、是不是要凉了、是不是应该考虑要转行?看完你就知道

作者:googdev最近在知乎上,有许多人在邀请我去回答“Android前景怎么样、是不是要凉了、是不是应该考虑要转行?”等一系列的问题。想着可能有很多人都有这样的担心,于是就赶紧写篇文章,来跟你们谈下Android开发的前景到底怎么样?1.我们先来说说编程语言众所周知,Android 开发是基于 Java 编程语言的,而 Java 作为老牌成熟的编程语言,虽然经常被人诟病,但是毫无疑问,Java是目前市场上最成熟、应用最广泛的编程语言,很多成熟的业务系统 Java 都是第一选择,每月的 TIO.

2020-08-14 22:42:53 1234

原创 你觉得Android又凉了?那带你看下2020年Android开发的前景如何?

不管在任何行业,任何岗位,初级技术人才总是供大于求,都是不好找工作的,Android开发只是其中之一同样,不管任何行业、岗位,技术过硬的也都是非常吃香的!说到底,是Android凉了吗?其实只是你凉了!技术不过硬,就算转去Java、大数据、人工智能,还是会问出类似的问题:“Java凉了?Java前景如何?”“大数据凉了?大数据前景如何?”“人工智能凉了?人工智能前景如何?”……身边有很多同学都会问到:1、Android开发如何啊?2、感觉前景不太乐观啊?3、现在人工智

2020-08-14 16:31:01 1204

原创 Android自定义控件进阶14-特殊控件的事件处理方案

本文带大家了解 Android 特殊形状控件的事件处理方式,主要是利用了 Region 和 Matrix 的一些方法,超级实用的事件处理方案,相信看完本篇之后,任何奇葩控件的事件处理都会变得十分简单。不得不说,Android 对事件体系封装的非常棒,即便对事件体系不太了解的人,只要简单的调用方法就能使用,而且具有防呆设计,能够保证事件流的完整性和统一性,最大可能性的避免了事件处理的混乱,着实令人佩服。然而世界上并没有绝对完美的东西,当”事件处理”遇上”自定义View”,一场好戏就开演了。特殊形状控件

2020-08-12 14:50:24 457

原创 Android自定义控件进阶13-MotionEvent详解

Android MotionEvent 详解,之前用了两篇文章 事件分发机制原理 和 事件分发机制详解 来讲解事件分发,而作为事件分发主角之一的 MotionEvent 并没有过多的说明,本文就带大家了解 MotionEvent 的相关内容,简要介绍触摸事件,主要包括 单点触控、多点触控、鼠标事件 以及 getAction() 和 getActionMasked() 的区别。Android 将所有的输入事件都放在了 MotionEvent 中,随着安卓的不断发展壮大,MotionEvent 也开始变得越来

2020-08-12 14:48:54 637

原创 Android自定义控件进阶12-事件分发机制原理

Android 事件分发机制详解,在上一篇文章 事件分发机制原理 中简要分析了一下事件分发机制的原理,原理是十分简单的,一句话就能总结:责任链模式,事件层层传递,直到被消费。 虽然原理简单,但是随着 Android 不断的发展,实际运用场景也越来越复杂,所以想要彻底玩转事件分发机制还需要一定技巧,本篇事件分发机制详解将带大家了解 …你以为我接下来要讲源码?我就不按套路,所有的源码都是为了适应具体的应用场景而写的,只要能够理解运用场景,理解源码也就十分简单了。所以本篇的核心问题是:正确理解在实际场景中事

2020-08-12 14:43:13 360

原创 Android自定义控件进阶11-事件分发机制原理01

之前讲解了很多与View绘图相关的知识, 那么至少2D绘图部分不是难题了,大部分的需求都能满足,但是关于View还有很多知识点,例如: 让绘图更加炫酷的Paint,让View动起来的动画,与用户交互的触控事件 等一系列内容。本次就带大家简单的了解一下与交互息息相关的东西-事件分发原理。本次魔法小火车的终点站是事件分发,请各位魔法师带好装备,准备登车启程。注意:本文中所有源码分析部分均基于 API23(Android 6.0) 版本,由于安卓系统源码改变很多,可能与之前版本有所不同,但基本流程都是一致

2020-08-12 14:42:31 416

原创 Android自定义控件进阶11-事件分发机制原理

之前讲解了很多与View绘图相关的知识, 那么至少2D绘图部分不是难题了,大部分的需求都能满足,但是关于View还有很多知识点,例如: 让绘图更加炫酷的Paint,让View动起来的动画,与用户交互的触控事件 等一系列内容。本次就带大家简单的了解一下与交互息息相关的东西-事件分发原理。本次魔法小火车的终点站是事件分发,请各位魔法师带好装备,准备登车启程。注意:本文中所有源码分析部分均基于 API23(Android 6.0) 版本,由于安卓系统源码改变很多,可能与之前版本有所不同,但基本流程都是一致

2020-08-12 14:42:11 433

原创 Android自定义控件进阶10-控件核心Matrix Camera

本篇依旧属于Matrix,主要讲解Camera,Android下有很多相机应用,其中的美颜相机更是不少,不过今天这个Camera可不是我们平时拍照的那个相机,而是graphic包下的Camera,专业给View拍照的相机,不过既然是相机,作用都是类似的,主要是将3D的内容拍扁变成2D的内容。众所周知,我们的手机屏幕是一个2D的平面,所以也没办法直接显示3D的信息,因此我们看到的所有3D效果都是3D在2D平面的投影而已,而本文中的Camera主要作用就是这个,将3D信息转换为2D平面上的投影,实际上这个类更

2020-08-11 22:30:39 824

原创 Android自定义控件进阶09-控件核心Matrix原理

本篇的主角Matrix,是一个一直在后台默默工作的劳动模范,虽然我们所有看到View背后都有着Matrix的功劳,但我们却很少见到它,本篇我们就看看它是何方神圣吧。由于Google已经对这一部分已经做了很好的封装,所以跳过本部分对实际开发影响并不会太大,不想深究的粗略浏览即可,下一篇中将会详细讲解Matrix的具体用法和技巧。⚠️ 警告:测试本文章示例之前请关闭硬件加速。Matrix简介Matrix是一个矩阵,主要功能是坐标映射,数值转换。它看起来大概是下面这样:Matrix作用就是坐标映

2020-08-11 22:27:35 415

原创 Android自定义控件进阶08-PathMeasure详解

可以看到,在经过 Path之基本操作 Path之贝塞尔曲线 和 Path之完结篇 后, Path中各类方法基本上都讲完了,表格中还没有讲解到到方法就是矩阵变换了,难道本篇终于要讲矩阵了? 非也,矩阵这一部分仍在后面单独讲解,本篇主要讲解 PathMeasure 这个类与 Path 的一些使用技巧。PS:不要问我为什么不讲 PathEffect,因为这个方法在后面的Paint系列中。先放一个图镇楼,省的下面无聊的内容把你们都吓跑了Σ( ̄。 ̄ノ)ノPath & PathMeasure顾名

2020-08-11 22:24:35 310

原创 Android自定义控件进阶07-Path之完结篇

经历过前两篇 Path之基本操作 和 Path之贝塞尔曲线 的讲解,本篇终于进入Path的收尾篇,本篇结束后Path的大部分相关方法都已经讲解完了,但Path还有一些更有意思的玩法,应该会在后续的文章中出现。一.Path常用方法表为了兼容性(偷懒) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下,为啥看起来有些顺手就能写的重载方法要等到API21才添加上啊。宝宝此刻内心也是崩溃的。作用相关方法备注移动起点moveTo移动下一次操作的起

2020-08-11 22:18:18 406

原创 Android自定义控件进阶06-Path之贝塞尔曲线

一.Path常用方法表为了兼容性(偷懒) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下,为啥看起来有些顺手就能写的重载方法要等到API21才添加上啊。宝宝此刻内心也是崩溃的。作用相关方法备注移动起点moveTo移动下一次操作的起点位置设置终点setLastPoint重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同连接直线lineTo添加上一个点到当前点之间的直线到Path闭合路径clo

2020-08-11 22:15:36 477

原创 Android自定义控件进阶05-Path之基本操作

Android自定义控件进阶05-Path之基本操作在上一篇Canvas之图片文字中我们了解了如何使用Canvas中绘制图片文字,结合前几篇文章,Canvas的基本操作已经差不多完结了,然而Canvas不仅仅具有这些基本的操作,还可以更加炫酷,本次会了解到path(路径)这个Canvas中的神器,有了这个神器,就能创造出更多**炫(zhuang)酷(B)**的东东了。一.Path常用方法表为了兼容性(偷懒) 本表格中去除了部分API21(即安卓版本5.0)以上才添加的方法。作用相

2020-08-11 22:12:36 438

原创 Android自定义控件进阶04-Canvas之图片文字

Android自定义控件进阶04-Canvas之图片文字码牛学院用代码码出自己牛逼的人生在上一篇文章Canvas之画布操作中我们了解了画布的一些基本操作方法,本次了解一些绘制图片文字相关的内容。如果你对前几篇文章讲述的内容熟练掌握的话,那么恭喜你,本篇结束之后,大部分的自定义View已经难不倒你了,当然了,这并不是终点,接下来还会有更加炫酷的技能。一.Canvas的常用操作速查表操作类型相关API备注绘制颜色drawColor, drawRGB, drawARGB使用单

2020-08-11 22:09:28 518

原创 Android自定义控件进阶03-Canvas之画布操作

Android自定义控件进阶03-Canvas之画布操作本来想把画布操作放到后面部分的,但是发现很多图形绘制都离不开画布操作,于是先讲解一下画布的基本操作方法。一.Canvas的常用操作速查表操作类型相关API备注绘制颜色drawColor, drawRGB, drawARGB使用单一颜色填充整个画布绘制基本形状drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval,

2020-08-11 21:54:47 444

原创 Android自定义控件进阶02-Canvas之绘制图形

Android自定义控件进阶02-Canvas之绘制图形在上一篇自定义View分类与流程中我们了解自定义View相关的基本知识,不过,这些东西依旧还是理论,并不能拿来(zhuang)用(B), 这一次我们就了解一些能(zhaung)用(B)的东西。在本篇文章中,我们先了解Canvas的基本用法,最后用一个小示例来结束本次教程。一.Canvas简介Canvas我们可以称之为画布,能够在上面绘制各种东西,是安卓平台2D图形绘制的基础,非常强大。一般来说,比较基础的东西有两大特点:1.可操作性强

2020-08-11 21:53:07 1032

原创 Android自定义控件进阶01-自定义控件开发套路与流程

Android自定义控件进阶01-自定义控件开发套路与流程本章节为什么要叫进阶篇?(虽然讲的是基础内容),因为从本篇开始,将会逐渐揭开自定义View的神秘面纱,每一篇都将比上一篇内容更加深入,利用所学的知识能够制作更加炫酷自定义View,就像在台阶上一样,每一篇都更上一层,帮助大家一步步走向人生巅峰,出任CEO,迎娶白富美。 误,是帮助大家更加了解那些炫酷的自定义View是如何制作的,达到举一反三的效果。码牛学院用代码码出自己牛逼的人生自定义View绘制流程函数调用链(简化版)一.自定义V

2020-08-11 21:48:51 354

原创 Android开发之APP插件化实践

背景在Android开发行业里,插件化已经不是一门新鲜的技术了,在稍大的平台型App上早已是标配。Atlas、Replugin、VirtualAPK相继开源,标志着插件化技术进入了成熟阶段。但纵观各大插件框架,都是基于自身App的业务来开发的,目标或多或少都有区别,所以很难有一个插件框架能一统江湖解决所有问题。最后就是绕不开的兼容性问题,Android每次版本升级都会给各个插件化框架带来不少冲击,都要费劲心思适配一番,更别提国内各个厂商对在ROM上做的定制了,正如VirtualAPK的作者任玉刚所说:完成

2020-08-09 22:24:17 894

原创 是时候上车Jetpack了,内含音乐播放器实例

1. 背景之前公司项目用的一直是MVP框架,我个人也在几个月前基于鸿神 WanAndroid API开发了一款MVP版的App,使用MVP的过程最深的感受是开发效率极低,往往写一大堆接口,可复用的屈指可数。年初了解了Jetpack模式下的MVVM,在LiveData、ViewModel、DataBinDing的加持下实现了单向依赖和数据绑定,代码量大幅度减少,根据Jetpack的特性项目稳定性也提升了不少。为了更深入的理解Jetpack中各个组件,在前段时间基于Jetpack MVVM又实现了一版W

2020-08-09 22:13:43 379

转载 怎么解决引用计数 GC 的循环引用问题?

作者:Android面试官引用计数方式 GC 存在循环引用问题,导致无法辨别无用对象,而 GC ROOT 方式不存在循环引用的问题引用计数和 GC ROOT 的实现机理很易理解,面试时大家都能流利应答,那怎么才能脱颖而出呢?思考一个问题:不通过 GC ROOT,仍使用引用计数方式,怎么解决它的循环引用问题?解答此问题前,通过目标驱动法来想象一下,若 Get 了此知识点,可以这样应用到面试中:面试官: 说一下垃圾回收机制吧我: …可以通过强、弱引用计数结合方式解决引用计数的循环引用问题,实际上

2020-08-07 22:29:51 1043

原创 字节瞧不上老程序员?我很慌…

前段时间,字节的朋友有个新项目,要我推荐靠谱的朋友,然后我就推荐了一个88年的同事老贾。一面的时候,老贾各方面都挺好,问啥都会,后来聊到性能优化问题,答得也还行,至少勉强进了二面。可好巧不巧,二面的时候问了个内存回收机制与GC算法,然后他就答不上来了,据说走的时候几乎落泪...唉!后来跟字节的朋友聊起这件事,他告诉我其实老贾并不是个例,他提醒了我以后面试的几个点,在这里我也分享给大家: 当面试官向你问图片的三级缓存中,图片加载到内存中,如果内存快爆了,会发生什么?怎么处理?

2020-08-07 17:39:02 234

原创 一次线程OOM排查看线程使用注意事项

一、背景介绍在开发项目中发生了一次OOM问题,通过crash 平台查看上报信息,发现在很多的页面都有报这个错误,但是相同的出错都是以下的错误,看不到APP的堆栈只能看到是线程池创建有问题的堆栈信息,如下所示:java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again at java.lang.Thread.nativeCreate(Native Method) at java.lang.Th

2020-08-06 21:02:18 927

原创 从应用中的Binder谈起

一、前言要自顶向下的介绍Binder,那么我们需要先从日常开发中接触到的Binder组件说起,对于应用开发来说Binder的存在是透明的,我们可能在不经意间就通过Binder完成了一系列操作,接下来我将会介绍和应用开发和Binder关系最为紧密的部分,以次让读者对Binder的在系统中的存在有初步的认识和了解。二、Activity的启动Activity启动的时候是我第一个想到的使用Binder的场景,这是我们开发中最频繁使用的功能,接下来我们看看我潜入到Activity启动中看看Binder如何

2020-08-06 20:40:02 269

原创 通过字节码分析Java中自动装箱和拆箱是如何实现的

Java中自动装箱和拆箱装箱(Boxing),也称为包装(Wrapper),是在对象中放置原语类型(primitive type)的过程,以便原语(primitive)可以作为引用对象使用。这里的primitive type就是Java里面的基本类型,所有的基本类型都有一个与之对应的类。例如,Integer类对应基本类型int。通常,这些类称为包装器(wrapper)。这些对象包装器类拥有很明显的名字:Integer、Long、Float、Double、Short、Byte、Character、

2020-08-05 22:39:05 574 1

组件化通信之LiveData.rar

都说新项目组件通信一定用LiveData,我们就从源码层来聊聊LiveData的魅力 内容点: 1.LiveData到底是什么? 2.LiveData源码解读? 3.通过手写LiveData让大家了解更清晰 4.如何将LiveData封装得更加好用?

2020-12-18

resized_img.zip

手势识别图片,主要是训练神经网络图片。用tersorflow实现手势识别

2019-07-12

WangyiPush.zip

直播详解,可运行,通过rtmp协议实现,直播的详细说明可参考https://github.com/interviewandroid/AndroidInterView/blob/master/android/live.md 关于直播的视频讲解可以加qq 1051917835 免费的 哦

2019-06-22

RabbitMQ消息中间件技术精讲

RabbitMQ消息中间件技术精讲(渐进式,深入RabbitMQ高级特性,手把手,整合RabbitMQ&Spring;家族,高可靠,构建RabbitMQ集群架构,追前沿,领略SET化架构衍化与设计)

2019-02-24

MySQL原理分析与架构设计视频教程

MySQL原理分析与架构设计(数据库索引优化,数据库的分库分表, SQL查询优化,mysql行内锁原理)

2019-02-24

2019Java高级面试专题

2019Java高级面试专题包含(微服务+数据库原理+Java性能优化面试视频)

2019-02-24

rxjava 1.0.14

rxjavah和rxandroid下载

2016-11-23

eclipse svn插件

2016-08-12

jbox2d愤怒的小鸟游戏源码

jbox2d愤怒的小鸟游戏源码

2016-07-14

FreScon源码下载

FreScon源码下载

2016-06-30

sdk build-tool 19.1.0

build-tool 19.1.0 解压到sdk下面的build-tools目录就可以了

2016-01-07

Xcode6.4 beta2 下载

Xcode6.4 ios版 适合mac 10.10以下版本

2015-12-27

cdt插件下载

Eclipse 中CDT插件 将文件解压后 分别放到对应的eclipse目录中的features 和plugins文件夹中

2015-12-27

城市选择器

城市选择器,自动定位,城市列表自动按拼音排序

2015-10-21

可以拨动的时间选择器

直接可以运行。漂亮的时间选择空间 public class MainActivity extends FragmentActivity implements OnDateSetListener, TimePickerDialog.OnTimeSetListener { public static final String DATEPICKER_TAG = "datepicker"; public static final String TIMEPICKER_TAG = "timepicker"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Calendar calendar = Calendar.getInstance(); final DatePickerDialog datePickerDialog = DatePickerDialog.newInstance(this, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), isVibrate()); final TimePickerDialog timePickerDialog = TimePickerDialog.newInstance(this, calendar.get(Calendar.HOUR_OF_DAY) ,calendar.get(Calendar.MINUTE), false, false); findViewById(R.id.dateButton).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { datePickerDialog.setVibrate(isVibrate()); datePickerDialog.setYearRange(1985, 2028); datePickerDialog.setCloseOnSingleTapDay(isCloseOnSingleTapDay()); datePickerDialog.show(getSupportFragmentManager(), DATEPICKER_TAG); } }); findViewById(R.id.timeButton).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { timePickerDialog.setVibrate(isVibrate()); timePickerDialog.setCloseOnSingleTapMinute(isCloseOnSingleTapMinute()); timePickerDialog.show(getSupportFragmentManager(), TIMEPICKER_TAG); } }); if (savedInstanceState != null) { DatePickerDialog dpd = (DatePickerDialog) getSupportFragmentManager().findFragmentByTag(DATEPICKER_TAG); if (dpd != null) { dpd.setOnDateSetListener(this); } TimePickerDialog tpd = (TimePi

2015-10-21

annotations注解

android annotations注解 快速注解,findbyid

2015-10-21

仿QQ自定义ListView 下拉刷新

package me.maxwin; import java.util.ArrayList; import me.maxwin.view.XListView; import me.maxwin.view.XListView.IXListViewListener; import me.maxwin.view.XListView.RemoveListener; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; public class XListViewActivity extends Activity implements IXListViewListener ,RemoveListener,OnItemClickListener{ private XListView mListView; // private ArrayAdapter<String> mAdapter; private ItemAdapter adapter; // private Context context; private ArrayList<String> items = new ArrayList<String>(); private Handler mHandler; private int start = 0; private static int refreshCnt = 0; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); geneItems(); init(); mHandler = new Handler(); } private void init() { // TODO Auto-generated method stub mListView = (XListView) findViewById(R.id.xListView); mListView.setPullLoadEnable(true); mListView.setRemoveListener(this); mListView.setOnItemClickListener(this); // mListView.setPullLoadEnable(false); // mListView.setPullRefreshEnable(false); mListView.setXListViewListener(this); adapter=new ItemAdapter(this); adapter.setData(items); mListView.setAdapter(adapter); } private void geneItems() { for (int i = 0; i != 20; ++i) { items.add("refresh cnt " + (++start)); } } private void onLoad() { mListView.stopRefresh(); mListView.stopLoadMore(); mListView.setRefreshTime("刚刚"); } @Override public void onRefresh() { mHandler.postDelayed(new Runnable() { @Override public void run() { start = ++refreshCnt; items.clear(); geneItems(); // mAdapter.notifyDataSetChanged(); adapter=new ItemAdapter(XListViewActivity.this); adapter.setData(items); mListView.setAdapter(adapter); onLoad(); } }, 2000); } @Override public void onLoadMore() { mHandler.postDelayed(new Runnable() { @Override public void run() { geneItems(); adapter.notifyDataSetChanged(); onLoad(); } }, 2000); } @Override public void removeItem(int position) { // TODO Auto-generated method stub mListView.isSlide = false; mListView.itemView.findViewById(R.id.tv_coating).setVisibility(View.VISIBLE); items.remove(position); adapter.notifyDataSetChanged(); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub Intent intent = new Intent(getApplicationContext(), ItemActivity.class); intent.putExtra("item", items.get(position)); startActivity(intent); overridePendingTransition(R.anim.slide_in_from_right, R.anim.remain_original_location); } } 自定义LIstView * * @file XListView.java * @package me.maxwin.view * @create Mar 18, 2012 6:28:41 PM * @author Maxwin * @description An ListView support (a) Pull down to refresh, (b) Pull up to load more. * Implement IXListViewListener, and see stopRefresh() / stopLoadMore(). */ package me.maxwin.view; import me.maxwin.R; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.DecelerateInterpolator; import android.view.animation.ScaleAnimation; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Scroller; import android.widget.TextView; public class XListView extends ListView implements OnScrollListener { private float mLastY = -1; // save event y private Scroller mScroller; // used for scroll back private OnScrollListener mScrollListener; // user's scroll listener // the interface to trigger refresh and load more. private IXListViewListener mListViewListener; // -- header view private XListViewHeader mHeaderView; // header view content, use it to calculate the Header's height. And hide it // when disable pull refresh. private RelativeLayout mHeaderViewContent; private TextView mHeaderTimeView; private int mHeaderViewHeight; // header view's height private boolean mEnablePullRefresh = true; private boolean mPullRefreshing = false; // is refreashing. // -- footer view private XListViewFooter mFooterView; private boolean mEnablePullLoad; private boolean mPullLoading; private boolean mIsFooterReady = false; // total list items, used to detect is at the bottom of listview. private int mTotalItemCount; // for mScroller, scroll back from header or footer. private int mScrollBack; private final static int SCROLLBACK_HEADER = 0; private final static int SCROLLBACK_FOOTER = 1; private final static int SCROLL_DURATION = 400; // scroll back duration private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px // at bottom, trigger // load more. private final static float OFFSET_RADIO = 1.8f; // support iOS like pull // feature. private int slidePosition, preSlidePosition; private int downY; private int downX; public static View itemView, preItemView; // private Scroller scroller; private static final int SNAP_VELOCITY = 600; private VelocityTracker velocityTracker; public static boolean isSlide = false; private boolean isResponse = true; public static boolean isObstruct = true; private int mTouchSlop; private RemoveListener mRemoveListener; private static Animation scaleHideAnimation; private static Animation scaleShowAnimation; /** * @param context */ public XListView(Context context) { super(context); initWithContext(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } public XListView(Context context, AttributeSet attrs) { super(context, attrs); initWithContext(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } public XListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // mScroller = new Scroller(context, new DecelerateInterpolator()); initWithContext(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } private void initWithContext(Context context) { mScroller = new Scroller(context, new DecelerateInterpolator()); // XListView need the scroll event, and it will dispatch the event to // user's listener (as a proxy). super.setOnScrollListener(this); // init header view mHeaderView = new XListViewHeader(context); mHeaderViewContent = (RelativeLayout) mHeaderView .findViewById(R.id.xlistview_header_content); mHeaderTimeView = (TextView) mHeaderView .findViewById(R.id.xlistview_header_time); addHeaderView(mHeaderView); // init footer view mFooterView = new XListViewFooter(context); // init header height mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mHeaderViewHeight = mHeaderViewContent.getHeight(); getViewTreeObserver() .removeGlobalOnLayoutListener(this); } }); } @Override public void setAdapter(ListAdapter adapter) { // make sure XListViewFooter is the last footer view, and only add once. if (mIsFooterReady == false) { mIsFooterReady = true; addFooterView(mFooterView); } super.setAdapter(adapter); } /** * enable or disable pull down refresh feature. * * @param enable */ public void setPullRefreshEnable(boolean enable) { mEnablePullRefresh = enable; if (!mEnablePullRefresh) { // disable, hide the content mHeaderViewContent.setVisibility(View.INVISIBLE); } else { mHeaderViewContent.setVisibility(View.VISIBLE); } } /** * enable or disable pull up load more feature. * * @param enable */ public void setPullLoadEnable(boolean enable) { mEnablePullLoad = enable; if (!mEnablePullLoad) { mFooterView.hide(); mFooterView.setOnClickListener(null); } else { mPullLoading = false; mFooterView.show(); mFooterView.setState(XListViewFooter.STATE_NORMAL); // both "pull up" and "click" will invoke load more. mFooterView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startLoadMore(); } }); } } /** * stop refresh, reset header view. */ public void stopRefresh() { if (mPullRefreshing == true) { mPullRefreshing = false; resetHeaderHeight(); } } /** * stop load more, reset footer view. */ public void stopLoadMore() { if (mPullLoading == true) { mPullLoading = false; mFooterView.setState(XListViewFooter.STATE_NORMAL); } } /** * set last refresh time * * @param time */ public void setRefreshTime(String time) { mHeaderTimeView.setText(time); } private void invokeOnScrolling() { if (mScrollListener instanceof OnXScrollListener) { OnXScrollListener l = (OnXScrollListener) mScrollListener; l.onXScrolling(this); } } private void updateHeaderHeight(float delta) { mHeaderView.setVisiableHeight((int) delta + mHeaderView.getVisiableHeight()); if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态,更新箭头 if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) { mHeaderView.setState(XListViewHeader.STATE_READY); } else { mHeaderView.setState(XListViewHeader.STATE_NORMAL); } } setSelection(0); // scroll to top each time } /** * reset header view's height. */ private void resetHeaderHeight() { int height = mHeaderView.getVisiableHeight(); if (height == 0) // not visible. return; // refreshing and header isn't shown fully. do nothing. if (mPullRefreshing && height <= mHeaderViewHeight) { return; } int finalHeight = 0; // default: scroll back to dismiss header. // is refreshing, just scroll back to show all the header. if (mPullRefreshing && height > mHeaderViewHeight) { finalHeight = mHeaderViewHeight; } mScrollBack = SCROLLBACK_HEADER; mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION); // trigger computeScroll invalidate(); } private void updateFooterHeight(float delta) { int height = mFooterView.getBottomMargin() + (int) delta; if (mEnablePullLoad && !mPullLoading) { if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load // more. mFooterView.setState(XListViewFooter.STATE_READY); } else { mFooterView.setState(XListViewFooter.STATE_NORMAL); } } mFooterView.setBottomMargin(height); // setSelection(mTotalItemCount - 1); // scroll to bottom } private void resetFooterHeight() { int bottomMargin = mFooterView.getBottomMargin(); if (bottomMargin > 0) { mScrollBack = SCROLLBACK_FOOTER; mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION); invalidate(); } } private void startLoadMore() { mPullLoading = true; mFooterView.setState(XListViewFooter.STATE_LOADING); if (mListViewListener != null) { mListViewListener.onLoadMore(); } } //RemoveListener public void setRemoveListener(RemoveListener removeListener) { this.mRemoveListener = removeListener; } public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { Log.e("lg", "dispatchTouchEvent ACTION_DOWN isSlide1111 = " + isSlide); addVelocityTracker(event); downX = (int) event.getX(); downY = (int) event.getY(); slidePosition = pointToPosition(downX, downY); if (slidePosition == AdapterView.INVALID_POSITION) { return super.dispatchTouchEvent(event); } if (preItemView != null && preItemView.findViewById(R.id.tv_coating).getVisibility() == View.GONE) { itemView = preItemView; slidePosition = preSlidePosition; } else { itemView = getChildAt(slidePosition - getFirstVisiblePosition()); preItemView = itemView; preSlidePosition = slidePosition; } break; } case MotionEvent.ACTION_MOVE: { if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY || (Math.abs(event.getX() - downX) > mTouchSlop && Math.abs(event.getY() - downY) < mTouchSlop)) { isSlide = true; } break; } case MotionEvent.ACTION_UP: recycleVelocityTracker(); isObstruct = true; break; } return super.dispatchTouchEvent(event); } public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: if (itemView.findViewById(R.id.tv_coating).getVisibility() == View.VISIBLE) { isSlide = false; } else { isSlide = true; } break; default: break; } return super.onInterceptTouchEvent(ev); } //dispatchTouchEvent ACTION_DOWN isSlide // @Override dispatchTouchEvent public boolean onTouchEvent(MotionEvent ev) { if (isSlide && slidePosition != AdapterView.INVALID_POSITION) { addVelocityTracker(ev); final int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_MOVE: if (isObstruct) { if (itemView.findViewById(R.id.tv_coating).getVisibility() == View.VISIBLE && isResponse == true) { scaleHideAnimation = new ScaleAnimation(1.0f, 0.0f, 1.0f, 1.0f); scaleHideAnimation.setDuration(250); scaleHideAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { isResponse = false; isObstruct = false; } public void onAnimationRepeat(Animation animation) { } public void onAnimationEnd(Animation animation) { isResponse = true; itemView.findViewById(R.id.tv_coating).setVisibility(View.GONE); itemView.findViewById(R.id.tv_functions).setClickable(true); itemView.findViewById(R.id.tv_functions).setOnClickListener(new OnClickListener() { public void onClick(View v) { mRemoveListener.removeItem(slidePosition); } }); } }); itemView.findViewById(R.id.tv_coating).startAnimation(scaleHideAnimation); } else if (itemView.findViewById(R.id.tv_coating).getVisibility() == View.GONE && isResponse == true) { scaleShowAnimation = new ScaleAnimation(0.0f, 1.0f, 1.0f, 1.0f); scaleShowAnimation.setDuration(250); scaleShowAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { isResponse = false; isObstruct = false; } public void onAnimationRepeat(Animation animation) { } public void onAnimationEnd(Animation animation) { isSlide = false; isResponse = true; itemView.findViewById(R.id.tv_coating).setVisibility(View.VISIBLE); } }); itemView.findViewById(R.id.tv_coating).startAnimation(scaleShowAnimation); } } break; case MotionEvent.ACTION_UP: isObstruct = true; recycleVelocityTracker(); isSlide = true; break; } return true; } if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); if (getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) { // the first item is showing, header has shown or pull down. updateHeaderHeight(deltaY / OFFSET_RADIO); invokeOnScrolling(); } else if (getLastVisiblePosition() == mTotalItemCount - 1 && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) { // last item, already pulled up or want to pull up. updateFooterHeight(-deltaY / OFFSET_RADIO); } break; default: mLastY = -1; // reset if (getFirstVisiblePosition() == 0) { // invoke refresh if (mEnablePullRefresh && mHeaderView.getVisiableHeight() > mHeaderViewHeight) { mPullRefreshing = true; mHeaderView.setState(XListViewHeader.STATE_REFRESHING); if (mListViewListener != null) { mListViewListener.onRefresh(); } } resetHeaderHeight(); } else if (getLastVisiblePosition() == mTotalItemCount - 1) { // invoke load more. if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA && !mPullLoading) { startLoadMore(); } resetFooterHeight(); } break; } return super.onTouchEvent(ev); // return super.onTouchEvent(ev); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { if (mScrollBack == SCROLLBACK_HEADER) { mHeaderView.setVisiableHeight(mScroller.getCurrY()); } else { mFooterView.setBottomMargin(mScroller.getCurrY()); } postInvalidate(); invokeOnScrolling(); if (mScroller.isFinished()) { if (mRemoveListener == null) { throw new NullPointerException("RemoveListener is null, we should called setRemoveListener()"); } itemView.scrollTo(0, 0); } } super.computeScroll(); } //addVelocityTracker private void addVelocityTracker(MotionEvent event) { if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); } private void recycleVelocityTracker() { if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } } private int getScrollVelocity() { velocityTracker.computeCurrentVelocity(1000); int velocity = (int) velocityTracker.getXVelocity(); return velocity; } public interface RemoveListener { public void removeItem(int position); } @Override public void setOnScrollListener(OnScrollListener l) { mScrollListener = l; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mScrollListener != null) { mScrollListener.onScrollStateChanged(view, scrollState); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // send to user's listener mTotalItemCount = totalItemCount; if (mScrollListener != null) { mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } } public void setXListViewListener(IXListViewListener l) { mListViewListener = l; } /** * you can listen ListView.OnScrollListener or this one. it will invoke * onXScrolling when header/footer scroll back. */ public interface OnXScrollListener extends OnScrollListener { public void onXScrolling(View view); } /** * implements this interface to get refresh/load more event. */ public interface IXListViewListener { public void onRefresh(); public void onLoadMore(); } }

2015-05-04

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除