自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 Android中okhttp原理详解-极度针对面试篇

1、okhttp工作的大致流程1.1、整体流程(1)、当我们通过OkhttpClient创立一个Call,并发起同步或者异步请求时;(2)、okhttp会通过Dispatcher对我们所有的RealCall(Call的具体实现类)进行统一管理,并通过execute()及enqueue()方法对同步或者异步请求进行解决;(3)、execute()及enqueue()这两个方法会最终调用RealCall中的getResponseWithInterceptorChain()方法,从阻拦器链中获取返回结

2020-06-30 21:59:10 3639

转载 集成HMS Scan Kit扫码SDK,轻松实现手机扫码选购

场景在购物类APP中,通过扫描二维码的入口,扫描商品的二维码,直接显示商品信息和购买链接,方便客户选购商品。 整体方案开发前准备打开AndroidStudio项目级build.gradle文件 在allprojects ->repositories里面配置H...

2020-06-30 21:33:53 1942

原创 Android开发之 Wifi扫描分析

使用开始wifi扫描的代码很简单:val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManagerval success = wifiManager.startScan()if (!success) { // scan failure handling scanFailure()}然后定义一个receiver接收结果val wifiScanReceiver = object : B

2020-06-30 21:14:39 4077

转载 腾讯面试官——说说你对 binder 驱动的了解?

作者:Android面试官原文地址:https://juejin.im/post/5eeea016e51d45740e4273e8面试官提了一个问题:说说你对 binder 驱动的了解。这个问题虽有些 "面试造火箭" 的无奈,可难点就是亮点、价值所在,是筛选面试者的有效手段。如果让你回答,你能说出多少呢?我们来看看 ????、???? 和 ????️ 三位同学的回答如何吧???? 自认为无所不知,水平已达应用开发天花板,目前月薪 10k面试官️:说说你对 binder 驱动的了解??

2020-06-30 17:05:58 5951

原创 巧用Flag--Android Flag一探究竟

Android中存在着各种各样的Flag的使用,这篇文章主要研究一下这种Flag的运用方式。为什么要用Flag程序开发中,不同的场景可能需要不同的控制流;不同的控制流中,后置的控制流可能依赖于前置控制流的某一个属性或状态,这个时候,我们可以考虑引入标志位Flag,记录前置控制流中的属性或状态,在后置控制流执行时再去访问。在相对简单的场景中,我们完全可以这么处理:boolean success = false;public void putElephantIntoFridge(){ .

2020-06-29 16:19:59 1079

原创 Android性能优化:这些绘制优化你一定不能忽略!

前言在 Android开发中,性能优化策略十分重要 本文主要讲解性能优化中的绘制优化,希望你们会喜欢。目录1. 影响的性能绘制性能的好坏 主要影响 :Android应用中的页面显示速度2. 如何影响性能绘制影响Android性能的实质:页面的绘制时间1个页面通过递归 完成测量 & 绘制过程3. 优化思路主要优化方向是:降低View.onDraw()的复杂度 避免过度绘制(Overdraw)4. 具体优化方案具体如下下面,我...

2020-06-29 16:05:56 465

原创 Andorid性能优化之traceview的使用(不懂揍我)

一、traceview的使用方式有2种方式这2种方式可以根据场景,去选择哪一种方式。最终效果是一样的通过手动埋点 Profile1.1、通过手动埋点。步骤1: 比如我们知道在点击一个按钮的时候,会有卡顿,那么就可以用//可以用以下代码测试你的代码。//开始埋点,“app”是最后生成的性能分析文件Debug.startMethodTracing("App");//埋点结束,期间start 到 stop 之间的代码,就是你要测试的代码范围Debug.stopMethodTraci

2020-06-28 22:04:37 2060

原创 深入理解Android MTP之UsbService启动分析

闲话公司接了项目,开发一个在线升级功能,其中我需要实现手机端与PC端的通信。公司选择使用MTP来实现这个需求,因此我分析了大量的关于MTP的代码,从frameworks层到app,再到JNI层。鉴于网上关于这样的文章太少,而我开发的过程也比较长,因此我决定把framework, app , JNI层的分析都写下来,希望能帮助开发类似功能的小伙伴。邓凡平老师写的深入理解Android系列书籍,有的已经不出版了,但是他在博客中把文章的所有内容都发布出来,他说知识需要传递。这一点,我深感佩服。服务

2020-06-28 21:51:52 4163 1

原创 Android scheme 跳转的设计与实现

缘起随着 App 的成长,我们难免会遇到以下这些需求:H5 跳原生界面 Notification 点击调相关界面 根据后台返回数据跳转界面,例如登录成功后跳不同界面或者根据运营需求跳不同界面 实现 AppLink 的跳转为了解决这些问题,App 一般都会自定义一个 scheme 跳转协议,多端都实现这个协议,以此来解决各种运营需求。今天就来解析下QMUI 最新版 QMUISchemeHandler 的设计与实现。一个 scheme 的格式大概是这样子:schemeName://a.

2020-06-28 19:52:52 450

原创 Android Flutter 混合开发高仿大厂App

这篇文章将概述Android组件化的架构搭建及Flutter和Android如何混合开发(整个App只有首页是用原生Android完成,其他页面都是引入之前的做好的Flutter页面),主宿主程序由 Android 搭建,采用了组件化的架构搭建整个App,不同业务,对应不同的 module 工程,业务之间采用接口通信(ARouter),以 module 的形式混入 Flutter,通过MethodChannel和Flutter端进行数据通信等,且这些功能实现源码开源,感兴趣的小...

2020-06-24 20:52:31 809

原创 面试官:“看你简历上写熟悉 Handler 机制,那聊聊 IdleHandler 吧?”

一. 序Handler 机制算是 Android 基本功,面试常客。但现在面试,多数已经不会直接让你讲讲 Handler 的机制,Looper 是如何循环的,MessageQueue 是如何管理 Message 等,而是基于场景去提问,看看你对 Handler 机制的掌握是否扎实。本文就来聊聊 Handler 中的 IdleHandler,这个我们比较少用的功能。它能干什么?怎么使用?有什么合适的使用场景?哪些不是合适的使用场景?在 Android Framework 中有哪些地方用到了它?.

2020-06-24 19:31:38 442

原创 Android 23种设计模式全面解析

一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:二、设计模式的六大原则总原则:开闭原则(.

2020-06-23 20:48:50 2711

转载 详解Android Bitmap:关于你所要知道的一切

前言在平时的 Android 开发中,与 Bitmap 打交道可以说是再常见不过的事了。我在写这篇文章之前,对于 Bitmap 相关的一些东西总是模模糊糊,比如 Bitmap 的文件大小还有占用内存大小的区别,还有对 Bitmap 压缩的几种方法各自的区别和通途是什么,等等在这篇文章中,我将会把在 Bitmap 中相关的知识点都一一介绍,如果你也是对 Bitmap 总是感觉模模糊糊的话, 相信你看完这篇文章后一定会有所收获目录一、Bitmap 的创建二、Bitmap 的颜色配置信息与压缩方

2020-06-23 17:42:26 680

原创 扒一扒面试必问的Handler

前言Handler作为Android代码编写以及面试时经常遇到的内容,有必要花个时间整理一下,毕竟写过的东西印象会更加深刻。1.什么是Handler?1.1 定义源码里面捞出来的内容,英文不难看懂。主要就是说每个Handler会和每个线程以及线程对应的消息队列相绑定。之后消息就可通过Handler在线程之间传递。A Handler allows you to send and process {@link Message} and Runnable objects associated

2020-06-22 22:16:23 465

转载 Kotlin Vocabulary | 内联函数的原理与应用

我们的项目里常常会创建一些 Util 类,用于分类整理那些会在许多地方用到的小型函数 (也称实用函数),如果这类函数接收了另一个函数作为参数,则可能会造成一些额外的对象分配,通过使用 inline 关键字,您可以避免这种情况并提升应用性能。接下来我们就来看一看,当您把一个函数作为参数传递时发生了什么、inline 关键字背后做了哪些工作,以及使用内联函数 (inline function) 时的注意事项。函数调用——工作原理我们在应用中常常要用到 SharedPreferences,现在假设您为了减

2020-06-22 21:01:55 399

转载 Fragment 的过去、现在和将来

Fragment 是 Android 中历史十分悠久的一个组件,它在 API 11 被加入,时至今日已成为 Android 开发中最常用的组件之一。Fragment 有了哪些新特性、修复了哪些问题,都是开发者们十分关心的话题。下面我们就来重新说一说 Fragment —— 不仅仅是说现在的 Fragment,还会回顾它的发展,并让您一瞥它未来的样子。Fragment 的诞生与发展不知道您是否还记得 "上古时期",在那些还没有 Fragment 的日子,几乎所有逻辑都被放在了 Activity 中,使

2020-06-22 20:56:36 408

原创 Android Jetpack架构开发组件化应用实战

项目介绍本项目采用组件化+MVVM架构进行开发,对功能组件和业务组件进行拆分,通过ARouter进行组件之间的通信。本文主要是对整个应用的技术架构作一个简单的介绍。技术要点Kotlin+Jetpack+Coroutines+Retrofit+koin项目整体架构图:宿主App没有任何的业务代码,整个业务被拆分为各个ft_lib模块。对一些功能组件进行封装抽取为lib,提供给上层依赖。ft_lib之间没有任务依赖关系,通过Arouter进行通信。首页功能首页分为5个Tab.

2020-06-21 22:19:23 686

原创 网易云--手机QQ的换肤是怎么做到的,你对换肤有了解吗?看过换肤的原理没?

面试官: 网易云QQ的换肤是怎么做到的,你对换肤有了解吗?看过换肤的原理没?心理分析:没有接触过换肤技术 第一次听到该名词肯定会很茫然。面试官考的是对资源加载,监听布局,有没有了解.本文从换肤实战一对一讲解。告诉你如何做以及实现。文章末尾带换肤项目源码求职者:从监听布局开始到 换肤原理,详细给面试官讲解换肤的原理接下来我们一起分享这篇干货。 Android的主题换肤 ,可插件化提供皮肤包,无需Activity的重启直接实现无缝切换,可高仿网易云音乐的主题换肤。这个链接是本次的D..

2020-06-20 22:46:08 2393 6

原创 腾讯面试---为什么会用到EventBus,EventBus的源码详解与架构分析,使用EventBus会造成什么弊端

面试官: 为什么会用到EventBus,EventBus的源码详解与架构分析,使用EventBus会造成什么弊端心理分析:eventbus对程序员相爱相恨,爱 爱在太方便了,恨 恨在对程序的可读性有致命的伤害,小公司会用但面试的时候不会考,大公司不会用,但面试的时候使劲考。从该文中我们可以找到如何面试上大公司的线索和机会求职者:求职者应该从 eventbus弊端入手,然后深入源码入手,告诉面试官 我不仅用过 还深入研究过。最后因为他的可读性 抛弃了它,所以这才是最厉害的EventB..

2020-06-20 21:35:17 1467

原创 Jetpack 之 LiveData 源码分析

LiveDataLiveData 是一个可以感知 LifecycleOwner 生命周期的可被观察的数据容器。接下来,我们从 3 个角度来分析 LiveData 。数据容器; 可被观察; 感知生命周期数据容器LiveData 它实际上是一个数据容器,我们设置的数据真正是存放在 mData 里面的。static final int START_VERSION = -1;private static final Object NOT_SET = new Object();

2020-06-20 20:49:26 307

原创 Android Handler机制-Looper、Handler、MessageQueue、Message的关系

一、概述Handler是Android中处理异步消息的机制。Looper、Handler、MessageQueue、Message概括来说就是:Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息Message,然后回调相应的消息处理函数,而消息的创建者就是一个或多个Handler,执行完成一个消息后则继续循环。二、MessageQueue详解消息队列MessageQueue就是存放消息的队列。那队列中存储的消息是什么呢?.

2020-06-19 22:25:28 669

原创 Android - JNI 开发你所需要知道的基础

这篇文章主要讲解了 JNI 的基础语法和交叉编译的基本使用,通过这篇文章的学习就完全可以入门 Android 下 JNI 项目的开发了。JNI 概念从 JVM 角度,存在两种类型的代码:“Java”和“native”, native 一般指的是 c/c++,为了使 java 和 native 端能够进行交互,java 设计了 JNI(java native interface)。 JNI 允许java虚拟机(VM)内运行的java代码与C++、C++和汇编等其他编程语言编写的应用程序和库进行互操作。

2020-06-19 21:26:07 754

原创 字节跳动-谈下音视频同步原理,音频和视频能绝对同步吗?

面试官: 谈下音视频同步原理,音频和视频能绝对同步吗心理分析:音视频同步本身比较难,一般使用ijkplayer 第三方做音视频同步。不排除有视频直播 视频通话需要用音视频同步,可以从三种 音频为准 视频为准 自定义时钟为准三种方式实现音视频同步**求职者: **如果被问到 放正心态,能回答多少是多少。如果你看了这篇文章肯定是可以回答上的音视频的直播系统是一个复杂的工程系统,要做到非常低延迟的直播,需要复杂的系统工程优化和对各组件非常熟悉的掌握。下面整理几个简单常用的调优技巧:以f.

2020-06-19 17:00:36 1440

原创 Message 引发的 DialogFragment 内存泄漏分析与解决方案

Q:咋回事?正常使用 Dialog 和 DialogFragment 也有可能会导致内存泄漏?A: ....是的,说来话长。长话短说:某一个 HandlerThread 的 Looper#loop 方法,一直等待 queue#next 方法返回,但是它的 msg 局部变量还引用着上一个循环中已经被放到 Message Pool 中 Message,我们称之为 MessageA。 DialogFragment#onActivityCreated 方法中,会调用 Dialog#setOnC.

2020-06-18 21:41:53 3523 2

原创 “沉浸式”体验?异形屏适配?我把他们扒光了明明白白告诉你应该这样做

看似复杂的沉浸式体验设计,其实也就是在处理以下两个 System UI与用户布局(setContentView)之间说不清理还乱的关系:StatusBar 系统状态栏 NavigationBar 系统导航栏网上类似“沉浸式状态栏”的文章一搜一大把,且先不吐槽所谓的“沉浸式状态栏”说法正确与否,随便一篇文章都会告诉你,要实现沉浸式体验有两个关键地方:window.decorView.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or S

2020-06-18 21:26:03 1744

原创 Activity 的快乐你不懂!

前言本文本来是自己复盘 Android 知识梳理用的,没想到在上周部门内部的知识测评中发现,同事们对这些基础知识的掌握参差不齐,甚至可以说是模棱两可。是网上关于 Activity 的教程太少了吗?不是的,恰恰相反,网上的信息多如牛毛,却没有一篇愿意费哪怕一丝丝的笔墨 来介绍 Activity 的起源、它的职责边界、它的存在到底是为了解决什么问题、我们学习它,到底学到什么程度才算掌握。 ...

2020-06-17 20:41:09 324

原创 Android 中 Parcelable和Serializable的区别

本文主要介绍Parcelable和Serializable的作用、效率、区别及选择。1、作用Serializable的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在,Parcelable是通过IBinder通信的消息的载体。从

2020-06-17 20:23:30 607

原创 Android 该如何开发一个证件照DIY小程序 这篇来教你

引子  不知道大家是否有这样的经历,忽然学校或者公司需要提供让提供个人的一寸或者两寸头像照片,要办理出入证、学生证什么的,并且对照片的底色有要求,有很多人当前没有拍好的证件照需要到照相馆重拍,又或者之前已经拍过了,但是照片底色不满足要求,小编就有过类似的经历,当时学校让办个出入证,学校照相馆又关门了,匆匆忙忙用手机拍了下,然后用床单作为背景应付,结果被老师大骂了一顿。  多年以后华为的HMS MLKit机器学习有了图像分割的功能,使用这个SDK开发一个证件照DIY的小程序,可以完美解决小编当年遇到的

2020-06-17 16:18:38 1095

转载 DataBinding从基本使用到核心源码解析,看不懂的兄弟跟我一起去摆摊

DataBinding是谷歌发布的jetpack库里的重要一员,通过使用DataBinding来实现MVVM架构,可以有效避免了MVP架构里新建文件过多的繁杂问题,并且每次数据源更新时不再需要开发人员来调用控件的set方法更新数据了,同时支持双向绑定也能让控件之间互相刷新,可以减少控件之间的监听,从而减缓陷入回调地狱的进度。今天笔者给大家分享一下DataBinding从入门基本使用,到深入源码的一整个过程。如果你从来没用过DataBinding,那么恭喜你看完就是jetpack大佬了。哈哈开个玩笑乐呵乐呵,

2020-06-17 14:32:08 959 2

原创 Android一次完美的跨进程服务共享实践

背景最近需要做这样一个事情,一个服务来完成多款App的录音功能,大致有如下逻辑服务以lib的形式集成到各个端 当主App存在时,所有其他App都使用主App的录音服务 当主App不存在时,其他App使用自带录音服务 有优先级,优先级高的App有绝对的录音权限,不管其他App是否在录音都要暂停,优先处理高优先级的App请求 支持AudioRecord、MediaRecorder两种录音方案为什么要这么设计?Android系统底层对录音有限制,同一时间只支持一个进程使用录音的功能 业务需

2020-06-15 20:41:31 523

原创 你真的懂Handler吗?Handler问答

为什么写 Handler确实 Handler 是 Android 开发过程中非常非常常见的东西,讲Handler的博客也不胜枚举为什么我还要写关于Handler的内容?起因是这样的,公司为了扩张业务准备做一个新的产品线所以给移动端这边分配了4个招聘名额(iOS和Android各两名),头一个星期我因为在忙着做需求并没有参与公司的面试,都是公司的另外两个同事在参与面试,后一个星期我也参与到其中,但是我发现一个很严重的问题:在我面试的几个人虽然工作经验都集中3~6年但都没有把 Handler 讲清楚。

2020-06-15 17:54:04 536

原创 终于明白了Handler怎么线程间通信的

一直对handler似懂非懂,这次看了别的文章加上自己的理解,终于明白Handler到底是如何实现线程间的通信了.大家共同探讨研究.首先得明白,一个线程只有一个Looper和MessageQueue.调用本线程的Handler只能发送Message到本线程的MessageQueue.那怎么区分Handler是哪个线程的呢,是通过Handler对象中的Looper对象.然后本线程Looper对象loop(),不断从MessageQueue取消息。1.主线程初始化Handler//内存泄漏的问题请先

2020-06-15 17:26:56 1583

原创 阿里架构师最新 Android 面试点梳理,我收藏了你呢?

目录:网络:分层模型、TCP、UDP、HTTP、HTTPS 算法:数据结构、常用算法 Java 基础:StringBuilder、泛型擦除、Exception、IO、容器 Java 同步:volatile、wait、synchronized、可重入锁、乐观锁、死锁 Java 设计模式:六大原则、23 种设计模式、动态代理 Java 虚拟机:内存模型、内存结构、GC、四种引用、ClassLoader Android 基础:Activity、View 绘制、动画、Window、SurfaceVi

2020-06-14 22:04:25 945

原创 动作编辑器实时布局,布局实时验证,Kotlin 实时模板,构建数据实时分析,AndroidStudio 4值得更新

2020年5月28日,Android Studio发布了4.0,其中的一些亮点包括:新的动作编辑器,可真正实现拖拽式编程; 构建分析器,可分析出是什么原因导致了应用构建变得缓慢; Java 8语言的API,无论APP的最低API级别是什么,都可以使用Java 8的API;此外,还对CPU Profiler用户界面进行了修改,以提供更直观的工作流程,更容易对线程活动进行并排分析。而改进后的布局检查器能获得APP的UI的实时数据,可以更加轻松地调试设备上显示的确切内容。外观设计动作编...

2020-06-12 20:47:03 513

原创 Android程序员是如何使用 Kotlin 连接 MQTT的?

MQTT是一种轻量级的、灵活的物联网消息交换和数据传递协议,致力于为 IoT 开发人员实现灵活性与硬件/网络资源的平衡。Kotlin是一门由 JetBrains 公司开发的编程语言,Kotlin 是基于 JVM 的,所以开发者可以很方便地用它来进行Android 开发,并且支持 Kotlin 和 Java 的混合编写。而早在 2017 年,Google 就宣布 Kotlin 成为官方开发语言。本文主要介绍使用 Kotlin 语言在 Android 平台上使用 MQTT。新建 Kotlin 项..

2020-06-12 20:24:22 589 3

原创 面试时面试官问到,你做过哪些性能优化?

如果你已经有 2 - 3 年以上开发经验还不懂的怎么去优化自己的项目,那就有点说不过去了,下面是我自己总结的一套通用级别的 Android 性能优化。1、 你对 APP 的启动有过研究吗? 有做过相关的启动优化吗?程序员:之前做热修复的时候研究过 Application 的启动原理。项目中也做过一些启动优化。面试官:哦,你之前研究过热修复? (这个时候有可能就会深入的问问热修复的原理,这里咱们就不讨论热修复原理) 那你说说对启动方面都做了哪些优化?程序员:1. 我发现.

2020-06-12 17:41:18 2408

原创 为什么为数不多的人知道的 Kotlin 技巧以及 原理解析呢?

Google 引入 Kotlin 的目的就是为了让 Android 开发更加方便,自从官宣 Kotlin 成为了 Android 开发的首选语言之后,已经有越来越多的人开始使用 Kotlin。结合着 Kotlin 的高级函数的特性可以让代码可读性更强,更加简洁,但是呢简洁的背后是有代价的,使用不当对性能可能会有损耗,这块往往很容易被我们忽略,这就需要我们去研究 kotlin 语法糖背后的魔法,当我们在开发的时候,选择合适的语法糖,尽量避免这些错误,关于 Kotlin 性能损失那些事,可以看一下我另外两篇

2020-06-11 18:07:20 515

原创 这篇带你搞懂Handler怎么线程间通信的

一直对handler似懂非懂,这次看了别的文章加上自己的理解,终于明白Handler到底是如何实现线程间的通信了.大家共同探讨研究.首先得明白,一个线程只有一个Looper和MessageQueue.调用本线程的Handler只能发送Message到本线程的MessageQueue.那怎么区分Handler是哪个线程的呢,是通过Handler对象中的Looper对象.然后本线程Looper对象loop(),不断从MessageQueue取消息.1.主线程初始化Handler//内存泄漏的问题请先

2020-06-11 17:55:47 1175 4

转载 Android开发设计模式六大原则之开闭原则

开闭原则定义:软件中的对象(类,模块,函数等)应该对于扩展是开放的,对于修改是关闭的。英文全称(Open Close Principle),简称:OCP在实际开发中常常会遇到这样的问题,从别人那里接手过来的代码,还没来的及熟悉代码,项目就催着赶紧升级,当你想使用一个功能的时候,你可能发现项目里有相关代码,但是你又不敢用,你怕改出来问题,所以一般可能都会采取新增一块功能一样的代码。其实这就是简单的遵循了开闭原则。上面的场景相信大家都遇见过,你不想你写的代码,被别人诟病吧。所以掌握开闭原则要领很有必要.

2020-06-11 17:42:45 575

原创 Android开发设计模式六大原则之单一职责原则

​学习Android设计模式也有一段时间了,这段时间工作不忙,想把所学知识沉淀下来,决定把设计模式的知识做一个系列,方便你我。废话不多说。学习设计模式难免要先学习六大原则,因为在后面的设计模式运用过程中,都或多或少的遵循这六大原则。所以要想精通设计模式,六大原则必须要熟练掌握。本篇要讲的是单一职责原则:1、单一职责原则(Single Responsibility Principle,简称SRP )解释: 应该有且仅有一个原因引起类的变更,通俗来讲就是一个类只干一件事。看代码://从

2020-06-11 17:38:12 342

组件化通信之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关注的人

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