基本概念

  1. 分辨率:屏幕上显示的像素个数,单位尺寸内像素点越多,显示的图像就越清楚
    主流分辨率:480*800720*12801080*1920
  2. 像素密度
    240dpi(480*800)、320dpi(720*1280)、480dpi(1080*1920)
  3. 单位
    px:像素
    dp:设备独立像素(160dpi为标准)
    240dpi下,1dp=1.5px
    320dpi下,1dp=2px
    480dpi下,1dp=3px
    sp:等同于dp,用于描述字体大小
    240dpi下,1sp=1.5px
    320dpi下,1sp=2px
    480dpi下,1sp=3px

常见分辨率

  • 4:3
    VGA 640*480
    QVGA 320*240
    HVGA 480*320
    SVGA 800*600
  • 5:3
    WVGA 800*480
  • 16:9
    FWVGA 854*480
    HD 1920*1080
    QHD 960*540
    720p 1280*720
    1080p 1920*1080
  • Apple
    iPhone4/4s 960*640
    iPhone5/5s 1136*640
    iPhone6 1334*750
    iPhone6Plus 1920*1080
    小米1 854*480
    小米2 1280*720
    红米1/1s/note 1280*720

对应的DPI

  • HVGA mdpi
  • WVGA hdpi
  • FWVGA hdpi
  • QHD hdpi
  • 720p xhdpi
  • 1080p xxhdpi

最佳方案

  1. 选取320dpi下(720*1280)进行设计,此分辨率下1dp=2px

  2. 对于一切切图资源特殊处理
    输出多套分辨率的切图,例如480p和720p,在设计的时候要注意好切图区域的大小能被2和1.5整除的大小,如48p*48px96*96px等。

  3. 使用相对于单位进行标注

  4. 采用自适应布局

  5. 标注尽量采用相对关系

文字

中文字体:默认为Droid Sans Fallback,设计时可采用微软雅黑。
英文字体:Andriod4.x及以上采用Roboto,Andrio2.x和andriod3.x采用 Droid Sans。建议尽量采用系统默认字体。
Andriod规范建议,字号采用12sp、14sp、18sp、22sp等四个级别来设计。(实际设计时可以按实际情况调整)

总结

  1. 采用720*1280分辨率来进行设计。(设计时,采用偶数值进行设计,方便dp和px的转换)
  2. 开始标注了,标注尽量采用相对位置进行标注。
  3. 切图了,在720*1280下进行切图,可以完全适配720*1280后放大缩小切图资源
  4. 分别适配480*8001080*1920
  5. 不要忘记了,开发完后要进行bug测试(视觉方面的)

使用

作为图片加载库必须设置网络、SD卡权限

1
2
<uses-permission android:name="android.permission.INTERNET" />  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • 设置缓存目录
1
2
3
File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(),"imageloader/Cache");
// 设置ImageLoaderConfiguration
.discCache(new UnlimitedDiscCache(cacheDir));

配置ImageLoaderConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ImageLoaderConfiguration config = new ImageLoaderConfiguration
.Builder(context)
.memoryCacheExtraOptions(480,800) // 保存的每个文件的最大长宽
.discCacheExtraOptions(480,800,CompressFormat.JPEG,75,null) // 设置详细信息,最好不要设置
.threadPoolSize(3) // 线程池加载的数量
.threadPriority(Thread.NORM_PRIORITY - 2)
.denyCacheImageMultipleSizesInMemory()
.memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) // 缓存,可以自己实现
.memoryCacheSize(2 * 1024 * 1024)
.discCacheSize(50 * 1024 * 1024)
.discCacheFileNameGenerator(new Md5FileNameGenerator()) // 保存URI名称用MD5加密 可以使用HashCodeFileNameGenerator
.tasksProcessingOrder(QueueProcessingType.LIFO)
.discCacheFileCount(100) // 缓存文件数量
.discCache(new UnlimitedDiscCache(cacheDir)) // 自定义缓存路径
.defaultDisplayImageOptions(DisplayImageOptions.createSimple())
.imageDownloader(new BaseImageDownloader(context,5 * 1000,30 * 1000)) // 连接超时5s,读取超时30s
.writeDebugLogs()
.build(); // 开始构建
ImageLoader.getInstance().init(config);

