android

Android开发中可能会出现的一些常见的问题:
http请求:
一般请求分为GET请求和POST请求,区别如下:
GET请求可以被缓存。
我们之前提到,当发送键值对信息时,可以在URL上面直接追加键值对参数。当用GET请求发送键值对时,键值对会随着URL一起发送的。
由于GET请求发送的键值对时随着URL一起发送的,所以一旦该URL被黑客截获,那么就能看到发送的键值对信息,所以GET请求的安全性很低,不能用GET请求发送敏感的信息(比如用户名密码)。
由于URL不能超过2048个字符,所以GET请求发送数据是有长度限制的。
由于GET请求较低的安全性,我们不应该用GET请求去执行增加、删除、修改等的操作,应该只用它获取数据。
POST请求从不会被缓存。
POST请求的URL中追加键值对参数,不过这些键值对参数不是随着URL发送的,而是被放入到请求体中发送的,这样安全性稍微好一些。
应该用POST请求发送敏感信息,而不是用GET。
由于可以在请求体中发送任意的数据,所以理论上POST请求不存在发送数据大小的限制。
当执行增减、删除、修改等操作时,应该使用POST请求,而不应该使用GET请求。
下面介绍目前请求使用请求常见的两个类:
HttpURLConnection vs DefaultHttpClient
在Android API Level 9(Android 2.2)之前之能使用DefaultHttpClient类发送http请求。DefaultHttpClient是Apache用于发送http请求的客户端,其提供了强大的API支持,而且基本没有什么bug,但是由于其太过复杂,Android团队在保持向后兼容的情况下,很难对DefaultHttpClient进行增强。为此,Android团队从Android API Level 9开始自己实现了一个发送http请求的客户端类——–HttpURLConnection。
相比于DefaultHttpClient,HttpURLConnection比较轻量级,虽然功能没有DefaultHttpClient那么强大,但是能够满足大部分的需求,所以Android推荐使用HttpURLConnection代替DefaultHttpClient,并不强制使用HttpURLConnection。
但从Android API Level 23(Android 6.0)开始,不能再在Android中使用DefaultHttpClient,强制使用HttpURLConnection。
请求的参数可以使用Map或者List等来封装上传的数据。
一些常见的状态码为:
  200 - 服务器成功返回网页
  404 - 请求的网页不存在
  503 - 服务器超时
HTTP状态码一览表。
1xx:请求收到,继续处理
2xx:操作成功收到,分析、接受
3xx:完成此请求必须进一步处理
4xx:请求包含一个错误语法或不能完成
5xx:服务器执行一个完全有效请求失败

数据解析:
目前移动端一般使用json来解析,一般用JSONObject和JSONArray来解析数据,解释见下:
public class
JSONObject
extends Object

org.json.JSONObject

Class Overview
A modifiable set of name/value mappings. Names are unique, non-null strings. Values may be any mix of JSONObjects, JSONArrays, Strings, Booleans, Integers, Longs, Doubles or NULL. Values may not be null, NaNs, infinities, or of any type not listed here.

JSONObject(String json)
Creates a new JSONObject with name/value mappings from the JSON string.

Object get(String name)
Returns the value mapped by name.

int getInt(String name)
Returns the value mapped by name if it exists and is an int or can be coerced to an int.

String getString(String name)
Returns the value mapped by name if it exists, coercing it if necessary.

JSONArray getJSONArray(String name)
Returns the value mapped by name if it exists and is a JSONArray.

public class
JSONArray
extends Object

org.json.JSONArray

Class Overview
A dense indexed sequence of values. Values may be any mix of JSONObjects, other JSONArrays, Strings, Booleans, Integers, Longs, Doubles, null or NULL. Values may not be NaNs, infinities, or of any type not listed here.

JSONObject getJSONObject(int index)
Returns the value at index if it exists and is a JSONObject.

JSONStringer :用来生成json ,实际上就是JSONArray和JSONObject配合使用。
Stringers only encode well-formed JSON strings. In particular:
The stringer must have exactly one top-level array or object.
Lexical scopes must be balanced: every call to array() must have a matching call to endArray() and every call to object() must have a matching call to endObject(). //每次调用array(),必须匹配endArray,object,endObject同理。
Arrays may not contain keys (property names).
Objects must alternate keys (property names) and values.
Values are inserted with either literal value calls, or by nesting arrays or objects.

