Android屏幕适配全攻略(最权威的官方适配指导)

转载:http://blog.csdn.net/zhaokaiqiang1992 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因、重要概念、解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的屏幕适配,你将有所收获! - [Android屏幕适配出现的原因](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#android屏幕适配出现的原因) - [重要概念](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#重要概念) - [屏幕尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕尺寸) - [屏幕分辨率](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕分辨率) - [屏幕像素密度](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#屏幕像素密度) - [dpdipdpisppx](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#dpdipdpisppx) - [mdpihdpixdpixxdpi](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#mdpihdpixdpixxdpi) - [解决方案](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#解决方案) - [支持各种屏幕尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#支持各种屏幕尺寸) - [使用wrap_contentmatch_parentweight](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用wrapcontentmatchparentweight) - [使用相对布局禁用绝对布局](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用相对布局禁用绝对布局) - [使用限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用限定符) - [使用尺寸限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用尺寸限定符) - [使用最小宽度限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用最小宽度限定符) - [使用布局别名](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用布局别名) - [使用屏幕方向限定符](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用屏幕方向限定符) - [使用自动拉伸位图](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用自动拉伸位图) - [支持各种屏幕密度](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#支持各种屏幕密度) - [使用非密度制约像素](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#使用非密度制约像素) - [提供备用位图](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#提供备用位图) - [实施自适应用户界面流程](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#实施自适应用户界面流程) - [确定当前布局](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#确定当前布局) - [根据当前布局做出响应](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#根据当前布局做出响应) - [重复使用其他活动中的片段](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#重复使用其他活动中的片段) - [处理屏幕配置变化](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#处理屏幕配置变化) - [最佳实践](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#最佳实践) - [关于高清设计图尺寸](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#关于高清设计图尺寸) - [ImageView的ScaleType属性](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#imageview的scaletype属性) - [动态设置](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#动态设置) - [更多参考资料](http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023#更多参考资料) Android屏幕适配出现的原因 在我们学习如何进行屏幕适配之前,我们需要先了解下为什么Android需要进行屏幕适配。 由于Android系统的开放性,任何用户、开发者、OEM厂商、运营商都可以对Android进行定制,修改成他们想要的样子。 但是这种“碎片化”到底到达什么程度呢? 在2012年,OpenSignalMaps(以下简称OSM)发布了第一份Android碎片化报告,统计数据表明, 2012年,支持Android的设备共有3997种。 2013年,支持Android的设备共有11868种。 2014年,支持Android的设备共有18796种。 下面这张图片所显示的内容足以充分说明当今Android系统碎片化问题的严重性,因为该图片中的每一个矩形都代表着一种Android设备。 ...

2015年6月6日 · 16 分钟 · 天边的星星

通过 Navigation View 创建导航抽屉

