Android 6.0 运行时权限处理

运行时权限介绍 Android 6.0在我们原有的AndroidManifest.xml声明权限的基础上,又新增了运行时权限动态检测,以下权限都需要在运行时判断: 身体传感器 日历 摄像头 通讯录 地理位置 麦克风 电话 短信 存储空间 运行时权限处理 Android6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限,所以如果你以前的APP设置的targetSdkVersion低于23,在运行时也不会崩溃,但这也只是一个临时的救急策略,用户还是可以在设置中取消授予的权限。 声明目标SDK版本 我们需要在build.gradle中声明targetSdkVersion为23 android { compileSdkVersion 23 buildToolsVersion "23.0.1" defaultConfig { applicationId "com.yourcomany.app minSdkVersion 18 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } 检查并申请权限 我们需要在用到权限的地方,每次都检查是否APP已经拥有权限,比如我们有一个下载功能,需要写SD卡的权限,我们在写入之前检查是否有WRITE_EXTERNAL_STORAGE权限,没有则申请权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { //申请WRITE_EXTERNAL_STORAGE权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST_CODE); } 请求权限后,系统会弹出请求权限的Dialog ...

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

美团Android DEX自动拆包及动态加载简介

概述 作为一个android开发者,在开发应用时,随着业务规模发展到一定程度,不断地加入新功能、添加新的类库,代码在急剧的膨胀,相应的apk包的大小也急剧增加, 那么终有一天,你会不幸遇到这个错误: 生成的apk在android 2.3或之前的机器上无法安装,提示INSTALL_FAILED_DEXOPT 方法数量过多,编译时出错,提示: Conversion to Dalvik format failed:Unable to execute dex: method ID not in [0, 0xffff]: 65536 而问题产生的具体原因如下: 无法安装(Android 2.3 INSTALL_FAILED_DEXOPT)问题,是由dexopt的LinearAlloc限制引起的,在Android版本不同分别经历了4M/5M/8M/16M限制,目前主流4.2.x系统上可能都已到16M, 在Gingerbread或者以下系统LinearAllocHdr分配空间只有5M大小的, 高于Gingerbread的系统提升到了8M。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中,系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB,Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时,会造成dexopt崩溃。 超过最大方法数限制的问题,是由于DEX文件格式限制,一个DEX文件中method个数采用使用原生类型short来索引文件中的方法,也就是4个字节共计最多表达65536个method,field/class的个数也均有此限制。对于DEX文件,则是将工程所需全部class文件合并且压缩到一个DEX文件期间,也就是Android打包的DEX过程中, 单个DEX文件可被引用的方法总数(自己开发的代码以及所引用的Android框架、类库的代码)被限制为65536; 插件化? MultiDex? 解决这个问题,一般有下面几种方案,一种方案是加大Proguard的力度来减小DEX的大小和方法数,但这是治标不治本的方案,随着业务代码的添加,方法数终究会到达这个限制,一种比较流行的方案是插件化方案,另外一种是采用google提供的MultiDex方案,以及google在推出MultiDex之前Android Developers博客介绍的通过自定义类加载过程, 再就是Facebook推出的为Android应用开发的Dalvik补丁, 但facebook博客里写的不是很详细;我们在插件化方案上也做了探索和尝试,发现部署插件化方案,首先需要梳理和修改各个业务线的代码,使之解耦,改动的面和量比较巨大,通过一定的探讨和分析,我们认为对我们目前来说采用MultiDex方案更靠谱一些,这样我们可以快速和简洁的对代码进行拆分,同时代码改动也在可以接受的范围内; 这样我们采用了google提供的MultiDex方式进行了开发。 插件化方案在业内有不同的实现原理,这里不再一一列举,这里只列举下Google为构建超过65K方法数的应用提供官方支持的方案:MultiDex。 首先使用Android SDK Manager升级到最新的Android SDK Build Tools和Android Support Library。然后进行以下两步操作: 1.修改Gradle配置文件,启用MultiDex并包含MultiDex支持: android { compileSdkVersion 21 buildToolsVersion "21.1.0" defaultConfig { ... minSdkVersion 14 targetSdkVersion 21 ... // Enabling MultiDex support. MultiDexEnabled true } ... } dependencies { compile 'com.android.support:MultiDex:1.0.0' } 2.让应用支持多DEX文件。在官方文档中描述了三种可选方法: ...

2015年11月12日 · 4 分钟 · 天边的星星

美团Android资源混淆保护实践

前言 Android应用中的APK安全性一直遭人诟病,市面上充斥着各种被破解或者汉化的应用,破解者可以非常简单的通过破解工具就能对一个APK进行反编译、破解、汉化等等,这样就可以修改原有代码的逻辑、添加新代码、添加或修改资源、或者更有甚者植入病毒等等,从而破坏原有APK的安全和用户体验,最终伤害到用户和原有的开发者。 而事物都是有两方面的,有矛就有盾,针对Android应用安全的各种方案应运而生,大家比较熟悉一般是各类加壳加固的工具,我们可以使用这些工具来保护我们的APK,加壳加固是另外一个话题了,我们这里不对加壳加固进行介绍,后续如果有机会会单独开一个话题讨论,我们在开发过程中可以通过ProGuard或者DexGuard来保护我们的代码,从而实现相对的代码安全,但我们的资源呢?我们往往忽略对资源文件的保护,那这里将要分享的是如果采用常规方式对APK中的资源文件进行保护。 资源安全 资源安全这个话题目前大家关注度不算太高,相比较而言大家更关注代码安全,目前市面上各类APP基本都使用了ProGuard来保护代码的安全,但对资源文件的保护力度都不大,其实资源文件是存在比较大的安全隐患,那资源会有哪些安全隐患呢?下面我们通过一个比较简单的例子来说明下保护资源文件的重要性。 我们先用最常见的apktool工具来反编译一个应用来看看,通过运行下面命令就能进行反编译; apktool d -s xxx.apk 反编译成功后我们来看下反编译得到的文件结构(见下图); 通过上图中的目录结构,我们可以看到这个应用的资源文件大概有:anim、drawable、layout、menu、values等等,我们可以通过修改这些文件夹下的资源文件,并通过apktool进行回编译(apktool b 命令)就能创建一个经过修改过的APK应用,例如我们修改下图中红色横线所标示的layout文件,就能往原有APK的支付信息(根据资源名称猜测这个layout的意图)中添加一些我们自己的东西; 这个问题主要是因为我们在开发过程中倡导命名的规范性,一般都要求在命名时做到见名知意,这样能够方便我们自己的理解和维护,但同时这也方便了破解者,破解者可以轻松的根据文件名称来猜测这个文件的意图和作用,从而做破坏性的修改。 通过这个例子我们可以看出目前资源安全的重要性,那如何做到资源安全呢?安全都是相对的,没有绝对的安全,我们接下来要讨论的是类似Proguard方式的对我们的资源进行保护。我们主要是通过修改AAPT工具来对资源进行保护,为了方便理解,下面先讲一下Android应用是怎么查找资源的。 Android查找资源的流程 在Android系统中,每一个应用程序一般都会配置很多资源,用来适配不同密度、大小和方向的屏幕,以及适配不同的国家、地区和语言等等。这些资源是在应用程序运行时自动根据设备的当前配置信息进行适配的。这也就是说,给定一个相同的资源ID,在不同的设备配置之下,查找到的可能是不同的资源。 这个查找过程对应用程序来说,是完全透明的,这个过程主要是靠Android资源管理框架来完成的,而Android资源管理框架实际是由AssetManager和Resources两个类来实现的。其中,Resources类可以根据ID来查找资源,而AssetManager类根据文件名来查找资源。事实上,如果一个资源ID对应的是一个文件,那么Resources类是先根据ID来找到资源文件名称,然后再将该文件名称交给AssetManager类来打开对应的文件的。基本流程如下图: 通过上图我们可以看到Resources是通过resources.arsc把Resource的ID转化成资源文件的名称,然后交由AssetManager来加载的。 而Resources.arsc这个文件是存放在APK包中的,他是由AAPT工具在打包过程中生成的,他本身是一个资源的索引表,里面维护者资源ID、Name、Path或者Value的对应关系,AssetManager通过这个索引表,就可以通过资源的ID找到这个资源对应的文件或者数据。 AAPT介绍 AAPT是Android Asset Packaging Tool的缩写,它存放在SDK的tools/目录下,AAPT的功能很强大,可以通过它查看查看、创建、更新压缩文件(如 .zip文件,.jar文件, .apk文件), 它也可以把资源编译为二进制文件,并生成resources.arsc, AAPT这个工具在APK打包过程中起到了非常重要作用,在打包过程中使用AAPT对APK中用到的资源进行打包,这里不对AAPT这个工具做过多的讨论,只看一下AAPT这个工具在打包过程中起到的作用,下图是AAPT打包的流程: AAPT这个工具在打包过程中主要做了下列工作: 把”assets”和”res/raw”目录下的所有资源进行打包(会根据不同的文件后缀选择压缩或不压缩),而”res/”目录下的其他资源进行编译或者其他处理(具体处理方式视文件后缀不同而不同,例如:”.xml”会编译成二进制文件,”.png”文件会进行优化等等)后才进行打包; 会对除了assets资源之外所有的资源赋予一个资源ID常量,并且会生成一个资源索引表resources.arsc; 编译AndroidManifest.xml成二进制的XML文件; 把上面3个步骤中生成结果保存在一个*.ap_文件,并把各个资源ID常量定义在一个R.java中; .ap_这个文件会在生成APK时放入APK包中, .ap _这个文件本身是一个ZIP包,他里面包含resources.arsc、AndroidManifest.xml、assets以及所有的资源文件,下图是UNZIP后的截图: 可以看出*.ap_这个文件中包含的内容,这个文件存放在build/intermediates/res的目录下,下图是这个文件存放的路径截图: 资源保护 我们这里参考Proguard Obfuscator方式,对APK中资源文件名使用简短无意义名称进行替换,给破解者制造困难,从而做到资源的相对安全;通过上面分析,我们可以看出通过修改AAPT在生成resources.arsc和*.ap_时把资源文件的名称进行替换,从而保护资源。 通过阅读AAPT编译资源的代码,我们发现修改AAPT在处理资源文件相关的源码是能够做到资源文件名的替换,下面是Resource.cpp中makeFileResources()的修改的代码片段: static status_t makeFileResources(Bundle* bundle, const sp<AaptAssets>& assets, ResourceTable* table, const sp<ResourceTypeSet>& set, const char* resType) { String8 type8(resType); String16 type16(resType); bool hasErrors = false; ResourceDirIterator it(set, String8(resType)); ssize_t res; while ((res=it.next()) == NO_ERROR) { if (bundle->getVerbose()) { printf(" (new resource id %s from %s)\n", it.getBaseName().string(), it.getFile()->getPrintableSource().string()); } String16 baseName(it.getBaseName()); const char16_t* str = baseName.string(); const char16_t* const end = str + baseName.size(); while (str < end) { if (!((*str >= 'a' && *str <= 'z') || (*str >= '0' && *str <= '9') || *str == '_' || *str == '.')) { fprintf(stderr, "%s: Invalid file name: must contain only [a-z0-9_.]\n", it.getPath().string()); hasErrors = true; } str++; } String8 resPath = it.getPath(); resPath.convertToResPath(); String8 obfuscationName; String8 obfuscationPath = getObfuscationName(resPath, obfuscationName); table->addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()), type16, baseName, // String16(obfuscationName), String16(obfuscationPath), // resPath NULL, &it.getParams()); assets->addResource(it.getLeafName(), obfuscationPath/*resPath*/, it.getFile(), type8); } return hasErrors ? UNKNOWN_ERROR : NO_ERROR; } 上述代码是在ResourceTable和Assets中添加资源文件时, 对资源文件名称进行修改,这就能够做到资源文件名称的替换,这样通过使用修改过的AAPT编译资源并进行打包,我们再用上面讲到的apktool这个工具进行反编译,下图是反编译后的截图: ...

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

美团Android自动化之旅—适配渠道包

概述 前一篇文章(美团Android自动化之旅—生成渠道包)介绍了Android中几种生成渠道包的方式,基本解决了打包慢的问题。 但是,随着渠道越来越多,不同渠道对应用的要求也不尽相同。例如,有的渠道要求美团客户端的应用名为美团,有的渠道要求应用名为美团团购。又比如,有些渠道要求应用不能使用第三方统计工具(如flurry)。总之,每次打包都需要对这些渠道进行适配。 之前的做法是为每个需要适配的渠道创建一个Git分支,发版时再切换到相应的分支,并合并主分支的代码。适配的渠道比较少的话这种方式还可以接受,如果分支比较多,对开发人员来说简直就是噩梦。还好,自从有了Gradle flavor,一切都变得简单了。本文假定读者使用过Gradle,如果还不了解建议先阅读相关文档。 Flavor 先来看build.gradle文件中的一段代码: android { .... productFlavors { flavor1 { minSdkVersion 14 } } } 上例定义了一个flavor:flavor1,并指定了应用的minSdkVersion为14(当然还可以配置更多的属性,具体可参考相关文档)。与此同时,Gradle还会为该flavor关联对应的sourceSet,默认位置为src/<flavorName>目录,对应到本例就是src/flavor1。 接下来,要做的就是根据具体的需求在build.gradle文件中配置flavor,并添加必要的代码和资源文件。以flavor1为例,运行gradle assembleFlavor1命令既可生成所需的适配包。下面主要介绍美团团购Android客户端的一些适配案例。 案例 使用不同的包名 美团团购Android客户端之前有两个版本:手机版(com.meituan.group)和hd版(com.meituan.group.hd),两个版本使用了不同的代码。目前hd版对应的代码已不再维护,希望能直接使用手机版的代码。解决该问题可以有多种方法,不过使用flavor相对比较简单,示例如下: productFlavors { hd { applicationId "com.meituan.group.hd" } } 上面的代码添加了一个名为hd的flavor,并指定了应用的包名为com.meituan.group.hd,运行gradle assembleHd命令即可生成hd适配包。 控制是否自动更新 美团团购Android客户端在启动时会默认检查客户端是否有更新,如果有更新就会提示用户下载。但是有些渠道和应用市场不允许这种默认行为,所以在适配这些渠道时需要禁止自动更新功能。 解决的思路是提供一个配置字段,应用启动的时候检查该字段的值以决定是否开启自动更新功能。使用flavor可以完美的解决这类问题。 Gradle会在generateSources阶段为flavor生成一个BuildConfig.java文件。BuildConfig类默认提供了一些常量字段,比如应用的版本名(VERSION_NAME),应用的包名(PACKAGE_NAME)等。更强大的是,开发者还可以添加自定义的一些字段。下面的示例假设wandoujia市场默认禁止自动更新功能: android { defaultConfig { buildConfigField "boolean", "AUTO_UPDATES", "true" } productFlavors { wandoujia { buildConfigField "boolean", "AUTO_UPDATES", "false" } } } 上面的代码会在BuildConfig类中生成AUTO_UPDATES布尔常量,默认值为true,在使用wandoujia flavor时,该值会被设置成false。接下来就可以在代码中使用AUTO_UPDATES常量来判断是否开启自动更新功能了。最后,运行gradle assembleWandoujia命令即可生成默认不开启自动升级功能的渠道包,是不是很简单。 使用不同的应用名 最常见的一类适配是修改应用的资源。例如,美团团购Android客户端的应用名是美团,但有的渠道需要把应用名修改为美团团购;还有,客户端经常会和一些应用分发市场合作,需要在应用的启动界面中加上第三方市场的Logo,类似这类适配形式还有很多。 Gradle在构建应用时,会优先使用flavor所属dataSet中的同名资源。所以,解决思路就是在flavor的dataSet中添加同名的字符串资源,以覆盖默认的资源。下面以适配wandoujia渠道的应用名为美团团购为例进行介绍。 首先,在build.gradle配置文件中添加如下flavor: android { productFlavors { wandoujia { } } } 上面的配置会默认src/wandoujia目录为wandoujia flavor的dataSet。 ...

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

Introduction to Glide, Image Loader Library for Android, recommended by Google

In the passed Google Developer Summit Thailand, Google introduced us an Image Loader Library for Android developed by bumptech named Glide as a library that recommended by Google. It has been used in many Google open source projects till now including Google I/O 2014 official application. It succeeded in making me interested. I spent a whole night playing with it and decided to share my experience in this blog post. As a begining, I must say that it looks 90% similar to Picasso. To be more precise, I think it is something like a Picasso-clone. ...

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

Android5.0+(CoordinatorLayout)

英文原文:https://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout 这篇文章专门讲解和CoordinatorLayout相关的知识点,这也是Design Support Library中最重要与最难的部分。 概览 CoordinatorLayout 实现了多种Material Design中提到的滚动效果。目前这个框架提供了几种不用写动画代码就能工作的方法,这些效果包括: 让浮动操作按钮上下滑动,为Snackbar留出空间。 扩展或者缩小Toolbar或者头部,让主内容区域有更多的空间。 控制哪个view应该扩展还是收缩,以及其显示大小比例,包括视差滚动效果动画。 设置 首先确保遵循了Design Support Library的使用说明。 浮动操作按钮与Snackbar CoordinatorLayout可以用来配合浮动操作按钮的 layout_anchor 和 layout_gravity属性创造出浮动效果,详情请参见浮动操作按钮指南。 当Snackbar在显示的时候,往往出现在屏幕的底部。为了给Snackbar留出空间,浮动操作按钮需要向上移动。 只要使用CoordinatorLayout作为基本布局,将自动产生向上移动的动画。浮动操作按钮有一个 默认的 behavior来检测Snackbar的添加并让按钮在Snackbar之上呈现上移与Snackbar等高的动画。 [?](http://my.oschina.net/kooeasy/blog/484593#) <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> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> ` ``&lt;``android.support.design.widget.CoordinatorLayout` </div> <div class="line number2 index1 alt1"> ` ``android:id``=``"@+id/main_content"` </div> <div class="line number3 index2 alt2"> ` ``xmlns:android``=``"http://schemas.android.com/apk/res/android"` </div> <div class="line number4 index3 alt1"> ` ``xmlns:app``=``"http://schemas.android.com/apk/res-auto"` </div> <div class="line number5 index4 alt2"> ` ``android:layout_width``=``"match_parent"` </div> <div class="line number6 index5 alt1"> ` ``android:layout_height``=``"match_parent"``&gt;` </div> <div class="line number7 index6 alt2"> ` ` </div> <div class="line number8 index7 alt1"> ` ``&lt;``android.support.v7.widget.RecyclerView` </div> <div class="line number9 index8 alt2"> ` ``android:id``=``"@+id/rvToDoList"` </div> <div class="line number10 index9 alt1"> ` ``android:layout_width``=``"match_parent"` </div> <div class="line number11 index10 alt2"> ` ``android:layout_height``=``"match_parent"``&gt;` </div> <div class="line number12 index11 alt1"> ` ``&lt;/``android.support.v7.widget.RecyclerView``&gt;` </div> <div class="line number13 index12 alt2"> ` ` </div> <div class="line number14 index13 alt1"> ` ``&lt;``android.support.design.widget.FloatingActionButton` </div> <div class="line number15 index14 alt2"> ` ``android:layout_width``=``"wrap_content"` </div> <div class="line number16 index15 alt1"> ` ``android:layout_height``=``"wrap_content"` </div> <div class="line number17 index16 alt2"> ` ``android:layout_gravity``=``"bottom|right"` </div> <div class="line number18 index17 alt1"> ` ``android:layout_margin``=``"16dp"` </div> <div class="line number19 index18 alt2"> ` ``android:src``=``"@mipmap/ic_launcher"` </div> <div class="line number20 index19 alt1"> ` ``app:layout_anchor``=``"@id/rvToDoList"` </div> <div class="line number21 index20 alt2"> ` ``app:layout_anchorGravity``=``"bottom|right|end"``/&gt;` </div> <div class="line number22 index21 alt1"> ` ``&lt;/``android.support.design.widget.CoordinatorLayout``&gt;` </div> </div> </td> </tr> </table> </div> Toolbar的扩展与收缩 首先需要确保你不是使用已经过时的ActionBar。务必遵循 使用ToolBar作为actionbar这篇文章的指南。同样,这里也需要CoordinatorLayout作为主布局容器。 ...

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

Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较

在android中的加载网络图片是一件十分令人头疼的事情,在网上有着许多关于加载网络图片的开源库,可以让我们十分方便的加载网络图片。在这里我主要介绍一下我自己在使用Volley, Picasso, Universal-Imageloader的一些使用的感悟。以及最基本的用法介绍。 1.android-Volley 给ImageView设置图片源 - > // imageView是一个ImageView实例 - > // ImageLoader.getImageListener的第二个参数是默认的图片resource id - > // 第三个参数是请求失败时候的资源id,可以指定为0 - > ImageListener listener = ImageLoader.getImageListener(imageView, android.R.drawable.ic_menu_rotate, android.R.drawable.ic_delete); - > mImageLoader.get(url, listener); 复制代码 使用NetworkImageView Volley提供了一个新的控件NetworkImageView来代替传统的ImageView,这个控件的图片属性可以通过 - > mImageView.setImageUrl(url, imageLoader) 复制代码 来设定。而且,这个控件在被从父控件detach的时候,会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题。 - > mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache()); - > &#8230;. &#8230; - > - > if(holder.imageRequest != null) { - > holder.imageRequest.cancel(); - > } - > holder.imageRequest = mImageLoader.get(BASE_UR + item.image_url, holder.imageView, R.drawable.loading, R.drawable.error); - > 复制代码 总结:如果你的工程项目,是一个比较小的项目,或者要求不是很高的项目,处理比较简单的可以使用这个库,这个库是Google 2013 I/O 发布的一个开源库。使用这个库在图片的处理上,没有提供任何的图片处理的操作,个人感觉这个库主要在网络数据连接上比较好,在图片处理上还是不够完善,强大。 ...

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

Android库Volley的使用介绍

Android Volley 是Google开发的一个网络lib,可以让你更加简单并且快速的访问网络数据。Volley库的网络请求都是异步的,你不必担心异步处理问题。 Volley的优点: 请求队列和请求优先级 请求Cache和内存管理 扩展性性强 可以取消请求 ##下载和编译volley.jar 需要安装git,ant,android sdk clone代码: git clone https://android.googlesource.com/platform/frameworks/volley 编译jar: android update project -p . ant jar 添加volley.jar到你的项目中 不过已经有人将volley的代码放到github上了: https://github.com/mcxiaoke/android-volley,你可以使用更加简单的方式来使用volley: ###Maven format: jar <span class="tag"><<span class="title">dependency</span>></span> <span class="tag"><<span class="title">groupId</span>></span>com.mcxiaoke.volley<span class="tag"></<span class="title">groupId</span>></span> <span class="tag"><<span class="title">artifactId</span>></span>library<span class="tag"></<span class="title">artifactId</span>></span> <span class="tag"><<span class="title">version</span>></span>1.0.6<span class="tag"></<span class="title">version</span>></span> <span class="tag"></<span class="title">dependency</span>></span> ###Gradle format: jar compile 'com.mcxiaoke.volley:library:1.0.6' ##Volley工作原理图 {.fancybox} ##创建Volley 单例 使用volley时,必须要创建一个请求队列RequestQueue,使用请求队列的最佳方式就是将它做成一个单例,整个app使用这么一个请求队列。 <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AppController</span> <span class="keyword">extends</span> <span class="title">Application</span> </span>{ <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = AppController.class .getSimpleName(); <span class="keyword">private</span> RequestQueue mRequestQueue; <span class="keyword">private</span> ImageLoader mImageLoader; <span class="keyword">private</span> <span class="keyword">static</span> AppController mInstance; <span class="annotation">@Override</span> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">()</span> </span>{ <span class="keyword">super</span>.onCreate(); mInstance = <span class="keyword">this</span>; } <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> AppController <span class="title">getInstance</span><span class="params">()</span> </span>{ <span class="keyword">return</span> mInstance; } <span class="function"><span class="keyword">public</span> RequestQueue <span class="title">getRequestQueue</span><span class="params">()</span> </span>{ <span class="keyword">if</span> (mRequestQueue == <span class="keyword">null</span>) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } <span class="keyword">return</span> mRequestQueue; } <span class="function"><span class="keyword">public</span> ImageLoader <span class="title">getImageLoader</span><span class="params">()</span> </span>{ getRequestQueue(); <span class="keyword">if</span> (mImageLoader == <span class="keyword">null</span>) { mImageLoader = <span class="keyword">new</span> ImageLoader(<span class="keyword">this</span>.mRequestQueue, <span class="keyword">new</span> LruBitmapCache()); } <span class="keyword">return</span> <span class="keyword">this</span>.mImageLoader; } <span class="keyword">public</span> <T> <span class="function"><span class="keyword">void</span> <span class="title">addToRequestQueue</span><span class="params">(Request<T> req, String tag)</span> </span>{ <span class="comment">// set the default tag if tag is empty</span> req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); getRequestQueue().add(req); } <span class="keyword">public</span> <T> <span class="function"><span class="keyword">void</span> <span class="title">addToRequestQueue</span><span class="params">(Request<T> req)</span> </span>{ req.setTag(TAG); getRequestQueue().add(req); } <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">cancelPendingRequests</span><span class="params">(Object tag)</span> </span>{ <span class="keyword">if</span> (mRequestQueue != <span class="keyword">null</span>) { mRequestQueue.cancelAll(tag); } } } 另外,你还需要一个Cache来存放请求的图片: ...

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

如何使用Android Studio把自己的Android library分享到jCenter和Maven Central

原文:How to distribute your own Android library through jCenter and Maven Central from Android Studio 如果你想在Android Studio中引入一个library到你的项目,你只需添加如下的一行代码到模块的build.gradle文件中。 1 <div class="line number2 index1 alt1"> 2 </div> <div class="line number3 index2 alt2"> 3 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `dependencies {` </div> <div class="line number2 index1 alt1"> ` ``compile ``'com.inthecheesefactory.thecheeselibrary:fb-like:0.9.3'` </div> <div class="line number3 index2 alt2"> `}` </div> </div> </td> </tr> </table> 就是如此简单的一行代码,你就可以使用这个library了。 ...

2015年11月4日 · 9 分钟 · 天边的星星

介绍4款json的java类库 及 其性能测试

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999的一个子集。 JSON采用完全独立于语言的文本格式,这些特性使JSON成为理想的数据交换语言。 下面介绍四款处理json的java类库:Json-lib、Gson、Jackson、Fastjson 一、Json-lib JSON-lib is a java library for transforming beans, maps, collections, java arrays and XML to JSON and back again to beans and DynaBeans. 官网:http://json-lib.sourceforge.net/ maven依赖配置: ![复制代码](http://common.cnblogs.com/images/copycode.gif) &lt;dependency&gt; &lt;groupId&gt;net.sf.json-lib&lt;/groupId&gt; &lt;artifactId&gt;json-lib&lt;/artifactId&gt; &lt;version&gt;2.4&lt;/version&gt; &lt;classifier&gt;jdk15&lt;/classifier&gt; &lt;/dependency&gt; ![复制代码](http://common.cnblogs.com/images/copycode.gif) 示例: ![复制代码](http://common.cnblogs.com/images/copycode.gif) /** * 将对象序列化成json字符串 * @param obj * @return */ public static String bean2Json(Object obj){ JSONObject jsonObject=JSONObject.fromObject(obj); return jsonObject.toString(); } /** * 将json字符串反序列化为对象 * @param jsonStr * @param objClass 反序列化为该类的对象 * @return */ @SuppressWarnings("unchecked") public static &lt;T&gt; T json2Bean(String jsonStr,Class&lt;T&gt; objClass){ return (T)JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass); } ![复制代码](http://common.cnblogs.com/images/copycode.gif) ...

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