JSON Vs XML
1.JSON和XML的数据可读性基本相同
2.JSON和XML同样拥有丰富的解析手段
3.JSON相对于XML来讲,数据的体积小
4.JSON与JavaScript的交互更加方便
5.JSON对数据的描述性比XML较差
6.JSON的速度要远远快于XML

图片压缩:
一般使用BitmapFactory进行图片的读入,压缩,展示。
1、等比压缩,等比压缩是保持原图长宽比例的压缩,只是图片变小,展示的还是原图的所有内容(区别于第二种通过Matrix压缩,可以选取图片的一部分,类似于上传头像时,让你在图上选一块zoom的形式)。等比压缩用的的主要是BitmapFactory.Options,通过options缩放比例的设置,来生成缩略图。
一般化的压缩代码见下:
[html] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* 图片按比例大小压缩方法
*
* @param srcPath (根据路径获取图片并压缩)
* @return
*/
public static Bitmap getimage(String srcPath) {

BitmapFactory.Options newOpts = new BitmapFactory.Options();    
// 开始读入图片,此时把options.inJustDecodeBounds 设回true了    
newOpts.inJustDecodeBounds = true;    
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空    

newOpts.inJustDecodeBounds = false;    
int w = newOpts.outWidth;    
int h = newOpts.outHeight;    
// 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为    
float hh = 800f;// 这里设置高度为800f    
float ww = 480f;// 这里设置宽度为480f    
// 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可    
int be = 1;// be=1表示不缩放    
if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放    
    be = (int) (newOpts.outWidth / ww);    
} else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放    
    be = (int) (newOpts.outHeight / hh);    
}    
if (be <= 0)    
    be = 1;    
newOpts.inSampleSize = be;// 设置缩放比例    
// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了    
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);    
return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩    

}

[html] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* 质量压缩方法
*
* @param image
* @return
*/
public static Bitmap compressImage(Bitmap image) {

ByteArrayOutputStream baos = new ByteArrayOutputStream();    
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中    
int options = 90;    

while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩    
    baos.reset(); // 重置baos即清空baos    
    image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中    
    options -= 10;// 每次都减少10    
}    
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中    
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片    
return bitmap;    

}

2、通过Matrix进行更加灵活的缩放:这种方式主要是通过构建缩放矩阵和Bitmap.createBitmap方法来实现灵活缩放,宽和高缩放的比例可以不一致,而且通过Bitmap.createBitmap方法创建出来的是新的位图,这个位图可以是选取原图的一部分,而不是对原图进行整体缩放!类似于上传头像时,让你在原图上扣下来一块的效果,控制非常灵活。
图片格式:
一般格式主要有jpg,png,
二者对比:
1、png有透明通道,而jpg没有
2、png是无损压缩的,而jpg是有损压缩,因此png中存储的信息会很多,体积自然就大了
3、手机对png情有独钟,会对其进行硬件加速,所以同样一张背景图,png虽然体积大,但是加载速度更快
综述:1、对于app包中的图片,我们都使用png格式的,而对于要从网络上加载的图片,考虑到流量以及下载上速度,则使用jpg格式的,因为它有较高的压缩率,体积更小。
2、对于背景图、引导页,这种大尺寸的图片,我们还是倾向于jpg格式的,虽然加载慢一些吗,但是体积小,减少了包的体积
3、Google后来发布了一种新的图片格式,WebP,它的压缩率比jpg更好,已经在慢慢普及
其实图片内部编码等比较复杂,简单说下:
1、ImageFormat(android.graphics.ImageFormat),格式参数有以下几种:
[html] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* Use this function to retrieve the number of bits per pixel of an
* ImageFormat.
*
* @param format
* @return the number of bits per pixel of the given format or -1 if the
* format doesn’t exist or is not supported.
*/
public static int getBitsPerPixel(int format) {
switch (format) {
case RGB_565:
return 16;
case NV16:
return 16;
case YUY2:
return 16;
case YV12:
return 12;
case Y8:
return 8;
case Y16:
return 16;
case NV21:
return 12;
case YUV_420_888:
return 12;
case RAW_SENSOR:
return 16;
case BAYER_RGGB:
return 16;
}
return -1;
}
解释:
[html] view plain copy 在CODE上查看代码片派生到我的代码片
int JPEG ,Encoded formats,常量值: 256 (0x00000100)