加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 获取ImageLoader实例
ImageLoader imageLoader = ImageLoader.getInstance();
// 设置配置
DisplayImageOptions option;
options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.ic_launcher) // 设置图片在下载期间显示的图片
.showImageForEmptyUri(R.drawable.ic_launcher) // 设置图片Uri为空或者是错误的时候显示的图片
.showImageOnFail(R.drawable.ic_laucher) // 设置图片加载、解码过程错误的时候显示的图片
.cacheInMemory(true) // 设置下载的图片是否缓存在内存中
.cacheOnDisc(true) // 设置下载的图片是否缓存在SD卡中
.considerExifParams(true) // 是否考虑JPEG图像EXIF参数(旋转、翻转)
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED) //设置图片以何种编码方式显示
.bitmapConfig(Bitmap.Config.RGB_565) // 设置图片的解码类型
.decodingOptions(android.graphics.BitmapFactory.Options decodingOptions) // 设置图片的解码配置
.delayBeforeLoading(int delayInMillis) // 下载完的延迟时间
.preProcessor(BitmapProcessor preProcessor) // 设置图片加入缓存前,对bitmap进行设置
.resetViewBeforeLoading(true) // 设置图片在下载前是否重置,复位
.displayer(new RondedBitmapDisplayer(20)) // 是否设置为圆角
.displayer(new FadeInBitmapDisplayer(100)) // 是否显示加载渐入动画
.build(); // 构建完成

不需要的可以不做配置

  1. .imageScaleType(ImageScaleType imageScaleType) 设置图片的缩放方式
    EXACTLY:图像将完全按比例缩小到目标大小
    EXACTLY_STRETCHED:图片会缩放到目标大小
    IN_SAMPLE_INT:图像将被二次采样的整数倍
    IN_SAMPLE_POWER_OF_2:图片将降低2倍,直到下一减少步骤,使图像更小的目标大小
    NONE:图片不会调整
  2. .displayer(BitmapDisplayer displayer) 是设置 图片的显示方式
    RoundedBitmapDisplayer(int roundPixels) 设置圆角图片
    FakeBitmapDisplayer() 这个类什么都没做
    FadeInBitmapDisplayer(int durationMillis) 设置图片渐显的时间
    SimpleBitmapDisplayer() 正常显示一张图片

  

1
2
ImageLoader.getInstance().displayImage(imageUrl, imageView); // imageUrl代表图片的URL地址,imageView代表承载图片的IMAGEVIEW控件  
ImageLoader.getInstance().displayImage(imageUrl, imageView,options); // imageUrl代表图片的URL地址,imageView代表承载图片的IMAGEVIEW控件 , options代表DisplayImageOptions配置文件

加载监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
imageLoader.displayImage(imageUrl, imageView, options, new ImageLoadingListener() {  
@Override
public void onLoadingStarted() {
//开始加载的时候执行
}
@Override
public void onLoadingFailed(FailReason failReason) {
//加载失败的时候执行
}
@Override
public void onLoadingComplete(Bitmap loadedImage) {
//加载成功的时候执行
}
@Override
public void onLoadingCancelled() {
//加载取消的时候执行

}});

