自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

黎程雨的博客

粉丝交流群:849907537

  • 博客(258)
  • 资源 (16)

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

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

2020-06-20 22:46:08 1783 4

转载 Android 网络框架之OkHttp源码解析

作者:Amter前言:OkHttp框架是Android的网络请求框架,无数的项目都在使用着这个框架,重要性不言而喻;本文会将OKHTTP的源码进行拆解,每个部分来单独学习,由简入深,循序渐进,篇幅较长,建议收藏,慢慢观看,如果觉得内容不错的话,点赞关注来一波,感谢!源码基于okhttp3 java版本:3.14.9OkHttp3的简单使用:public void request() { String url = "http://wwww.baidu.com";.

2020-09-19 21:46:41 7

原创 渣本安卓客户端Android秋招总结(重排了字号)

作者:吴宇来晚了来晚了,整理一下去年秋招面经,一直想想整理因之前太忙了,所以拖到现在才发,希望对大家有所帮助,能在金九银十的时候连斩Offer。一、学习经历比较菜,辣鸡本科生,2018年十一月份开始全面一些的接触安卓,学了第一行代码,面试后进入某公司某部门,正好比较缺人给我这零基础的人过了,十二月份去实习,断断续续中间回学校考试有请假,大概有效实习时间是6个月吧,边学边做的需求,到7月底学校有事离开的。后来回来又干到9月。对于安卓的学习主要经历就是在公司学的这半年多,感谢能有这样的机会,lead.

2020-09-18 22:37:02 94

转载 Kotlin 协程和 Android SQLite API 中的线程模型

作者:Android_开发者从 Room 2.1 版本之后,开发者们可以通过定义 suspend DAO 函数来使用 Kotlin 协程了。协程在处理异步操作时表现得异常优秀,它可以让您用顺序自然的代码处理诸如操作数据库一类的耗时操作,而不再需要专门在线程之间来回切换任务、处理结果或错误了。Room 支持协程后,可以在数据库操作中使用由并发作用域、生命周期、嵌套所带来的一些便利。在我们为 Room 添加协程的支持期间,我们遇到并解决了在协程模型和 Android SQL API 中没想到的一些问题。.

2020-09-17 22:29:07 24

原创 35岁没有晋级的同事都去哪了?

35岁的职场人活该被淘汰吗?相信大家都知道35岁的中年危机这一个问题,那我们该如何去应对和过渡完这一个中年危机呢?前段时间,某公司去大学校园里面校招,HR兴致勃勃地宣传公司年轻化很阳光, 结构有人问“那你们公司大龄的员工都去哪了呢?”去哪了?咱也不敢说,咱也不敢问但是从上方这个问题映射出的社会问题便是**“中年危机”**找工作时,公司单位普遍要求35岁以下,那35岁以上的人都干什么去了?35岁中年危机真的存在吗?事件:小L从事互联网IT行业已经10年了,今年35岁,三月份裸辞后到.

2020-09-17 21:20:41 71

原创 Jetpack 之 LifeCycle 组件使用详解

一、LifeCycle 简介LifeCycle 是一个可以感知宿主生命周期变化的组件。常见的宿主包括 Activity/Fragment、Service 和 Application。LifeCycle 会持有宿主的生命周期状态的信息,当宿主生命周期发生变化时,会通知监听宿主的观察者。LifeCycle 的出现主要是为了解决: 系统组件的生命周期与普通组件之间的耦合性。系统组件指:Activity/Fragment、Service 和 Application。普通组件指:将代码按照功能或者作用封装成

2020-09-16 17:33:25 25 1

原创 你真的理解Binder“一次拷贝“吗?

前言谈到到Binder相对于其他传统进程间通信方式的优点的时候,我们总会说Binder只需要做“一次拷贝”就行了,而其他传统方式需要“两次拷贝”。这确实是Binder的优点,但再进一步思考就会碰到两个问题:这所谓的“一次拷贝”到底是发生在什么地方?拷贝的到底是什么东西?而很多介绍Binder的文章会列出“一次拷贝”是其优点,但对上面的两个问题要么一笔带过,要么就是回答的并不完全正确,造成一些理解上的混乱。本篇文章意在探索这两个问题的正确答案,所以需要读者对Binder驱动的工作过程和Binder驱

2020-09-15 22:16:22 15

原创 阿里两轮面试都被问了组件化问题,你会嘛?

阿里4轮面试,两轮面试都被问到组件化问题,面试的点各不相同,有组件化架构设计、插件化框架设计、路由架构设计、热修复设计等问题,但是最终都是殊途同归,所有的问题都汇集在这,如何对手机淘宝组架构设计?组件化如何实现,组件化与插件化的差别在 哪里,该怎么选型**面试官:**组件化如何实现,组件化与插件化的差别在哪里,该怎么选型**心理分析:**面试官从架构层次 了解求职者是否用过 模块化 组件 化 和插件化,在过去经验有没有运用过这些技术到项目中,这道 题属于一个连环炮。求职者该格外小心**求职者:

2020-09-15 20:58:31 96

转载 进阶之路 | 奇妙的四大组件之旅

学习清单:Activity的工作过程Service的工作过程Service的启动过程Service的绑定过程BroadcastReceiver的工作过程BroadcastReceiver的注册过程BroadcastReceiver的发送和接收过程ContentProvider的工作过程一.为什么要学习四大组件?何为“四大”:ActivityServiceBroadcastReceiverContentProvider谈到四大组件,相信在座各位都再

2020-09-14 22:33:56 21

原创 面试斩获猫眼Android岗Offer,我是怎样准备Android技术面的知否?

作者:哈登前言本篇文章给大家分享一下笔者面试的一些感受和经验。笔者从前期准备到所有面试结束,花费了差不多3个月的时间。真可谓“面试造航母,工作拧螺丝”,面试过程真的很累很辛苦。笔者面了很多公司,最终拿下了猫眼Offer;有面试交流群小伙伴问我是怎么准备面试的,我也想谈谈我最近的一些想法和计划,大家一起讨论。因此写下了这篇文章。整体分为以下两个方面:自我介绍 & 项目经验知识储备自我介绍1、结合招聘岗位,只讲重点。简历内容这么多,实际的你,更有很多很多可以描述的东西。但时.

2020-09-14 21:34:27 27

转载 进阶之路 | 奇妙的 IPC 之旅

学习清单:IPC的基础概念 多进程和多线程的概念 Android中的序列化机制和Binder Android中的IPC方式 Binder连接池的概念及运用 各种IPC的优缺点一.为什么要学习IPC?IPC是Inter-Process Communication的缩写,含义是进程间通信,是指两个进程之间进行数据交换的过程。有些读者可能疑惑: “那什么是进程呢?什么是线程呢?多进程和多线程有什么区别呢?”进程:是资源分配的最小单位,一般指一个执行单元,在PC和移动设备上指一个程序

2020-09-13 21:38:24 20

原创 鸿蒙2.0正式开源,华为重磅押注开发者生态

作者:稀土君从第一轮制裁到第二轮制裁,华为的众多产品和业务都被笼罩在美国制裁的阴影之下,难以完成新品的生产和交付。在这种前所未有的外部危机下,华为发布了自研系统鸿蒙系统(HarmonyOS),同时带来基于该系统的华为移动服务HMS。但是仓促之推出的产品,难免存在不少有待完善的地方,鸿蒙系统也被众多网友戏称为“PPT系统”。但是这场特殊背景下的自救之路还远远没结束,怀带众多期盼的新的鸿蒙系统2.0已在松山湖畔悄悄登场。HarmonyOS 2.0问世,开源版本已开放下载2019年,华为创造性地推出了.

2020-09-12 22:02:03 231

原创 Android Jetpack组件之App Startup

写在前面在看Jetpack的官网时,发现官方在Jetpack中新加了一个App Startup组件,查了一下是前几天和Hilt、Paging3一起更新的,其他的组件还没看。官方网址: https://developer.android.com/topic/libraries/app-startup要选择语言为ENGLISH哦,中文版暂时还没有这个页面。为什么需要App Startup呢?在我们实际的开发工作中,一些第三方库需要在App启动的时候初始化并不少见,比如WorkManager和Life.

2020-09-11 22:30:53 18

原创 JetPack现在都成了Android开发必备技能嘛?

一、Android JetPack——Google多么痛的领悟最近好几个小伙伴问我什么是Android JetPack,听说这个包好像有点牛,帅哥你会不?我心想什么鬼!Android JetPack这货不是一个库,是一整套的库,是一种信仰一种态度好么。从前,Android开发者基本都是被放养的。生态基本全靠自建,代表有Square全家桶,Glide,Google自己也肯定是出力的,但是并没有明确Android开发的几个大方向,所以安卓的开发生态一直是百花齐放百家争鸣。带来的问题就是经常出现包引用莫名报错

2020-09-11 22:28:53 25

转载 回想自己从三流小公司到一线大厂的经历,你熬出头了嘛? 淦!!!

我想,没有一个程序员能够一步登天,一下子达到很高的高度,有些路是我们必须要走的,有些阶段是我们必须要经历的。有入门,才有进阶,才有更上一层楼。别看我现在在大厂,但是我也待过小到不能小的小公司,也许你会感兴趣,那么不妨听我说说,我在学习编程路上待过的公司吧。不到20人的小公司我在大学的时候学的不是计算机,上的课程基本上和计算机也没太大关系,但是我从小还是比较喜欢捣鼓电脑的,不瞒你说,以打游戏为主,修电脑为辅。兴趣使然,于是大学期间想要自学编程,但是无从入手,于是让家里人介绍了去了当地一个小公司学习

2020-09-10 22:29:57 31

转载 Android热修复技术选择和原理分析

背景热修复就是通过下发补丁包,让已安装的客户端动态更新,用户不用重新安装APP,就能够修复软件缺陷。热修复技术对比1.公司角度大致可以分为阿里系和腾讯系和其他,如下:阿里系Dexposed 开源,实时修复AndFix 开源,实时生效HotFix 阿里百川,未开源,免费、实时修复Sophix 未开源,商业收费,实时生效/冷启动修复HotFix是AndFix的优化版本,Sophix是HotFix的优化版本。目前阿里系主推是Sophix。腾讯系Qzone超级补丁 QQ空间,未开源,冷启动

2020-09-10 22:27:58 40

原创 Android岗BAT、网易、京东大厂试水面经,有幸拿到京东offer

前言本人在渣院二本毕业,毕业了3年,之前在一家小型的创业公司,本来是计划今年的三四月份找一份有挑战性的工作的,结果中间由于某些原因耽误了,在今年8月份的时候,向以下公司投递了简历:百度、腾讯、阿里巴巴、网易、京东,其中腾讯和阿里巴巴把我笔试给挂了,其余公司的笔试过了。阿里巴巴把我笔试挂了我感觉很坦然,因为笔试题做得实在不好,而腾讯把我的笔试挂了我就觉得很奇怪,当时大部分题目都做得还可以,只有一道算法题没做出来,后来就没过。不过都是往事了,有空把笔试经历总结一下,下面开始把面试经历好好回忆一下,因为已经过.

2020-09-09 22:40:34 38

原创 深入Android系统 Binder-4-驱动

Binder驱动Binder 驱动是整个Binder框架的核心,这部分就会详细介绍消息协议、内存共享机制、对象传递的具体细节了应用层和驱动的消息协议Binder应用层的IPCThreadState和Binder驱动之间通过ioctl来传递数据,因此,定义了一些ioctl命令:命令说明数据格式BIDNER_WRITE_READ向驱动读取和写入数据,既可以单独读写,也可以同时读写。通过传入的数据中有无读写数据来控制struct binder_write_readBIN

2020-09-09 22:38:05 29

原创 Android声明式UI框架 Litho 初探——基础使用

初衷Litho作为一个高性能的UI引擎,学习曲线还是比较高的,但是在国内能用的资料非常少(大部分都是相互复制的”Hello Word“教程),国外除了Litho自己的文档外,也没有太多教程。这几篇教程也是我边学边写。如果有那里理解不到位的地方,欢迎指正。Litho 是什么Litho是一个用于在Android上构建高效用户界面(UI)的声明性框架。但不同以往的UI框架,它的底层是Yoga,它通过将不需要交互的UI转换为Drawable来渲染视图,通过Yoga来完成组件布局的异步或同步(可根据场景定

2020-09-09 20:43:24 33

原创 Android性能优化之UI卡顿优化实例分析

网络上有许多关于UI卡顿优化的解析,但大部分都是简单的原理介绍,例子都比较简单,往往是为了验证UI卡顿而硬造的,不能在实际场景中应用。本文结合大图加载,与UI卡顿优化,向大家介绍UI卡顿优化的基本原理。UI卡顿的根本原因是UI线程无法在16ms内完成UI绘制。 下面以android大图加载为例,结合内存分析,systrace,TraceView等分析UI卡顿优化.两种大图加载方式对比方法1Android 高清加载巨图方案 拒绝压缩图片 使用BitmapRegionDecoder分区域加载

2020-09-09 20:37:40 38

原创 深入Android系统 Binder-3-原理

Binder的实现原理涉及到原理源码肯定是少不了的,9.0 binder 相关的源码分为三部分:Java:frameworks/base/core/java/android/os/Binder.javanative:frameworks/native/libs/binder/driver:common/drivers/android/binder.c还有一点需要明确的是:用户进程:针对内核空间或者binder驱动来说的,这里指的是向binder驱动发送消息的进程客户进程:针对binder

2020-09-08 22:38:12 24

原创 从事Android开发5年了,想跟闲聊一下35岁定律

其实很早就想写了,奈何当时啊有事耽误了,等有空闲都过了好几天了,再想写就 get 不到当时的心情和想法了还好今天看到一篇文章又让我想起了当时的感受,所以吧今天就不偷懒了,努努力写完他也算是经历了一些事,也算是有了些感想,到年底总要写点什么不是,这篇文章里我可能会零零碎碎说一些,估计上下文不成体系,不能连贯,大家看着玩吧,希望能有一起讨论的朋友文章我不想写大家都写的,我想换个角度,或是其他大家可能看的到的东西写写,不管大家怎么看请多留言吧,把你的想法写出来,给更多的看,这才能有更多的收获送给看不清行业

2020-09-07 22:44:11 66

转载 深入Android系统 Binder-2-使用

如何使用 Binder就开发语言而言,Binder服务可以用Java实现,也可以用C++实现,通常,我们在Java代码中调用Java语言实现的服务,在C++代码中调用C++编写的服务。但是从原理上讲,Binder并没有这种语言平台的限制,混合调用也是可以的。应用可以在任意的进程和线程中使用Binder服务的功能,非常方便、灵活。也不用关心同步、死锁等问题使用Binder服务C++层和Java层使用Binder服务的方式基本一样,包括函数的接口类型都相同,这里以C++为例:使用Binder服务前

2020-09-07 22:42:28 20

转载 经典 OOM 问题|pthread_create

一、背景近期版本上线后收到不少用户反馈(大多是华为用户)崩溃,日志上总体表现为 pthread_create (1040KB stack) failed: XXX。java.lang.OutOfMemoryErrorpthread_create (1040KB stack) failed: Out of memory1 java.lang.Thread.nativeCreate(Native Method)2 java.lang.Thread.start(Thread.java:743)3 ja

2020-09-07 21:31:08 70

转载 深入Android系统Binder-1-导读与简介

作者:apigfly简单的开始我们先简单了解下binder架构涉及的几个概念:客户进程:发起远程方法调用的进程服务进程:真正服务所运行的进程binder驱动:binder通信的核心,远程调用都是通过它来处理和传递的servicemanager:一个管理binder服务的进程一个简单版本的跨进程调用的流程:客户进程把调用信息发给驱动,等待驱动返回消息驱动处理一下调用信息,并通知服务进程服务进程接到驱动的通知,根据调用信息开始执行服务进程执行完毕,通知驱动驱动接收到服务进程的通.

2020-09-06 22:18:06 17

原创 从事Android开发4年,面试通过全靠狂刷这份面试题,从11K涨到25K+(内含答案)

在博主认为,对于Android面试以及进阶的最佳学习方法莫过于刷题+博客+书籍+总结,前三者博主将淋漓尽致地挥毫于这篇博客文章中,至于总结在于个人,实际上越到后面你会发现面试并不难,其次就是在刷题的过程中有没有去思考,刷题只是次之,这又是一个层次了,这里暂时不提后面再谈。博主总结了一系列大厂面试中常问的面试技术点,深入解析以及答案,将为最近准备面试的各开发者去大厂保驾护航,何谓面试? 博主所理解的面试,它是一个过程,是不断沉淀、不断总结、善于传达自己的专业领域技术以及解决问题能力的过程。以下是博主总结

2020-09-04 21:34:35 51

原创 2020年腾讯,阿里,美团等Android高频面试题及答案,知识脉络整理

前言这篇文章非常的干!覆盖了安卓面试的大多数知识点,值得收藏反复查看!安逸久了就容易迷失方向,多看看高质量的面试题找找差距,然后查漏补缺!##问题区:1.Activity的启动过程,AMS、PMS源码2.View的绘制过程,MeasureSpec测量模式分别代表什么意思,draw是哪里来的?自定义view3.view的事件分发机制4.hashmap原理,arraylist,linklist原理5.你在开发过程中常用设计模式有哪些,单例设计模式的双重校验的目的?去掉第一个判空或第二个判空有

2020-09-04 21:33:18 64

原创 Android音视频--H.264视频流解码

1. 简介H.264是比较多开发者使用较多的一种数字视频压缩格式,主要用于直播流的传输与视频网站的视频流传输,也有不少开发者开始使用H.265进行视频压缩,性能较H.264提升较大。本篇文章着重介绍使用MediaCodec硬件H.264裸字节流数据的实现方式,有关于更多H.264的介绍可以查看参考文章中H.264的结构介绍。2.使用MediaCodec硬解码2.1 MediaCodec介绍 MediaCodec类Android提供的用于访问低层多媒体编/解码器接口,它是Android低层多

2020-09-04 16:00:35 54

原创 程序员到底是吃青春饭还要奋斗?那么行业前景又如何?

程序员们最后喜欢讨论的话题就是:A:Java 真的凉了嘛?Java开发前景如何?B:大数据真的凉了嘛?大数据开发前景如何?C:人工智真的凉了嘛?人工智能前景如何?……在现在的时代,不管是在任何行业,任何岗位,初级技术人才总是供大于求,都是不好找工作。就算现在出了一个新的行业或新的岗位,开始可能对初级人员有着大量的需求,但过个两年,随着时代的变化,人员的变化,技术更新和行业的变化,不管你是什么行业岗位的初级人员都是一样,都只有那么两年可以吃的香。但随着市场的需求,行业要求的不断提升,初级人员也只

2020-09-03 22:58:30 138

原创 5G时代下,Android音视频强势崛起,我们该如何快速入门音视频技术?

5G时代到来对人们的影响几何?从历史来看,2G打开了了移动互联网天下,3G带来了即时通信,诞生了QQ 微信等巨头,4G 带来了短视频兴起。字节跳动等公司崛起。2 3 4G的出现促成了移动互联网10年繁荣。而5G的出现,也会促成至少10年音视频行业的繁荣。所以,做音视频研发的前景是广阔的,对于很早看出音视频前景的同学来说,已经开始通过各种渠道搜集相关的学习资料,及早的投入音视频研发的队伍。作为Android开发者的我们到底应不应该上音视频这条船?接下来一起分析下。大趋势从未来的大趋势来看,随

2020-09-03 22:55:49 54

原创 掌握 binder 机制?先搞懂这几个关键类!

作者: Android 面试官本文将深入源码详细介绍 binder 机制中的以下关键类:ProcessStateIPCThreadStateBpBinderBinderProxybinder 架构介绍之前,先简单回顾下 binder 的整体架构,大致了解这些类的角色。对于一个比较典型的、两个应用之间的 IPC 通信流程而言:Client 通过 ServiceManager 或 AMS 获取到的远程 binder 实体,一般会用 Proxy 做一层封装,比如 ServiceMana.

2020-09-01 20:51:15 30

原创 阿里取消“P”序列职级显示引热议,网友:P3、P4流下了感动的泪水

据36氪报道,阿里巴巴前日取消了内部系统的“P”序列职级显示,员工在邮件、钉钉、内网等系统中已无法再看到彼此的职级,只能看到所属集团部门。这是继阿里取消周报、不鼓励低效加班/会议后,又一大提升组织效率的措施。多位阿里员工表示,此次取消“P”序列职级显示,或与鼓励内部平等沟通有关。对此,阿里巴巴集团公关委员会主席王帅在朋友圈表示:“是的。阿里从来不靠职级管理。但阿里永远要直面未来管理的多元性。”此次变动,也引发了互联网人的热议。有阿里巴巴员工在社交平台表示,阿里巴巴正在淡化层级,能..

2020-09-01 15:51:19 200

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

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

2020-08-31 21:08:41 49

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

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

2020-08-31 20:35:26 46

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

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

2020-08-30 22:36:13 47

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

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

2020-08-30 22:31:42 36

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

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

2020-08-30 22:25:51 56

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

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

2020-08-27 22:06:29 42

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

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

2020-08-27 22:02:21 40

转载 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 35

FreScon源码下载|Fresco源码.rar

FreScon源码下载

2016-06-30

jbox2d愤怒的小鸟游戏源码|愤怒的小鸟游戏源码.zip

jbox2d愤怒的小鸟游戏源码

2016-07-14

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

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 = (TimePickerDialog) getSupportFragmentManager().findFragmentByTag(TIMEPICKER_TAG); if (tpd != null) { tpd.setOnTimeSetListener(this); } } } private boolean isVibrate() { return ((CheckBox) findViewById(R.id.checkBoxVibrate)).isChecked(); } private boolean isCloseOnSingleTapDay() { return ((CheckBox) findViewById(R.id.checkBoxCloseOnSingleTapDay)).isChecked(); } private boolean isCloseOnSingleTapMinute() { return ((CheckBox) findViewById(R.id.checkBoxCloseOnSingleTapMinute)).isChecked(); } @Override public void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day) { Toast.makeText(MainActivity.this, "new date:" + year + "-" + month + "-" + day, Toast.LENGTH_LONG).show(); } @Override public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) { Toast.makeText(MainActivity.this, "new time:" + hourOfDay + "-" + minute, Toast.LENGTH_LONG).show(); } }

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

空空如也

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