int NV16,YCbCr format, used for video,16 (0x00000010)

int NV21,YCrCb format used for images, which uses the NV21 encoding format,常量值: 17 (0x00000011)

int RGB_565,RGB format used for pictures encoded as RGB_565,常量值: 4 (0x00000004)

int UNKNOWN, 常量值:0 (0x00000000)

int YUY2,YCbCr format used for images,which uses YUYV (YUY2) encoding format,20 (0x00000014)

int YV12,Android YUV format,This format is exposed to software decoders and applications

YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed by (W/2) x (H/2) Cr and Cb planes
上面是说图片的格式,这里说说像素格式:
2、PixelFormat(android.graphics.PixelFormat),格式参数有以下几种:
int A_8,常量值:8 (0x00000008)
int JPEG,常量值:256 (0x00000100),constant,已声明不赞成使用,use ImageFormat.JPEG instead.
int LA_88,常量值:10 (0x0000000a)
int L_8, 常量值:9 (0x00000009)
int OPAQUE,常量值: -1 (0xffffffff),System chooses an opaque format (no alpha bits required)
int RGBA_4444,常量值:7 (0x00000007)
int RGBA_5551,常量值:6 (0x00000006)
int RGBA_8888,常量值:1 (0x00000001)
int RGBX_8888,常量值:2 (0x00000002)
int RGB_332,常量值:11 (0x0000000b)
int RGB_565,常量值:4 (0x00000004)
int RGB_888,常量值:3 (0x00000003)
int TRANSLUCENT,常量值: -3 (0xfffffffd),System chooses a format that supports translucency (many alpha bits)
int TRANSPARENT,常量值:-2 (0xfffffffe),System chooses a format that supports transparency (at least 1 alpha bit)
int UNKNOWN,常量值: 0 (0x00000000)
int YCbCr_420_SP,常量值:17 (0x00000011),constant 已声明不赞成使用 use ImageFormat.NV21 instead
int YCbCr_422_I,常量值: 20 (0x00000014),constant 已声明不赞成使用 use ImageFormat.YUY2 instead
int YCbCr_422_SP,常量值:16 (0x00000010),constant 已声明不赞成使用 use ImageFormat.NV16 instead
注意,有四种图像格式已被声明不赞成使用,可以用ImaggFormat相对应的格式进行代替。由此可知,两种图像格式之间存在相通之处。用法举例,让窗口实现渐变的效果,如
1 getWindow().setFormat(PixelFormat.RGBA_8888);
补充说明:RGBA_8888为android的一种32位颜色格式,R、G、B、A分别用八位表示,Android默认的图像格式是PixelFormat.OPAQUE,其是不带Alpha值的
3、Bitmap.Config(Android.graphics.Bitmap内部类)
Possible bitmap configurations。A bitmap configuration describes how pixels are stored。This affects the quality (color depth) as well as the ability to display transparent/translucent colors。(官网介绍,大致意思是说:影响一个图片色彩色度显示质量主要看位图配置,显示图片时透明还是半透明)。
ALPHA_8:Each pixel is stored as a single translucency (alpha) channel。(原图的每一个像素以半透明显示)
ARGB_4444:This field was deprecated in API level 13。Because of the poor quality of this configuration, it is advised to use ARGB_8888 instead。(在API13以后就被弃用了,建议使用8888)。
ARGB_8888 :Each pixel is stored on 4 bytes。 Each channel (RGB and alpha for translucency) is stored with 8 bits of precision (256 possible values) 。This configuration is very flexible and offers the best quality。 It should be used whenever possible。(每个像素占4个字节,每个颜色8位元,反正很清晰,看着很舒服)。
RGB_565:Each pixel is stored on 2 bytes and only the RGB channels are encoded:red is stored with 5 bits of precision (32 possible values),green is stored with 6 bits of precision (64 possible values) and blue is stored with 5 bits of precision。(这个应该很容易理解了)。
用法举例,构建Bitmap对象时,会用到BitmapConfig类图像格式对象,如:
1 Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.RGB_565)
图片格式之间的相互转换略,可以参考文章http://www.open-open.com/lib/view/open1438051625316.html,本段摘自该处。
适配:
图片的适配一般是切几套图,分别放在hdpi,xhdip,xxhdpi等文件夹中,系统会自动选择合适的图片去加载,布局的适配一般是建立values-hdpi,values-xhdpi,values-xxhdpi文件夹来适配,文件夹下有dimens.xml文件,里面会对需要修改偏移距离等地方增加相应的值,同一个key在不同的dimens文件中的值不同,便会适配各种屏幕。
适配方面多用相对布局,不要写死大小,偏移距离等单位多用dp,字体多用sp,就会好适配些。
DP:Density-independent pixel (dp)独立像素密度。标准是160dip.即1dp对应1个pixel,计算公式如:px = dp * (dpi / 160),屏幕密度越大,1dp对应 的像素点越多。
上面的公式中有个dpi,dpi为DPI是Dots Per Inch(每英寸所打印的点数),也就是当设备的dpi为160的时候1px=1dp;
SP:与缩放无关的抽象像素(Scale-independent Pixel)。sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。