加载监听进度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
imageLoader.displayImage(imageUrl, imageView, options, new ImageLoadingListener() {  
@Override
public void onLoadingStarted() {
//开始加载的时候执行
}
@Override
public void onLoadingFailed(FailReason failReason) {
//加载失败的时候执行
}
@Override
public void onLoadingComplete(Bitmap loadedImage) {
//加载成功的时候执行
}
@Override
public void onLoadingCancelled() {
//加载取消的时候执行
},new ImageLoadingProgressListener() {
@Override
public void onProgressUpdate(String imageUri, View view, int current,int total) {
//在这里更新 ProgressBar的进度信息
}
});

注意事项

  1. 权限
  2. 必须初始化ImageLoader.getInstance().init(config)
  3. ImageLoader是根据ImageView的height,width确定图片的宽高
  4. 如果经常出现OOM
    • ①减少配置之中线程池的大小,.(.threadPoolSize)推荐1-5;
      • ②使用.bitmapConfig(Bitmap.config.RGB_565)代替ARGB_8888;
    • ③使用.imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者try.imageScaleType(ImageScaleType.EXACTLY)
      • ④避免使用RoundedBitmapDisplayer.他会创建新的ARGB_8888格式的Bitmap对象;
      • ⑤使用.memoryCache(new WeakMemoryCache()),不要使用.cacheInMemory();

其他

1
2
3
4
5
String imageUri = "http://site.com/image.png"; // from Web  
String imageUri = "file:///mnt/sdcard/image.png"; // from SD card
String imageUri = "content://media/external/audio/albumart/13"; // from content provider
String imageUri = "assets://image.png"; // from assets
String imageUri = "drawable://" + R.drawable.image; // from drawables (only images, non-9patch)

基本请求

1
2
3
4
5
6
7
8
9
10
11
12
13
StringRequest stringRequest = new StringRequest("http://www.baidu.com",new Response.Listener<String>(){
@Override
public void onResponse(String response) {
//
}, new Response.ErrorListener() {
@Override
public void onErrorResopnse(VolleyError error) {
//
}
}
});
// 添加请求道请求队列中
mQueue.add(stringRequest);

三个参数分别是目标服务器的URL地址,服务器响应成功的回调,服务器响应失败的回调

Post

1
2
3
4
5
6
7
8
9
StringRequest stringRequest = new StringRequest(Method.POST,url,listener,errorListenrer) {
@Override
protected Map<String,String> getParams() throws AuthFailureError {
Map<String,String> map = newHash<String,String>();
map.put("params1","value1");
map.put("params2","value2");
return map;
}
}

JsonRequest

JsonRequest是一个抽象类,有两个直接子类,JsonObjectRequest和JsonArrayRequest,分别用于处理JSON数据和JSON数组

1
2
3
4
5
6
7
8
9
10
11
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://m.weather.com.cn/data/101010100.html",null, new Response.Listener<JSONObject>() {  
@Override
public void onResponse(JSONObject response) {
Log.d("TAG", response.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});

ImageRequest

1
2
3
4
5
6
7
8
9
10
11
12
13
ImageRequest imageRequest = new ImageRequest(
"https://avatars3.githubusercontent.com/u/5416585?v=2&s=460",
new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
},0,0,Config.RGB_565,new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
imageView.setImageResource(R.drawable.default_image);
}
});

第三第四个参数指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定为0即表示不管图片多大都不压缩。

ImageLoader

1
2
3
4
5
6
7
8
9
10
11
import urllib
import urllib2

url = 'http://ave.bolyartech.com/params.php'
values = {'param1':'2','param2':'3'}
data = urllib.urlencode(values)
print data
req = urllib2.Request(url, data) # Post请求
response = urllib2.urlopen(req)
the_page = response.read() # 读取返回数据
print the_page

交换变量

1
2
3
x = 6
y = 5
x,y = y,x

行内if语句

1
print "Hello" if True else "World"	#  Hello

连接

不同类型的对象连接

1
2
3
4
5
6
7
8
9
10
11
12
13
nfc = ["Packers", "49ers"]
afc = ["Ravens", "Patriots"]
nfc + afc # ['Packers', '49ers', 'Ravens', 'Patriots']
print str(1) + " world"
>>> 1 world

print `1` + " world"
>>> 1 world

print 1, "world"
>>> 1 world
print nfc, 1
>>> ['Packers', '49ers'] 1

数字技巧

1
2
3
4
5.0//2 	#  向下取整 2
2**5 # 2的5次方
.3/.1 # 2.9999999999999996
.3//.1 # 2.0

数值比较

1
2
3
4
5
x = 2
if 3 > x > 1
print x
if 1 < x > 0
print x

同时迭代两个列表