随着 Google I/O 2015,新的 Android Design Support Library 也出现了。 Android Design Support Library 给开发者带来了一些重要的 Material Design 组件,并且向下兼容到 Android 2.1,Navigation View就是其中之一,可用于方便地创建导航抽屉。 效果如下: 因为需要向下兼容,所以以下内容的 Activity 均继承于AppCompatActivity,使用的主题的父主题均为 AppCompat 的主题。 基本步骤 通过Navigation View创建导航抽屉首先自然需要引入这个支持包: compile 'com.android.support:design:22.2.0' 布局文件中加入以下代码: ``` <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <span class="c">&lt;!-- 需要呈现的内容 --&gt;</span> <span class="nt">&lt;android.support.design.widget.NavigationView</span> <span class="na">android:layout_width=</span><span class="s">"wrap_content"</span> <span class="na">android:layout_height=</span><span class="s">"match_parent"</span> <span class="na">android:layout_gravity=</span><span class="s">"start"</span> <span class="na">app:headerLayout=</span><span class="s">"@layout/drawer_header"</span> <span class="na">app:menu=</span><span class="s">"@menu/drawer"</span><span class="nt">/&gt;</span> </android.support.v4.widget.DrawerLayout> </div> 其中`app:headerLayout`用于指定一个任意的布局,作为导航抽屉的顶部,如效果图中的紫色带 Username 字样部分。 而`app:menu`用于指定导航抽屉的菜单项,具体代码如下: <div class="codehilite"> <menu xmlns:android=“http://schemas.android.com/apk/res/android"> <span class="nt">&lt;group</span> <span class="na">android:checkableBehavior=</span><span class="s">"single"</span><span class="nt">&gt;</span> <span class="nt">&lt;item</span> <span class="na">android:id=</span><span class="s">"@+id/nav_home"</span> <span class="na">android:icon=</span><span class="s">"@drawable/ic_dashboard"</span> <span class="na">android:title=</span><span class="s">"Home"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;item</span> <span class="na">android:id=</span><span class="s">"@+id/nav_messages"</span> <span class="na">android:icon=</span><span class="s">"@drawable/ic_event"</span> <span class="na">android:title=</span><span class="s">"Messages"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;item</span> <span class="na">android:id=</span><span class="s">"@+id/nav_friends"</span> <span class="na">android:icon=</span><span class="s">"@drawable/ic_headset"</span> <span class="na">android:title=</span><span class="s">"Friends"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;item</span> <span class="na">android:id=</span><span class="s">"@+id/nav_discussion"</span> <span class="na">android:icon=</span><span class="s">"@drawable/ic_forum"</span> <span class="na">android:title=</span><span class="s">"Discussion"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/group&gt;</span> <span class="nt">&lt;item</span> <span class="na">android:title=</span><span class="s">"Sub items"</span><span class="nt">&gt;</span> <span class="nt">&lt;menu&gt;</span> <span class="nt">&lt;item</span> <span class="na">android:icon=</span><span class="s">"@drawable/ic_dashboard"</span> <span class="na">android:title=</span><span class="s">"Sub item 1"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;item</span> <span class="na">android:icon=</span><span class="s">"@drawable/ic_forum"</span> <span class="na">android:title=</span><span class="s">"Sub item 2"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/menu&gt;</span> <span class="nt">&lt;/item&gt;</span> </menu> ...

2015年6月6日 · 2 分钟 · 天边的星星

Android开发技术周报

教程 在 Android 中使用 data-binder 绑定布局 xml 与数据在前几天的 Google IO 2015 中,Google 在 support-v7 中新增了 data-binder,使用 data-binder 可以直接在布局的 xml 中绑定布局与数据,从而简化代码。因为 data-binder 是包含在 support-v7 包里面的,所以可以向下兼容到最低 Android 2.1 (API level 7+). Android的材料设计兼容库这个兼容库很容易和之前的 Android Support Library 22.1混淆,都是兼容库,区别是这个库多了个Design。 Android Support Library 22.1只是支持了一些基本控件的材料设计化,但是这个库更多的是对一些特效的实现,这个库和github上的很多开源项目是有很大关系的,material design的很多效果,同一种效果在github上有太多的实现,现在官方把部分效果标准化了。 Google I/O 2015 为 Android 开发者带来了哪些福利?先得说的便是,今年的更新有些不给力,至少显得不够 Geek。我也不打算接着盘点一些在 Keynote 中的资讯,想必很多人在各个站点已经看过不知道多少遍了,我接下来想说的一些是关于这次 Google I/O 为 Android 开发者们带来了怎样的福利。 Nexus6 With Android M开启多窗口模式昨天的Google IO之后,Google放出了Android M Preview for Nexus6. 固件大家可以去Google的官网去下,下好了刷完之后,就可以体验一下最新的Android M了。 使用Android Accessibility实现免Root自动批量安装功能对于国内Android设备,应用的自动批量安装/更新一直是一个痛点,在之前,第三方应用商店通常要求设备Root,然后调用系统的PackageManagerService命令行来实现后台安装。最近,豌豆荚利用Android Accessibility(辅助功能)在业内率先实现了免Root自动批量安装功能。 Android 9patch 图片解析堆溢出漏洞分析前谷歌公开了一个今年1月份更新的漏洞。这个漏洞修复了一个存在于Android 5.1版本以下图片渲染的问题,可以查看相关链接。9patch是Android上特有的一种图片格式,就是在普通的png图片的基础了增加了一些像素的边框,使之具有可随意拉伸、缩放的功能。 Gradle 修改 Maven 仓库地址要先说明的是本文说的“渠道”单指在AndroidManifest.xml 用定义的一个标识字符串(如友盟统计)。在代码或者通过其他文件定义的方式殊途同归。说起 Android 多渠道打包,真是八仙过海各显神通:有手动一个个耐心打包的,有用Ant或Maven重复跑编译任务的,有用apktool解包后再修改重打包的,有在build.gradle定义一堆flavor的,乃至有通过apk里META-INF/下的空文件来定义渠道的。 谷歌推荐的技术能力提升指南打好扎实的计算机科学基础对于成为一个成功的软件工程师是非常重要的。本指南主要关于如何提升自己的技术能力,非常适合学生用于制定教学课程,当然这里提供的网络资源,并不意味着就可以完全取代现有的课程,正式的课程安排还是要学的(除非你不想拿到毕业证书)。 Android应用setContentView与LayoutInflater加载解析机制源码分析其实之所以要说这个话题有几个原因:1.理解xml等控件是咋被显示的原理,通常大家写代码都是直接在onCreate里setContentView就完事,没怎么关注其实现原理。2.前面分析《Android触摸屏事件派发机制详解与源码分析三(Activity篇)》时提到了一些关于布局嵌套的问题,当时没有深入解释。 Android应用程序UI硬件加速渲染的预加载资源地图集服务(Asset Atlas Service)分析我们知道,Android系统在启动的时候,会对一些系统资源进行预加载。这样不仅使得应用程序在需要时可以快速地访问这些资源,还使得这些资源能够在不同应用程序之间进行共享。在硬件加速渲染环境中,这些预加载资源还有进一步优化的空间。 Android 不规则封闭区域填充 手指秒变油漆桶图像的填充有2种经典算法。 一种是种子填充法。种子填充法理论上能够填充任意区域和图形,但是这种算法存在大量的反复入栈和大规模的递归,降低了填充效率。 另一种是扫描线填充法。 Android屏幕适配全攻略(最权威的官方适配指导)Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因、重要概念、解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的屏幕适配,你将有所收获! Android系统Root与静默安装静默安装,指的是安装时无需任何用户干预,直接按默认设置安装应用。因为,它的无需用户干预,很多情况下变成了用户压根不知道,应用不知不觉就安装上了。是在推广上极为流氓的手段,很类似PC上的捆绑安装。正因为静默安装时极为流氓的推广行为,所以,其推广价格也极其高。 代码&开源库 cheesesquareAndroid Design library的示例。 Android-NiceTab支持小圆点,背景模糊,图标cross fade等效果的自定义Tab. BGARefreshLayout-Android多种下拉刷新效果、上拉加载更多、可配置自定义头部广告位。 AnimateCheckBox自定义CheckBox,选中未选中的切换动画很赞。 SelectorInjection一个强大的selector注入器,它可以让view自动产生selector状态,免去了你写selector的麻烦。 ShareLoginLib第三方分享登录组件. AndroidGradleTemplateGradle + Android Studio + Robolectric + Espresso + Mockito + EasyMock/PowerMock + JaCoCo Android-Task可以在后台执行Task的Library。 FORMWatchFaceAnddroid Wear 表盘。 MultiThreadDownloader逻辑比较简单但实用的Android多线程断点续传下载器。 DatePickerAndroid日历选择器。 Material Calendar ViewMaterial Design风格的日历控件。 工具 Android Studio 1.3 Preview1The new version contains many new features.: New Allocation Tracker New Heap dump Viewer Many new code inspections to enforce framework and support library threading annotations, range annotations, call super, check result, etc. Missing permission checks and unhandled revocable permission checks Android M preview data binding Support Support for adding Google Services to the project in the project structure dialog (especially for Analytics) SDK update notifications, and brand new integrated SDK manager UI New quickfixes, such as automatic generation of a Parcelable implementation Many built-in live code templates Many other smaller features and bug fixes As announced at Google I/O, Android Studio 1.3 will include C/C++ support as well, but that is not included in the first couple of preview buil * [Android NDK r10e][28]Release Notes: <http://developer.android.com/intl/zh-cn/ndk/downloads/index.html#rel> * [GsonFormat][29]根据Gson库使用的要求,将JSONObject格式的String 解析成实体的 Android Studio 插件。 ### 视频 {#} 1. [Google I/O 2015的各种视频][30]墙内Google I/O 2015的各种视频,没有看的小伙伴赶紧去瞅瞅看吧。 2. [Android QQ音乐架构演进][31]随着移动互联网的不断蓬勃发展,更多用户在移动设备上使用音乐服务,QQ音乐移动客户端使用用户数也在屡创新高,QQ音乐为了达到更好的用户体验并实现用户的新需求,原有的框架已经不能优雅的实现新需求和优先。如何优雅的实现各种需求并在性能和稳定性得到提高,QQ音乐Android开发团队通过以下的篇章给大家分享QQ音乐架构演进带来的痛与乐。 转自:http://androidweekly.cn/android-dev-weekly-issue33/?utm_source=tuicool

2015年6月6日 · 2 分钟 · 天边的星星

Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()

Android中触摸事件传递过程中最重要的是dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()方法。这个是困扰初学者的问题之一,我开始也是。这里记录一下dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()的处理过程,以供记忆。 dispatchTouchEvent是处理触摸事件分发,事件(多数情况)是从Activity的dispatchTouchEvent开始的。执行 super.dispatchTouchEvent(ev),事件向下分发。 onInterceptTouchEvent是ViewGroup提供的方法,默认返回false,返回true表示拦截。 onTouchEvent是View中提供的方法,ViewGroup也有这个方法,view中不提供onInterceptTouchEvent。view中默认返回true,表示消费了这个事件。 View里,有两个回调函数 : **[java]** [view plain](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[copy](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[print](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[?](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219578)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219578/fork) <div> <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="27" height="15" align="middle" name="ZeroClipboardMovie_1"> </embed> </div> </div> - <span class="keyword">public</span> <span class="keyword">boolean</span> dispatchTouchEvent(MotionEvent ev); - <span class="keyword">public</span> <span class="keyword">boolean</span> onTouchEvent(MotionEvent ev); ViewGroup里,有三个回调函数 : **[java]** [view plain](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[copy](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[print](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[?](http://blog.csdn.net/xyz_lmn/article/details/12517911#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/219578)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/219578/fork) <div> <embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="27" height="15" align="middle" name="ZeroClipboardMovie_2"> </embed> </div> </div> - <span class="keyword">public</span> <span class="keyword">boolean</span> dispatchTouchEvent(MotionEvent ev); - <span class="keyword">public</span> <span class="keyword">boolean</span> onInterceptTouchEvent(MotionEvent ev); - <span class="keyword">public</span> <span class="keyword">boolean</span> onTouchEvent(MotionEvent ev); 在Activity里,有两个回调函数 : ...

2015年6月1日 · 1 分钟 · 天边的星星

ScrollView下,ListView生存之道

首先讲一下我遇到的需求吧,页面是这样的,上边有东西,中间是列表,下边还有东西。首先我看到列表立刻就想到了用ListView,但是页面有限,只能用ScrollView包一下。想到就做呗。我就在ScrollView里面加了一个ListView, ListView设置的是wapcontent,这样就出现了ListView数据只显示出了一行。好的,解决问题的方案就来了。 一.设置scrollView中的ListView内容全部显示,不能滑动,将滑动交给scrollView去做。 做法:在设置adapter之前,重新计算ListView的高度,我这里写了一个方法: java代码 [![](http://www.eyeandroid.com/source/plugin/milu_hightLight/help.png)](http://www.eyeandroid.com/) - <span class="comment">/**</span> - <span class="comment">* 动态设置listView的高度</span> - <span class="comment">* count 总条目</span> - <span class="comment">*/</span> - <span class="keyword">private</span> <span class="keyword">void</span> setListViewHeight(ListView listView, BaseAdapter adapter, - <span class="keyword">int</span> count) { - <span class="keyword">int</span> totalHeight = <span class="number"></span>; - <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < count; i++) { - View listItem = adapter.getView(i, <span class="keyword">null</span>, listView); - listItem.measure(<span class="number"></span>, <span class="number"></span>); - totalHeight += listItem.getMeasuredHeight(); - } - - ViewGroup.LayoutParams params = listView.getLayoutParams(); - params.height = totalHeight + (listView.getDividerHeight() * count); - listView.setLayoutParams(params); - } 这样做的前提条件是布局文件中ListView的高度要指定,这样才能重新计算,不要设成wapcontent! ...

2015年6月1日 · 5 分钟 · 天边的星星

ViewStub、include、merge使用与源码分析

在开发中UI布局是我们都会遇到的问题,随着UI越来越多,布局的重复性、复杂度也会随之增长。Android官方给了几个优化的方法,但是网络上的资料基本上都是对官方资料的翻译,这些资料都特别的简单,经常会出现问题而不知其所以然。这篇文章就是对这些问题的更详细的说明,也欢迎大家多留言交流。 一、include 首先用得最多的应该是include,按照官方的意思,include就是为了解决重复定义相同布局的问题。例如你有五个界面,这五个界面的顶部都有布局一模一样的一个返回按钮和一个文本控件,在不使用include的情况下你在每个界面都需要重新在xml里面写同样的返回按钮和文本控件的顶部栏,这样的重复工作会相当的恶心。使用include标签,我们只需要把这个会被多次使用的顶部栏独立成一个xml文件,然后在需要使用的地方通过include标签引入即可。其实就相当于C语言、C++中的include头文件一样,我们把一些常用的、底层的API封装起来,然后复用,需要的时候引入它即可,而不必每次都自己写一遍。示例如下 : my_title_layout.xml `&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:id="@+id/my_title_parent_id" android:layout_height="wrap_content" &gt; &lt;ImageButton android:id="@+id/back_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /&gt; &lt;TextView android:id="@+id/title_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_toRightOf="@+id/back_btn" android:gravity="center" android:text="我的title" android:textSize="18sp" /&gt; &lt;/RelativeLayout&gt; ` include布局文件: `&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" &gt; &lt;include android:id="@+id/my_title_ly" android:layout_width="match_parent" android:layout_height="wrap_content" layout="@layout/my_title_layout" /&gt; &lt;!-- 代码省略 --&gt; &lt;/LinearLayout&gt; ` 这样我们就可以使用my_title_layout了。 ...