事件分发:

从上图中我们可以看到 ViewGroup 及其子类对与 Touch 事件相关的三个方法均能响应,而 Activity 对onInterceptTouchEvent(MotionEvent ev) 也就是事件拦截不进行响应。另外需要注意的是 View 对dispatchTouchEvent(MotionEvent ev) 和onInterceptTouchEvent(MotionEvent ev) 的响应的前提是可以向该 View 中添加子 View,如果当前的 View 已经是一个最小的单元 View(比如 TextView),那么就无法向这个最小 View 中添加子 View,也就无法向子 View 进行事件的分发和拦截,所以它没有dispatchTouchEvent(MotionEvent ev) 和onInterceptTouchEvent(MotionEvent ev),只有onTouchEvent(MotionEvent ev)。
事件分发:public boolean dispatchTouchEvent(MotionEvent ev)
Touch 事件发生时Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:
如果return true,事件会分发给当前 View 并由 dispatchTouchEvent 方法进行消费,同时事件会停止向下传递;
如果return false,事件分发分为两种情况:
如果当前 View 获取的事件直接来自 Activity,则会将事件返回给 Activity 的 onTouchEvent 进行消费;
如果当前 View 获取的事件来自外层父控件,则会将事件返回给父 View 的 onTouchEvent 进行消费。
如果返回系统默认的super.dispatchTouchEvent(ev),事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。
▐事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev)
在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent的事件拦截逻辑如下:
如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理;
如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上,再由子 View 的 dispatchTouchEvent 来开始这个事件的分发;
如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认会被拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理。
▐事件响应:public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent的事件响应逻辑如下:
如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递,并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。
如果返回了 true 则会接收并消费该事件。
如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。
到这里,与 Touch 事件相关的三个方法就分析完毕了。下面的内容会通过各种不同的的测试案例来验证上文中三个方法对事件的处理逻辑。
总结:
1、如果ViewGroup找到了能够处理该事件的View,则直接交给子View处理,自己的onTouchEvent不会被触发;
2、可以通过复写onInterceptTouchEvent(ev)方法,拦截子View的事件(即return true),把事件交给自己处理,则会执行自己对应的onTouchEvent方法
3、子View可以通过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup对其MOVE或者UP事件进行拦截;