1
2
3
4
nfc = ["Packers", "49ers"]
afc = ["Ravens", "Patriots"]
for teama, teamb in zip(nfc, afc):
print teama + " vs. " + teamb

带索引的列表迭代

1
2
3
teams = ["Packers", "49ers", "Ravens", "Patriots"]
for index, team in enumerate(teams):
print index, team

列表推导式

1
2
numbers = [1,2,3,4,5,6]
even = [number for number in numbers if number%2 == 0] # 取偶数

字典推导

1
2
teams = ["Packers", "49ers", "Ravens", "Patriots"]
print {key: value for value, key in enumerate(teams)}

初始化列表

1
items = [0]*3

列表转换成字符串

1
2
3
teams = ["Packers", "49ers", "Ravens", "Patriots"]
print ", ".join(teams)
>>> 'Packers, 49ers, Ravens, Patriots'

文件读写

Python内置的open()函数可以传入文件名和标示符打开一个文件对象

1
f = open('./test.txt','r')

r表示读,如果文件不存在open()函数会抛出一个IOError错误
如果文件打开成功,调用read()函数可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示

1
str = f.read()

因为文件对象会占用系统资源,所以使用完毕需要调用close()函数关闭文件
Python引入with语句帮助我们自动调用close方法

1
2
with open('./file','r') as f:
f.read()

read方法可以read(size)每次最多读取size个字节的内容,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list

1
2
for line in f.readlines():
print(line.strip()) # 把末尾的`\n`删掉

二进制文件

读取二进制文件比如图片、视频等,用rb模式打开即可:

1
f = open('./test.jpg','rd')

字符编码

读取非ASCALL编码的文本文件,必须以二进制模式打开,再解码,比如GBK编码的文件

1
2
3
f = open('./gbk.txt','rb')
u = f.read().decode('gbk')
print u

写文件

open函数传入标识符W或者wb表示写文件或写二进制文件

1
2
3
f = open('./test.txt','w')
f.write('Hello,world!')
f.close

也可以使用with语句

1
2
with open('./test.txt','w') as f:
f.write('Hello,world!')

写入特定编码也需要转码

文件操作

要操作文件需要导入Python内置的os模块

1
2
import os
os.name # 操作系统的名字

如果是posix说明系统是LinuxUnix或者Mac OS X,如果是nt就是Windows系统
获取系统详细信息可以调用uname()函数
通过os.environ可以看到系统环境变量的dict
要获取环境变量的某个值可以调用os.getenv()函数

操作文件和目录

  • os.path.abspath(‘.’) # 当前目录的绝对路径
  • os.path.join(‘/User/zoe’,’testDir’) # 合并路径
  • os.path.split(‘/Users/zoe/testDir/file.txt’) # 拆分目录
  • os.path.splitext(‘/path/file.txt’) # 拆分文件扩展名
  • os.mkdir(‘./testdir’) # 创建目录
  • os.rmdir(‘./testdir’) # 删除目录
  • os.rename(‘test.txt’,’test.py’) # 重命名
  • os.remove(‘test.txt’) # 删除文件
    os模块中并没有复制文件可以使用shutil模块提供的copyfile()函数