2015年5月27日 · 8 分钟 · 天边的星星

android开发中,可能会导致内存泄露的问题

在android编码中,会有一些简便的写法和编码习惯,会导致我们的代码有很多内存泄露的问题。 在这里做一个已知错误的总结(其中有一些是个人总结和参考其他博主的文章,在此表示感谢)。 本文会不定时更新,将自己遇到的内存泄漏相关的问题记录下来并提供解决办法。 1,编写单例的时候常出现的错误。 错误方式: public class Foo{ private static Foo foo; private Context mContext; private Foo(Context mContext){ this.mContext = mContext; } // 普通单例,非线程安全 public static Foo getInstance(Context mContext){ if(foo == null) foo = new Foo(mContext); return foo; } public void otherAction(){ mContext.xxxx(); …. } } 错误原因: 如果我们在Activity A中或者其他地方使用Foo.getInstance()时,我们总是会顺手写一个『this』或者『mContext』(这个变量也是指向this)。试想一下,当前我们所用的Foo是单例,意味着被初始化后会一直存在与内存中,以方便我们以后调用的时候不会在此次创建Foo对象。但Foo中的『mContext』变量一直都会持有Activity A中的『Context』,导致Activity A即使执行了onDestroy方法,也不能够将自己销毁。但『applicationContext』就不同了,它一直伴随着我们应用存在(中途也可能会被销毁,但也会自动reCreate),所以就不用担心Foo中的『mContext』会持有某Activity的引用,让其无法销毁。 正确方式: public class Foo{ private static Foo foo; private Context mContext; private Foo(Context mContext){ this.mContext = mContext; } // 普通单例,非线程安全 public static Foo getInstance(Context mContext){ ...

2015年5月27日 · 2 分钟 · 天边的星星

听FackBook工程师讲Custom ViewGroups

原文链接 : [Custom ViewGroups][1] 原文作者 : [Sriram Ramani][2] Android提供了几个ViewGroups如LinearLayout, RelativeLayout, FrameLayout来固定child Views的位置。在这些普通的ViewGroups中有多种使用选择。 例如:LinearLayout几乎支持HTML Flexbox的所有特性(除了包装)。在view之间你可以选择是否显示分割线(dividers),并且基于最大的child测量所有的children。RelativeLayout是一种限制性的解决方案。这些layouts都已经足够好了,但是当你的UI非常复杂的时候它们还能很好的解决么? ViewGroup with a ProfilePhoto, Title, Subtitle and Menu button. 上面的这种布局在Facebook app中是非常常见的。有头像、其它的view垂直摆在它的右侧、还有一个可选操作的view在最右边。这个布局可以通过使用LinearLayout嵌套或者一个RelativeLayout这样的普通ViewGroup实现。我们看一下当分别使用这两种布局的情况下在measure时会发生什么。 使用LinearLayout完成布局的示例 ``` <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <span class="pl-k">&lt;</span><span class="pl-smi">ProfilePhoto</span> android<span class="pl-k">:</span>layout_width<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>40dp<span class="pl-pds">"</span></span> android<span class="pl-k">:</span>layout_height<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>40dp<span class="pl-pds">"</span></span><span class="pl-k">/</span><span class="pl-k">&gt;</span> <span class="pl-k">&lt;</span><span class="pl-smi">LinearLayout</span> android<span class="pl-k">:</span>layout_width<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>0dp<span class="pl-pds">"</span></span> android<span class="pl-k">:</span>layout_height<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>wrap_content<span class="pl-pds">"</span></span> android<span class="pl-k">:</span>layout_weight<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>1<span class="pl-pds">"</span></span> android<span class="pl-k">:</span>orientation<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>vertical<span class="pl-pds">"</span></span><span class="pl-k">&gt;</span> <span class="pl-k">&lt;</span><span class="pl-smi">Title</span> android<span class="pl-k">:</span>layout_width<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>match_parent<span class="pl-pds">"</span></span> android<span class="pl-k">:</span>layout_height<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>wrap_content<span class="pl-pds">"</span></span><span class="pl-k">/</span><span class="pl-k">&gt;</span> <span class="pl-k">&lt;</span><span class="pl-smi">Subtitle</span> android<span class="pl-k">:</span>layout_width<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>match_parent<span class="pl-pds">"</span></span> android<span class="pl-k">:</span>layout_height<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>wrap_content<span class="pl-pds">"</span></span><span class="pl-k">/</span><span class="pl-k">&gt;</span> <span class="pl-k">&lt;</span><span class="pl-k">/</span><span class="pl-smi">LinearLayout</span><span class="pl-k">&gt;</span> <span class="pl-k">&lt;</span><span class="pl-smi">Menu</span> android<span class="pl-k">:</span>layout_width<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>20dp<span class="pl-pds">"</span></span> android<span class="pl-k">:</span>layout_height<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>20dp<span class="pl-pds">"</span></span><span class="pl-k">/</span><span class="pl-k">&gt;</span> </LinearLayout> ...

2015年5月27日 · 5 分钟 · 天边的星星

Android WebView 总结

1、添加权限:AndroidManifest.xml中必须使用许可”android.permission.INTERNET”,否则会出Web page not available错误。 2、在要Activity中生成一个WebView组件:WebView webView = new WebView(this); 3、设置WebView基本信息: 如果访问的页面中有Javascript,则webview必须设置支持Javascript。 webview.getSettings().setJavaScriptEnabled(true); 触摸焦点起作用 requestFocus(); 取消滚动条 this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY); 4、设置WevView要显示的网页: 互联网用:webView.loadUrl(“http://www.google.com”); 本地文件用:webView.loadUrl(“file:///android_asset/XX.html”); 本地文件存放在:assets文件中 5、如果希望点击链接由自己处理,而不是新开Android的系统browser中响应该链接。 给WebView添加一个事件监听对象(WebViewClient) 并重写其中的一些方法 shouldOverrideUrlLoading:对网页中超链接按钮的响应。 当按下某个连接时WebViewClient会调用这个方法,并传递参数:按下的url onLoadResource onPageStart onPageFinish onReceiveError onReceivedHttpAuthRequest 6、如果用webview点链接看了很多页以后,如果不做任何处理,点击系统“Back”键,整个浏览器会调用finish()而结束自身,如果希望浏览的网页回退而不是退出浏览器,需要在当前Activity中处理并消费掉该Back事件。 覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法。 [?](http://www.oschina.net/question/163910_26516#) <table border="0" cellspacing="0" cellpadding="0"> <tr> <td class="gutter"> <div class="line number1 index0 alt2"> 1 </div> <div class="line number2 index1 alt1"> 2 </div> <div class="line number3 index2 alt2"> 3 </div> <div class="line number4 index3 alt1"> 4 </div> <div class="line number5 index4 alt2"> 5 </div> <div class="line number6 index5 alt1"> 6 </div> <div class="line number7 index6 alt2"> 7 </div> <div class="line number8 index7 alt1"> 8 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `public` `boolean` `onKeyDown(``int` `keyCoder,KeyEvent event){` </div> <div class="line number2 index1 alt1"> ` ``if``(webView.canGoBack() && keyCoder == KeyEvent.KEYCODE_BACK){` </div> <div class="line number3 index2 alt2"> ` ``webview.goBack(); ``//goBack()表示返回webView的上一页面` </div> <div class="line number4 index3 alt1"> </div> <div class="line number5 index4 alt2"> ` ``return` `true``;` </div> <div class="line number6 index5 alt1"> ` ``}` </div> <div class="line number7 index6 alt2"> ` ``return` `false``;` </div> <div class="line number8 index7 alt1"> `}` </div> </div> </td> </tr> </table> &nbsp; ### Android监听WebView滑动到底部 MainActivity如下: <div> <div id="highlighter_5859" class="syntaxhighlighter java"> <div class="toolbar"> [?](http://www.open-open.com/lib/view/open1379383341959.html#) </div> <table border="0" cellspacing="0" cellpadding="0"> <tr> <td class="gutter"> <div class="line number1 index0 alt2"> 1 </div> <div class="line number2 index1 alt1"> 2 </div> <div class="line number3 index2 alt2"> 3 </div> <div class="line number4 index3 alt1"> 4 </div> <div class="line number5 index4 alt2"> 5 </div> <div class="line number6 index5 alt1"> 6 </div> <div class="line number7 index6 alt2"> 7 </div> <div class="line number8 index7 alt1"> 8 </div> <div class="line number9 index8 alt2"> 9 </div> <div class="line number10 index9 alt1"> 10 </div> <div class="line number11 index10 alt2"> 11 </div> <div class="line number12 index11 alt1"> 12 </div> <div class="line number13 index12 alt2"> 13 </div> <div class="line number14 index13 alt1"> 14 </div> <div class="line number15 index14 alt2"> 15 </div> <div class="line number16 index15 alt1"> 16 </div> <div class="line number17 index16 alt2"> 17 </div> <div class="line number18 index17 alt1"> 18 </div> <div class="line number19 index18 alt2"> 19 </div> <div class="line number20 index19 alt1"> 20 </div> <div class="line number21 index20 alt2"> 21 </div> <div class="line number22 index21 alt1"> 22 </div> <div class="line number23 index22 alt2"> 23 </div> <div class="line number24 index23 alt1"> 24 </div> <div class="line number25 index24 alt2"> 25 </div> <div class="line number26 index25 alt1"> 26 </div> <div class="line number27 index26 alt2"> 27 </div> <div class="line number28 index27 alt1"> 28 </div> <div class="line number29 index28 alt2"> 29 </div> <div class="line number30 index29 alt1"> 30 </div> <div class="line number31 index30 alt2"> 31 </div> <div class="line number32 index31 alt1"> 32 </div> <div class="line number33 index32 alt2"> 33 </div> <div class="line number34 index33 alt1"> 34 </div> <div class="line number35 index34 alt2"> 35 </div> <div class="line number36 index35 alt1"> 36 </div> <div class="line number37 index36 alt2"> 37 </div> <div class="line number38 index37 alt1"> 38 </div> <div class="line number39 index38 alt2"> 39 </div> <div class="line number40 index39 alt1"> 40 </div> <div class="line number41 index40 alt2"> 41 </div> <div class="line number42 index41 alt1"> 42 </div> <div class="line number43 index42 alt2"> 43 </div> <div class="line number44 index43 alt1"> 44 </div> <div class="line number45 index44 alt2"> 45 </div> <div class="line number46 index45 alt1"> 46 </div> <div class="line number47 index46 alt2"> 47 </div> <div class="line number48 index47 alt1"> 48 </div> <div class="line number49 index48 alt2"> 49 </div> <div class="line number50 index49 alt1"> 50 </div> <div class="line number51 index50 alt2"> 51 </div> <div class="line number52 index51 alt1"> 52 </div> <div class="line number53 index52 alt2"> 53 </div> <div class="line number54 index53 alt1"> 54 </div> <div class="line number55 index54 alt2"> 55 </div> <div class="line number56 index55 alt1"> 56 </div> <div class="line number57 index56 alt2"> 57 </div> <div class="line number58 index57 alt1"> 58 </div> <div class="line number59 index58 alt2"> 59 </div> <div class="line number60 index59 alt1"> 60 </div> <div class="line number61 index60 alt2"> 61 </div> <div class="line number62 index61 alt1"> 62 </div> <div class="line number63 index62 alt2"> 63 </div> <div class="line number64 index63 alt1"> 64 </div> <div class="line number65 index64 alt2"> 65 </div> <div class="line number66 index65 alt1"> 66 </div> <div class="line number67 index66 alt2"> 67 </div> <div class="line number68 index67 alt1"> 68 </div> <div class="line number69 index68 alt2"> 69 </div> <div class="line number70 index69 alt1"> 70 </div> <div class="line number71 index70 alt2"> 71 </div> <div class="line number72 index71 alt1"> 72 </div> <div class="line number73 index72 alt2"> 73 </div> <div class="line number74 index73 alt1"> 74 </div> <div class="line number75 index74 alt2"> 75 </div> <div class="line number76 index75 alt1"> 76 </div> <div class="line number77 index76 alt2"> 77 </div> <div class="line number78 index77 alt1"> 78 </div> <div class="line number79 index78 alt2"> 79 </div> <div class="line number80 index79 alt1"> 80 </div> <div class="line number81 index80 alt2"> 81 </div> <div class="line number82 index81 alt1"> 82 </div> <div class="line number83 index82 alt2"> 83 </div> <div class="line number84 index83 alt1"> 84 </div> <div class="line number85 index84 alt2"> 85 </div> <div class="line number86 index85 alt1"> 86 </div> <div class="line number87 index86 alt2"> 87 </div> <div class="line number88 index87 alt1"> 88 </div> <div class="line number89 index88 alt2"> 89 </div> <div class="line number90 index89 alt1"> 90 </div> <div class="line number91 index90 alt2"> 91 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `package` `cn.testwebview;` </div> <div class="line number2 index1 alt1"> `import` `android.app.Activity;` </div> <div class="line number3 index2 alt2"> `import` `android.graphics.Bitmap;` </div> <div class="line number4 index3 alt1"> `import` `android.os.Bundle;` </div> <div class="line number5 index4 alt2"> `import` `android.webkit.WebSettings;` </div> <div class="line number6 index5 alt1"> `import` `android.webkit.WebView;` </div> <div class="line number7 index6 alt2"> `import` `android.webkit.WebViewClient;` </div> <div class="line number8 index7 alt1"> `import` `cn.testwebview.TestWebView.ScrollInterface;` </div> <div class="line number9 index8 alt2"> `/**` </div> <div class="line number10 index9 alt1"> ` ``* Demo描述:` </div> <div class="line number11 index10 alt2"> ` ``* 监听WebView滑动到底部` </div> <div class="line number12 index11 alt1"> ` ``*` </div> <div class="line number13 index12 alt2"> ` ``* 参考资料:` </div> <div class="line number14 index13 alt1"> ` ``* 1 http://blog.csdn.net/conant1989/article/details/8124582` </div> <div class="line number15 index14 alt2"> ` ``* Thank you very much` </div> <div class="line number16 index15 alt1"> ` ``*/` </div> <div class="line number17 index16 alt2"> `public` `class` `MainActivity ``extends` `Activity {` </div> <div class="line number18 index17 alt1"> ` ``private` `TestWebView mTestWebView;` </div> <div class="line number19 index18 alt2"> ` ``@Override` </div> <div class="line number20 index19 alt1"> ` ``protected` `void` `onCreate(Bundle savedInstanceState) {` </div> <div class="line number21 index20 alt2"> ` ``super``.onCreate(savedInstanceState);` </div> <div class="line number22 index21 alt1"> ` ``setContentView(R.layout.main);` </div> <div class="line number23 index22 alt2"> ` ``initWebView();` </div> <div class="line number24 index23 alt1"> ` ``}` </div> <div class="line number25 index24 alt2"> ` ` </div> <div class="line number26 index25 alt1"> ` ` </div> <div class="line number27 index26 alt2"> ` ` </div> <div class="line number28 index27 alt1"> ` ``//设置WebView` </div> <div class="line number29 index28 alt2"> ` ``private` `void` `initWebView() {` </div> <div class="line number30 index29 alt1"> ` ``mTestWebView = (TestWebView) findViewById(R.id.webView);` </div> <div class="line number31 index30 alt2"> ` ``mTestWebView.setVerticalScrollBarEnabled(``true``);` </div> <div class="line number32 index31 alt1"> ` ``mTestWebView.setHorizontalScrollBarEnabled(``false``);` </div> <div class="line number33 index32 alt2"> ` ``mTestWebView.getSettings().setSupportZoom(``true``);` </div> <div class="line number34 index33 alt1"> ` ``mTestWebView.getSettings().setBuiltInZoomControls(``true``);` </div> <div class="line number35 index34 alt2"> ` ``mTestWebView.getSettings().setJavaScriptEnabled(``true``);` </div> <div class="line number36 index35 alt1"> ` ` </div> <div class="line number37 index36 alt2"> ` ``mTestWebView.getSettings().setDomStorageEnabled(``true``);` </div> <div class="line number38 index37 alt1"> ` ``mTestWebView.getSettings().setPluginsEnabled(``true``);` </div> <div class="line number39 index38 alt2"> ` ``mTestWebView.requestFocus();` </div> <div class="line number40 index39 alt1"> ` ` </div> <div class="line number41 index40 alt2"> ` ``mTestWebView.getSettings().setUseWideViewPort(``true``);` </div> <div class="line number42 index41 alt1"> ` ``mTestWebView.getSettings().setLoadWithOverviewMode(``true``);` </div> <div class="line number43 index42 alt2"> ` ``mTestWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);` </div> <div class="line number44 index43 alt1"> ` ` </div> <div class="line number45 index44 alt2"> ` ``mTestWebView.loadUrl(``"http://www.ifeng.com"``);` </div> <div class="line number46 index45 alt1"> ` ``mTestWebView.setWebViewClient(``new` `TestWebViewClient());` </div> <div class="line number47 index46 alt2"> ` ``webViewScroolChangeListener();` </div> <div class="line number48 index47 alt1"> ` ` </div> <div class="line number49 index48 alt2"> ` ``}` </div> <div class="line number50 index49 alt1"> ` ` </div> <div class="line number51 index50 alt2"> ` ``//核心代码` </div> <div class="line number52 index51 alt1"> ` ``private` `void` `webViewScroolChangeListener() {` </div> <div class="line number53 index52 alt2"> ` ``mTestWebView.setOnCustomScroolChangeListener(``new` `ScrollInterface() {` </div> <div class="line number54 index53 alt1"> ` ``@Override` </div> <div class="line number55 index54 alt2"> ` ``public` `void` `onSChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt) {` </div> <div class="line number56 index55 alt1"> ` ``//WebView的总高度` </div> <div class="line number57 index56 alt2"> ` ``float` `webViewContentHeight=mTestWebView.getContentHeight() * mTestWebView.getScale();` </div> <div class="line number58 index57 alt1"> ` ``//WebView的现高度` </div> <div class="line number59 index58 alt2"> ` ``float` `webViewCurrentHeight=(mTestWebView.getHeight() + mTestWebView.getScrollY());` </div> <div class="line number60 index59 alt1"> ` ``System.out.println(``"webViewContentHeight="``+webViewContentHeight);` </div> <div class="line number61 index60 alt2"> ` ``System.out.println(``"webViewCurrentHeight="``+webViewCurrentHeight);` </div> <div class="line number62 index61 alt1"> ` ``if` `((webViewContentHeight-webViewCurrentHeight) == ````) {` </div> <div class="line number63 index62 alt2"> ` ``System.out.println(``"WebView滑动到了底端"``);` </div> <div class="line number64 index63 alt1"> ` ``}` </div> <div class="line number65 index64 alt2"> ` ``}` </div> <div class="line number66 index65 alt1"> ` ``});` </div> <div class="line number67 index66 alt2"> ` ``}` </div> <div class="line number68 index67 alt1"> ` ` </div> <div class="line number69 index68 alt2"> </div> <div class="line number70 index69 alt1"> ` ``private` `class` `TestWebViewClient ``extends` `WebViewClient{` </div> <div class="line number71 index70 alt2"> ` ``@Override` </div> <div class="line number72 index71 alt1"> ` ``public` `void` `onPageStarted(WebView view, String url, Bitmap favicon) {` </div> <div class="line number73 index72 alt2"> ` ``super``.onPageStarted(view, url, favicon);` </div> <div class="line number74 index73 alt1"> ` ``}` </div> <div class="line number75 index74 alt2"> ` ``@Override` </div> <div class="line number76 index75 alt1"> ` ``public` `boolean` `shouldOverrideUrlLoading(WebView view, String url) {` </div> <div class="line number77 index76 alt2"> ` ``view.loadUrl(url);` </div> <div class="line number78 index77 alt1"> ` ``return` `true``;` </div> <div class="line number79 index78 alt2"> ` ``}` </div> <div class="line number80 index79 alt1"> ` ``@Override` </div> <div class="line number81 index80 alt2"> ` ``public` `void` `onPageFinished(WebView view, String url) {` </div> <div class="line number82 index81 alt1"> ` ``super``.onPageFinished(view, url);` </div> <div class="line number83 index82 alt2"> ` ` </div> <div class="line number84 index83 alt1"> ` ``}` </div> <div class="line number85 index84 alt2"> ` ``@Override` </div> <div class="line number86 index85 alt1"> ` ``public` `void` `onReceivedError(WebView view, ``int` `errorCode,String description, String failingUrl) {` </div> <div class="line number87 index86 alt2"> ` ``super``.onReceivedError(view, errorCode, description, failingUrl);` </div> <div class="line number88 index87 alt1"> ` ``}` </div> <div class="line number89 index88 alt2"> ` ``}` </div> <div class="line number90 index89 alt1"> ` ` </div> <div class="line number91 index90 alt2"> `}` </div> </div> </td> </tr> </table> </div> </div> TestWebView如下: <div> <div id="highlighter_625536" class="syntaxhighlighter java"> <div class="toolbar"> [?](http://www.open-open.com/lib/view/open1379383341959.html#) </div> <table border="0" cellspacing="0" cellpadding="0"> <tr> <td class="gutter"> <div class="line number1 index0 alt2"> 1 </div> <div class="line number2 index1 alt1"> 2 </div> <div class="line number3 index2 alt2"> 3 </div> <div class="line number4 index3 alt1"> 4 </div> <div class="line number5 index4 alt2"> 5 </div> <div class="line number6 index5 alt1"> 6 </div> <div class="line number7 index6 alt2"> 7 </div> <div class="line number8 index7 alt1"> 8 </div> <div class="line number9 index8 alt2"> 9 </div> <div class="line number10 index9 alt1"> 10 </div> <div class="line number11 index10 alt2"> 11 </div> <div class="line number12 index11 alt1"> 12 </div> <div class="line number13 index12 alt2"> 13 </div> <div class="line number14 index13 alt1"> 14 </div> <div class="line number15 index14 alt2"> 15 </div> <div class="line number16 index15 alt1"> 16 </div> <div class="line number17 index16 alt2"> 17 </div> <div class="line number18 index17 alt1"> 18 </div> <div class="line number19 index18 alt2"> 19 </div> <div class="line number20 index19 alt1"> 20 </div> <div class="line number21 index20 alt2"> 21 </div> <div class="line number22 index21 alt1"> 22 </div> <div class="line number23 index22 alt2"> 23 </div> <div class="line number24 index23 alt1"> 24 </div> <div class="line number25 index24 alt2"> 25 </div> <div class="line number26 index25 alt1"> 26 </div> <div class="line number27 index26 alt2"> 27 </div> <div class="line number28 index27 alt1"> 28 </div> <div class="line number29 index28 alt2"> 29 </div> <div class="line number30 index29 alt1"> 30 </div> <div class="line number31 index30 alt2"> 31 </div> <div class="line number32 index31 alt1"> 32 </div> <div class="line number33 index32 alt2"> 33 </div> <div class="line number34 index33 alt1"> 34 </div> <div class="line number35 index34 alt2"> 35 </div> <div class="line number36 index35 alt1"> 36 </div> <div class="line number37 index36 alt2"> 37 </div> <div class="line number38 index37 alt1"> 38 </div> <div class="line number39 index38 alt2"> 39 </div> <div class="line number40 index39 alt1"> 40 </div> <div class="line number41 index40 alt2"> 41 </div> <div class="line number42 index41 alt1"> 42 </div> <div class="line number43 index42 alt2"> 43 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `package` `cn.testwebview;` </div> <div class="line number2 index1 alt1"> </div> <div class="line number3 index2 alt2"> `import` `android.content.Context;` </div> <div class="line number4 index3 alt1"> `import` `android.util.AttributeSet;` </div> <div class="line number5 index4 alt2"> `import` `android.webkit.WebView;` </div> <div class="line number6 index5 alt1"> </div> <div class="line number7 index6 alt2"> `public` `class` `TestWebView ``extends` `WebView {` </div> <div class="line number8 index7 alt1"> ` ``public` `ScrollInterface mScrollInterface;` </div> <div class="line number9 index8 alt2"> </div> <div class="line number10 index9 alt1"> ` ``public` `TestWebView(Context context) {` </div> <div class="line number11 index10 alt2"> ` ``super``(context);` </div> <div class="line number12 index11 alt1"> ` ``}` </div> <div class="line number13 index12 alt2"> </div> <div class="line number14 index13 alt1"> ` ``public` `TestWebView(Context context, AttributeSet attrs, ``int` `defStyle) {` </div> <div class="line number15 index14 alt2"> ` ``super``(context, attrs, defStyle);` </div> <div class="line number16 index15 alt1"> ` ``}` </div> <div class="line number17 index16 alt2"> </div> <div class="line number18 index17 alt1"> ` ``public` `TestWebView(Context context, AttributeSet attrs) {` </div> <div class="line number19 index18 alt2"> ` ``super``(context, attrs);` </div> <div class="line number20 index19 alt1"> ` ``}` </div> <div class="line number21 index20 alt2"> </div> <div class="line number22 index21 alt1"> ` ``@Override` </div> <div class="line number23 index22 alt2"> ` ``protected` `void` `onScrollChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt) {` </div> <div class="line number24 index23 alt1"> </div> <div class="line number25 index24 alt2"> ` ``super``.onScrollChanged(l, t, oldl, oldt);` </div> <div class="line number26 index25 alt1"> </div> <div class="line number27 index26 alt2"> ` ``mScrollInterface.onSChanged(l, t, oldl, oldt);` </div> <div class="line number28 index27 alt1"> </div> <div class="line number29 index28 alt2"> ` ``}` </div> <div class="line number30 index29 alt1"> </div> <div class="line number31 index30 alt2"> ` ``public` `void` `setOnCustomScroolChangeListener(ScrollInterface scrollInterface) {` </div> <div class="line number32 index31 alt1"> </div> <div class="line number33 index32 alt2"> ` ``this``.mScrollInterface = scrollInterface;` </div> <div class="line number34 index33 alt1"> </div> <div class="line number35 index34 alt2"> ` ``}` </div> <div class="line number36 index35 alt1"> </div> <div class="line number37 index36 alt2"> ` ``public` `interface` `ScrollInterface {` </div> <div class="line number38 index37 alt1"> </div> <div class="line number39 index38 alt2"> ` ``public` `void` `onSChanged(``int` `l, ``int` `t, ``int` `oldl, ``int` `oldt);` </div> <div class="line number40 index39 alt1"> </div> <div class="line number41 index40 alt2"> ` ``}` </div> <div class="line number42 index41 alt1"> </div> <div class="line number43 index42 alt2"> `}` </div> </div> </td> </tr> </table> </div> </div> &nbsp; main.xml如下: <div> <div id="highlighter_380669" class="syntaxhighlighter xml"> <div class="toolbar"> [?](http://www.open-open.com/lib/view/open1379383341959.html#) </div> <table border="0" cellspacing="0" cellpadding="0"> <tr> <td class="gutter"> <div class="line number1 index0 alt2"> 1 </div> <div class="line number2 index1 alt1"> 2 </div> <div class="line number3 index2 alt2"> 3 </div> <div class="line number4 index3 alt1"> 4 </div> <div class="line number5 index4 alt2"> 5 </div> <div class="line number6 index5 alt1"> 6 </div> <div class="line number7 index6 alt2"> 7 </div> <div class="line number8 index7 alt1"> 8 </div> <div class="line number9 index8 alt2"> 9 </div> <div class="line number10 index9 alt1"> 10 </div> <div class="line number11 index10 alt2"> 11 </div> <div class="line number12 index11 alt1"> 12 </div> <div class="line number13 index12 alt2"> 13 </div> <div class="line number14 index13 alt1"> 14 </div> <div class="line number15 index14 alt2"> 15 </div> <div class="line number16 index15 alt1"> 16 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `&lt;``RelativeLayout` </div> <div class="line number2 index1 alt1"> ` ``xmlns:android``=``"http://schemas.android.com/apk/res/android"` </div> <div class="line number3 index2 alt2"> ` ``xmlns:tools``=``"http://schemas.android.com/tools"` </div> <div class="line number4 index3 alt1"> ` ``android:layout_width``=``"match_parent"` </div> <div class="line number5 index4 alt2"> ` ``android:layout_height``=``"match_parent"` </div> <div class="line number6 index5 alt1"> ` ``&gt;` </div> <div class="line number7 index6 alt2"> </div> <div class="line number8 index7 alt1"> ` ``&lt;``cn.testwebview.TestWebView` </div> <div class="line number9 index8 alt2"> ` ``android:id``=``"@+id/webView"` </div> <div class="line number10 index9 alt1"> ` ``android:layout_width``=``"fill_parent"` </div> <div class="line number11 index10 alt2"> ` ``android:layout_height``=``"fill_parent"` </div> <div class="line number12 index11 alt1"> ` ``android:text``=``"@string/hello_world"` </div> <div class="line number13 index12 alt2"> ` ``android:layout_centerInParent``=``"true"` </div> <div class="line number14 index13 alt1"> ` ``/&gt;` </div> <div class="line number15 index14 alt2"> </div> <div class="line number16 index15 alt1"> `&lt;/``RelativeLayout``&gt;` </div> </div> </td> </tr> </table> </div> </div> &nbsp; </div>

2015年5月25日 · 13 分钟 · 天边的星星

Android大图片裁剪终极解决方案(上:原理分析)

约几个月前,我正为公司的APP在Android手机上实现拍照截图而烦恼不已。 上网搜索,确实有不少的例子,大多都是抄来抄去,而且水平多半处于demo的样子,可以用来讲解知识点,但是一碰到实际项目,就漏洞百出。 当时我用大众化的解决方案,暂时性的做了一个拍照截图的功能,似乎看起来很不错。问题随之而来,我用的是小米手机,在别的手机上都运行正常,小米这里却总是碰钉子。虽然我是个理性的米粉,但是也暗地里把小米的工程师问候了个遍。真是惭愧! 翻文档也找不出个答案来,我一直对com.android.camera.action.CROP持有大大的疑问,它是从哪里来,它能干什么,它接收处理什么类型的数据?Google对此却讳莫如深,在官方文档中只有Intent中有只言片语言及,却不甚详尽。 随着项目的驱动,我不能抱着不了解原理就不往前走的心态,唯一要做的,是解决问题。最后在德问上找到一条解决方案,说是哪怕是大米也没问题。当时乐呵呵将代码改了改,确实在所有的手机上跑起来了,一时如释重负,对这个的疑问也抛诸脑后了。 直到月前,BOSS要求将拍照上传到服务器的图片分辨率加倍。OK,加倍简单,增加outputX以及outputY不就得了? `1` <td class="content"> `intent.putExtra(``"outputX"``, outputX);` </td> </tr> </table> </div> <div class="line alt2"> <table> <tr> <td class="number"> `2` </td> <td class="content"> `intent.putExtra(``"outputY"``, outputY);` </td> </tr> </table> </div> 这一增加,吓了我一跳。BOSS的手机拍到的照片几乎就是个缩略图,但是被我问候了全体工程师的小米在这个时候就体现出国产神机的范儿了,小米上的尺寸一切正常。这个为什么呢?我大致了解原因,却不知道如何解决。 在Android中,Intent触发Camera程序,拍好照片后,将会返回数据,但是考虑到内存问题,Camera不会将全尺寸的图像返回给调用的Activity,一般情况下,有可能返回的是缩略图,比如120*160px。 这是为什么呢?这不是一个Bug,而是经过精心设计的,却对开发者不透明。 以我的小米手机为例,摄像头800W像素,根据我目前设置拍出来的图片尺寸为3200*2400px。有人说,那就返回呗,大不了耗1-2M的内存,不错,这个尺寸的图片确实只有1.8M左右的大小。但是你想不到的是,这个尺寸对应的Bitmap会耗光你应用程序的所有内存。Android出于安全性考虑,只会给你一个寒碜的缩略图。 在Android2.3中,默认的Bitmap为32位,类型是ARGB_8888,也就意味着一个像素点占用4个字节的内存。我们来做一个简单的计算题:3200*2400*4 bytes = 30M。 如此惊人的数字!哪怕你愿意为一张生命周期超不过10s的位图愿意耗费这么巨大的内存,Android也不会答应的。 `1` <td class="content"> `Mobile devices typically have constrained system resources.` </td> </tr> </table> </div> <div class="line alt2"> <table> <tr> <td class="number"> `2` </td> <td class="content"> `Android devices can have as little as 16MB of memory available to a single application.` </td> </tr> </table> </div> 这是Android Doc的原文,虽然不同手机系统的厂商可能围绕16M这个数字有微微的上调,但是这30M,一般的手机还真挥霍不起。也只有小米这种牛机,内存堪比个人PC,本着土财主般挥金如土的霸气才能做到。 ...

2015年5月23日 · 10 分钟 · 天边的星星