好了,那么实际应用中能解决哪些问题呢?
比如你需要写一个类似slidingmenu的左侧隐藏menu,主Activity上有个Button、ListView或者任何可以响应点击的View,你在当前View上死命的滑动,菜单栏也出不来;因为MOVE事件被子View处理了~ 你需要这么做:在ViewGroup的dispatchTouchEvent中判断用户是不是想显示菜单,如果是,则在onInterceptTouchEvent(ev)拦截子View的事件;自己进行处理,这样自己的onTouchEvent就可以顺利展现出菜单栏了~~
屏幕事件处理,手势识别:
平时使用较少,此处简略写一下:
android中提供了MotionEvent,GestureDetector等来方便识别各种手势操作。
MotionEvent: Object used to report movement (mouse, pen, finger, trackball) events.
Motion events may hold either absolute or relative movements and other data, depending on the type of device.
getAction()方法返回的是int类型,用到的只有低16位,其中:低八位是动作的类型,高8位是触摸点索引值的表示(单点为0,双点为1)
UI展示:
ui展示基本使用到的是view和widget等组合方式来显示各种各样的文字,图片,选框等内容,组合成一个操作窗口。
view包下主要有view,surfaceview,windowmanager等一些操作显示类,widget包下都是google封装的一些ui组件,比如各种layout,文本显示框,按钮,列表组件,复选框等等。有时间整理下这两个包下的类,梳理下,待续。。。
动画:
Android提供了几种动画类型:View Animation 、Drawable Animation 、Property Animation 。View Animation相当简单,不过只能支持对View进行简单的缩放、平移、旋转、透明度基本的动画,且有一定的局限性。逐帧动画就是多张图片一张一张的播放。属性动画是最新的,重点介绍下:
ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。
相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。
不过虽说ObjectAnimator会更加常用一些,但是它其实是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator仍然是整个属性动画当中最核心的一个类。那么既然是继承关系,说明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它们的用法也非常类似,这里如果我们想要将一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:
[html] view plain copy 在CODE上查看代码片派生到我的代码片
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, “alpha”, 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();

ofFloat()方法的第二个参数到底可以传哪些值呢?目前我们使用过了alpha、rotation、translationX和scaleY这几个值,分别可以完成淡入淡出、旋转、水平移动、垂直缩放这几种动画,那么还有哪些值是可以使用的呢?其实这个问题的答案非常玄乎,就是我们可以传入任意的值到ofFloat()方法的第二个参数当中。任意的值?相信这很出乎大家的意料吧,但事实就是如此。因为ObjectAnimator在设计的时候就没有针对于View来进行设计,而是针对于任意对象的,它所负责的工作就是不断地向某个对象中的某个属性进行赋值,然后对象根据属性值的改变再来决定如何展现出来
那么textview对象中是不是有alpha属性这个值呢?没有,不仅textview没有这个属性,连它所有的父类也是没有这个属性的!这就奇怪了,textview当中并没有alpha这个属性,ObjectAnimator是如何进行操作的呢?其实ObjectAnimator内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法,因此alpha属性所对应的get和set方法应该就是:
public void setAlpha(float value);
public float getAlpha();
那么textview对象中是否有这两个方法呢?确实有,并且这两个方法是由View对象提供的,也就是说不仅TextView可以使用这个属性来进行淡入淡出动画操作,任何继承自View的对象都可以的。
既然alpha是这个样子,相信大家一定已经明白了,前面我们所用的所有属性都是这个工作原理,那么View当中一定也存在着setRotation()、getRotation()、setTranslationX()、getTranslationX()、setScaleY()、getScaleY()这些方法,不信的话你可以到View当中去找一下。
实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:
after(Animator anim) 将现有动画插入到传入的动画之后执行
after(long delay) 将现有动画延迟指定毫秒后执行
before(Animator anim) 将现有动画插入到传入的动画之前执行
with(Animator anim) 将现有动画和传入的动画同时执行
属性动画就简单说这么点,参考博客http://blog.csdn.net/guolin_blog/article/details/43536355,写的非常详细了。。。
消息队列:
1.Message
消息对象,顾名思义就是记录消息信息的类。这个类有几个比较重要的字段:
a.arg1和arg2:我们可以使用两个字段用来存放我们需要传递的整型值,在Service中,我们可以用来存放Service的ID。
b.obj:该字段是Object类型,我们可以让该字段传递某个多项到消息的接受者中。
c.what:这个字段可以说是消息的标志,在消息处理中,我们可以根据这个字段的不同的值进行不同的处理,类似于我们在处理Button事件时,通过switch(v.getId())判断是点击了哪个按钮。
在使用Message时,我们可以通过new Message()创建一个Message实例,但是Android更推荐我们通过Message.obtain()或者Handler.obtainMessage()获取Message对象。这并不一定是直接创建一个新的实例,而是先从消息池中看有没有可用的Message实例,存在则直接取出并返回这个实例。反之如果消息池中没有可用的Message实例,则根据给定的参数new一个新Message对象。通过分析源码可得知,Android系统默认情况下在消息池中实例化10个Message对象。
2.MessageQueue
消息队列,用来存放Message对象的数据结构,按照“先进先出”的原则存放消息。存放并非实际意义的保存,而是将Message对象以链表的方式串联起来的。MessageQueue对象不需要我们自己创建,而是有Looper对象对其进行管理,一个线程最多只可以拥有一个MessageQueue。我们可以通过Looper.myQueue()获取当前线程中的MessageQueue。
3.Looper
MessageQueue的管理者,在一个线程中,如果存在Looper对象,则必定存在MessageQueue对象,并且只存在一个Looper对象和一个MessageQueue对象。倘若我们的线程中存在Looper对象,则我们可以通过Looper.myLooper()获取,此外我们还可以通过Looper.getMainLooper()获取当前应用系统中主线程的Looper对象。在这个地方有一点需要注意,假如Looper对象位于应用程序主线程中,则Looper.myLooper()和Looper.getMainLooper()获取的是同一个对象。
4.Handler
消息的处理者。通过Handler对象我们可以封装Message对象,然后通过sendMessage(msg)把Message对象添加到MessageQueue中;当MessageQueue循环到该Message时,就会调用该Message对象对应的handler对象的handleMessage()方法对其进行处理。由于是在handleMessage()方法中处理消息,因此我们应该编写一个类继承自Handler,然后在handleMessage()处理我们需要的操作。

   另外,我们知道,Android UI操作并不是线程安全的,所以无法在子线程中更新UI。但Andriod提供了几种方法,可以在子线程中通知UI线程更新界面:

Activity.runOnUiThread( Runnable )
View.post( Runnable )
View.postDelayed( Runnable, long )
Handler
比较常用的是通过Handler,用Handler来接收子线程发送的数据,并用此数据配合主线程更新UI。那么,只要在主线程中创建Handler对象,在子线程中调用Handler的sendMessage方法,就会把消息放入主线程的消息队列,并且将会在Handler主线程中调用该handler的handleMessage方法来处理消息。
此外,消息队列也可以做一些依次执行的事情,比如A-B-C-D依次执行,可以通过Handler来实现。
线程:
线程比计较复杂,涉及到线程池,线程同步,线程锁等一系列的概念,这里只能简单提一下:
ExecutorService executorService1 = Executors.newSingleThreadExecutor();

ExecutorService executorService2 = Executors.newFixedThreadPool(10);

ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
ExecutorService executorService4 = Executors.newCacheThreadPool();
newCachedThreadPool()
缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse.如果没有,就建一个新的线程加入池中。能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。缓存型池子通常用于执行一些生存期很短的异步型任务 。
newFixedThreadPool()
fixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程 其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子。和cacheThreadPool不同:fixedThreadPool池线程数固定,但是0秒IDLE(无IDLE)。这也就意味着创建的线程会一直存在。所以fixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器。
newScheduledThreadPool()
调度型线程池。这个池子里的线程可以按schedule依次delay执行,或周期执行 。0秒IDLE(无IDLE)。
SingleThreadExecutor
单例线程,任意时间池中只能有一个线程 。用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)。
线程池的关闭…
当我们不需要使用线程池的时候,我们需要对其进行关闭…有两种方法可以关闭掉线程池…
i.shutdown()…
shutdown并不是直接关闭线程池,而是不再接受新的任务…如果线程池内有任务,那么把这些任务执行完毕后,关闭线程池….
ii.shutdownNow()
这个方法表示不再接受新的任务,并把任务队列中的任务直接移出掉,如果有正在执行的,尝试进行停止…
线程管理中,主要就是同步,线程等待,唤醒等任务:
线程通讯:
当使用synchronized 来修饰某个共享资源时(分同步代码块和同步方法两种情况),当某个线程获得共享资源的锁后就可以执行相应的代码段,直到该线程运行完该代码段后才释放对该共享资源的锁,让其他线程有机会执行对该共享资源的修改。当某个线程占有某个共享资源的锁时,如果另外一个线程也想获得这把锁运行就需要使用wait() 和notify()/notifyAll()方法来进行线程通讯了。
Java.lang.object 里的三个方法wait() notify() notifyAll()