1
2
3
4
#  列出当前目录下的所有子目录
list1 = [x for x in os.listdir('.') if os.path.isdir(x)]
# 列出所有py文件
list2 = [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']

序列化

Python提供了cPicklepickle两个模块来实现序列化,两个模块功能一致,区别在于cPickle是C语言写的,速度快,pickle是纯Python写的,速度慢,用的时候先尝试导入cPickle,如果失败了,再导入pickle

1
2
3
4
try:
import cPickle as pickle
except ImportError:
import pickle

使用pickle.dumps()方法把任意对象序列化成一个str,然后,把str写入文件
也可以使用pickle.dump()直接把对象序列化写入file

1
2
3
4
5
d = dict(name='Bob',age=20,score=88)
str = pickle.dumps(d)
f = open('dump.txt','wb')
pickle.dump(d,f)
f.close()

反序列化是用pickle.loads()方法通过读取到字符串反序列化出对象,也可以直接用pickle.load()方法从file中直接反序列化出对象

1
2
3
f = open('dump.txt','rb')
d = pickle.load(f)
f.close()

Pickle的缺点很明显,只能用于Python并且可能不同版本的Python批次都不兼容

JSON

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

JSON类型 Python类型
{} dict
[] list
“string” str或u”unicode”
1234.56 int或float
true/flase True/False
null None

Python内置的json模块提供了完善的Python对象到JSON格式的转换

1
2
3
import json
d = dict(name='Bob',age=20,score=88)
json.dumps(d) # '{"age": 20, "score": 88, "name": "Bob"}'

同样dump()方法可以直接把JSON写入文件,loads()load()方法可以把反序列化

JSON进阶

对象序列化,需要实现一个转换函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import json
class Stundent(object):
def __init__(self,name,age,score):
self.name = name
self.age = age
self.score = score

s = Stundent('Bob',20,88)

def student2dict(std):
return {
'name':std.name,
'age':std.age,
'score':std.score
}

json.dumps(s,default=student2dict) # 先被student2dict转换成dict在顺利序列化为JSON

通常class实例都有一个__dict__属性,用来存储实例变量,所以也可以这么写:

1
json.dumps(s,default=lambda obj:obj.__dict__)

反序列化时

1
2
3
4
def dict2student(d):
return Student(d['name'],d['age'],d['score'])

json.loads(json_str,object_hook=dict2student)

try错误

1
2
3
4
5
6
7
8
try:
r = 10/0
print r
except ZeroDivisionError,e:
print 'except:',e
finally:
print 'finally'
print 'END'

在某段代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此执行完毕
如果没有发生错误发生,可以在except语句块后面加一个else,如果没有错误发生时,会自动执行else语句

记录错误

Python内置的logging模块可以非常容易地记录错误信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#  err.py
import logging

def foo(s):
return 10 / int(s)

def bar(s):
return foo(s) * 2

def main():
try:
bar('0')
except StandardError,e:
logging.exception(e)

main()
print 'END'

同样是出错,但程序打印完错误后会继续执行,并正常退出

抛出错误

错误是class,捕获一个错误就是捕获到该class的一个实例,因此,错误不是凭空产生的,而是有意创建抛出的。Python内置函数会抛出很多类型的错误,可以使用raise语句抛出错误

1
2
3
4
5
6
7
8
9
#  err.py
class FooError(StandarError):
pass

def foo(s):
n = int(s)
if n == 0:
raise FooError('invalid value:%s' % s)
return 10/n

断言

1
2
3
4
5
6
7
8
#  err.py
def foo(s):
n = int(s)
assert n != 0,'n is zero!'
return 10 / n

def main():
foo('0')

assert的意思是,表达式n != 0应该是True,否则,后面的代码就会出错(AssertionError)
Python解释器可以用-0参数来关闭assert

logging

1
2
3
4
5
6
7
#  err.py
import logging

s = '0'
n = int(s)
logging.info('n = %d' % n)
print 10 / n

logging.info()可以输出一段文本,可以使用logging.basicConfig(level=logging.INFO)指定记录信息的级别,有debuginfowarningerror,当指定level=INFO时,其他级别都不起作用,其他同理。

pdb

调试器,可以让程序以单步方式运行,可以随时查看运行状态

1
2
3
4
#  err.py
s = '0'
n = int(s)
print 10 / n

然后启动
$ python -m pdb err.py
以参数-m pdb启动后,pdb定位到下一步要执行的代码-> s = '0'输入命令l查看运行代码
输入n可以单步指定代码
也可以输入p 变量名来查看变量
输入q结束调试,退出程序

pdb.set_trace()

只需要import pdb然后在可能出错的地方放一个pdb.set_trace()就可以设置一个断点

1
2
3
4
5
6
7
#  err.py
import pdb

s = '0'
n = int(s)
pdb.set_trace()
print 10 / n

运行代码,程序自动在pdb.set_trace()暂停并进入pdb调试环境,可以用c继续运行