wait()
导致当前线程等待,直到其他线程调用同步监视器的notify方法或notifyAll方法来唤醒该线程。

wait(mills)
都是等待指定时间后自动苏醒,调用wait方法的当前线程会释放该同步监视器的锁定,可以不用notify或notifyAll方法把它唤醒。

notify()
唤醒在同步监视器上等待的单个线程,如果所有线程都在同步监视器上等待,则会选择唤醒其中一个线程,选择是任意性的,只有当前线程放弃对该同步监视器的锁定后,也就是使用wait方法后,才可以执行被唤醒的线程。

notifyAll()
唤醒在同步监视器上等待的所有的线程。只用当前线程放弃对该同步监视器的锁定后,也就是使用wait方法后,才可以执行被唤醒的线程。

内存泄漏:
Android 内存泄漏总结内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收。
1、非静态内部类的静态实例容易造成内存泄漏
[html] view plain copy 在CODE上查看代码片派生到我的代码片
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);

TextView label = new TextView(this);      
label.setText("Leaks are bad");      

if (sBackground == null) {      
    sBackground = getDrawable(R.drawable.large_bitmap);      
}      
label.setBackgroundDrawable(sBackground);      

setContentView(label);      

}

以上例子的内存泄漏都是因为Activity的引用的生命周期超越了activity对象的生命周期。也就是常说的Context泄漏,因为activity就是context。
想要避免context相关的内存泄漏,需要注意以下几点:
·不要对activity的context长期引用(一个activity的引用的生存周期应该和activity的生命周期相同)
·如果可以的话,尽量使用关于application的context来替代和activity相关的context
·如果一个acitivity的非静态内部类的生命周期不受控制,那么避免使用它;正确的方法是使用一个静态的内部类,并且对它的外部类有一WeakReference,就像在ViewRootImpl中内部类W所做的那样。
2、注册某个对象后未反注册
注册广播接收器、注册观察者等等:
3、资源对象没关闭造成的内存泄露
资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于Java虚拟机内,还存在于Java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄露。因为有些资源性对象,比如SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。因此对于资源性对象在不使用的时候,应该立即调用它的close()函数,将其关闭掉,然后再置为null.在我们的程序退出时一定要确保我们的资源性对象已经关
详细可以参考http://blog.csdn.net/gemmem/article/details/13017999,说的比较清楚
引起内存泄漏的原因很多,解决也比较复杂,一般开发工具会有工具支持分析内存使用情况,解决泄漏问题待续。。。
自定义view:
自定义view一般是继承view,通过重新绘制来实现一个view的过程,主要实现onDraw(绘制),onMeasure(测量),onLayout(摆放位置)等方法,完成绘制的过程。
在onDraw中可以直接用canvas,paint等来绘制,也可以绘制bitmap,绘制各种形状,甚至可以绘制文字等等。也可以对这些view添加动画。
至于组合控件比较简单,就是将多个view组合到一起,合并成一个整体的view向外提供。
可参考文章http://www.cnblogs.com/jiayongji/p/5560806.html,简单介绍了下自定义的view。
第三方框架:
okHttp、retrofit、RxJava、ButterKnife、Glide、Picasso
待续。。。
ViewPager+Fragment:
二者结合可以实现一般的底部导航,上面展示内容的需求,viewpager是v4包下的一个类,android.support.v4.view.ViewPager
Layout manager that allows the user to flip left and right through pages of data. You supply an implementation of aPagerAdapter to generate the pages that the view shows.
ViewPager is most often used in conjunction with Fragment, which is a convenient way to supply and manage the lifecycle of each page. There are standard adapters implemented for using fragments with the ViewPager, which cover the most common use cases. These are FragmentPagerAdapter andFragmentStatePagerAdapter; each of these classes have simple code showing how to build a full user interface with them.
Views which are annotated with the ViewPager.DecorView annotation are treated as part of the view pagers ‘decor’. Each decor view’s position can be controlled via its android:layout_gravity attribute. For example:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值