WordPress安装使用问题记录

file

本文记录在使用WordPress过程中的问题和解决。

安装

安装过程比较顺利,没有遇到大问题。安装环境是CentOS 6.5(DigitOcean的CentOS7 image里默认的yum源没有mysql-serve比较奇怪),安装步骤如下:

安装apache、mysql和php

 yum install httpd mysql-server mysql php php-mysql

下载wordpress安装包

wget https://wordpress.org/latest.tar.gz

解压缩到apache目录下

tar zxvf latest.tar.gz
mv /root/wp/wordpress /var/www/html

修改document root

修改/etc/httpd/conf/httpd.conf配置文件,添加域名配置:

ServerName www.mydomain.com

并在文件最后增加下面的设置:

<VirtualHost \*:80>
    DocumentRoot /var/www/html/wordpress
    ServerName www.mydomain.com
</VirtualHost>

如果有多个<VirtualHost>,需要在httpd.conf里启用下面这个配置:

NameVirutalHost *:80

启动apache和mysql服务器

service httpd start
service mysqld start

创建mysql用户(在mysql命令行里)

> create database wordpress;
> grant all privileges ON wordpress.* TO 'username'@'localhost' identified by 'mypassword' with grant option;
> flush privileges;

此时可以在浏览器里访问http://www.mydomain.com进入wordpress的安装向导,并按向导完成剩余的设置工作。

问题和解决

1、Wordpress向导提示无法建立"wp-config.php"文件

可手工在wordpress目录下建立此文件。

2、上传图片时提示“Unable to create directory wp-content/uploads/2014/11. Is its parent directory writable by the server?”

上传图片提示Unable to create directory wp-content/uploads/2014/11. Is its parent directory writable by the server?无法建立目录wp-content/uploads/2014/11。有没有上级目录的写权限?

试了网上一些办法没起作用,实际试验下来这样解决:

1) 在wp-content下建立uploads目录,并执行“chown -R nobody:nobody uploads”;

2) 将wp-content和wp-content/uploads的权限全部设置为777(不建议)。

3、上传plugin时提示需要ftp用户名密码

这也是由于权限不正确引起的,解决方法是将wordpress所在目录的所有者设为apache(在有些系统里可能是www):

chown -R apache:apache /var/www/html/wordpress

参考链接

4、加载google字体慢导致blog打开很慢

通过安装插件,用国内镜像字体网址替代google字体网址。参考链接

Arduino单片机使用和开发问题记录

file

1、将程序上传到板子时Arduino IDE提示“avrdude: stk500_getsync(): not in sync: resp=0x00”

网上查遇到这个问题的人比较多,有说驱动问题的,有说IDE设置问题的。具体到我遇到的这个情况,原因是板子上插了RF24无线传输模块(也许线还没有插对),拔掉以后再上传程序就正常了。

Continue reading "Arduino单片机使用和开发问题记录"

FreeSwitch安装配置记录

安装FreeSwitch

主要命令如下:

git clone -b v1.2.stable git://git.freeswitch.org/freeswitch.git  
cd freeswitch/  
./bootstrap.sh && ./configure && make && make install && make hd-sounds-install && make hd-moh-install && make samples

最后一个命令大约执行20分钟

缺省安装目录:/usr/local/freeswitch/

FreeSwitch所需的端口列表(需在防火墙设置里打开):http://wiki.freeswitch.org/wiki/Firewall

FreeSwitch默认只支持音频,为支持视频,修改vars.xml如下:

<X-PRE-PROCESS cmd="set" data="global\_codec\_prefs=PCMU,PCMA,GSM,**H264,H263-1998,H263**"/>  
<X-PRE-PROCESS cmd="set" data="outbound\_codec\_prefs=PCMU,PCMA,GSM,**H264,H263-1998,H263**"/>

检验是否安装成功

FreeSwitch安装后缺省用户是1000~1020,密码均为1234。用任意sip客户端(boghe, linphone, x-lite等等)登录,拨9664应该可以听到等待音乐,说明安装成功了。还有一些功能号码,总结如下:

\------------------  
号码 | 说明  
\----------------------  
9664 | 保持音乐  
9196 | echo,回音测试  
9195 | echo,回音测试,延迟5秒  
9197 | milliwatte extension,铃音生成  
9198 | TGML 铃音生成示例  
5000 | 示例IVR  
4000 | 听取语音信箱  
33xx | 电话会议,48K(其中xx可为00-99,下同)  
32xx | 电话会议,32K  
31xx | 电话会议,16K  
30xx | 电话会议,8K  
2000-2002 | 呼叫组  
1000-1019 | 默认分机号

曾遇到过一个问题,接通9664后立刻被自动挂断,接上摄像头后问题消失。

配置电信/联通双线

复制internal.xml为internal2.xml,修改internal2.xml里第一行的name为internal2,再将sip-ip和rtp-ip改为与internal里不同的那个公网ip,重启freeswitch即可。(用sofia status命令应该可以看到新建的internal2生效)

要使用智能域名解析,将vars.xml里的domain改为域名即可。

防掉线

在profile文件里修改nat-options-ping属性为true,大约每30秒FreeSwitch会发一个options包给客户端以保持连接。
http://wiki.freeswitch.org/wiki/Sofia.conf.xml#nat-options-ping

中文语音

中文语音包下载和使用方法:https://groups.google.com/forum/#!topic/freeswitch-cn/gYXmAv7sGKU

参考资料

http://www.dujinfang.com/2010/04/14/freeswitch-chu-bu.html

安装配置opensips过程记录

本文操作系统为CentOS,所用Opensips版本为1.8.2。

Update2013/6/27: 版本1.9.1也已验证通过,下载地址为http://opensips.org/pub/opensips/latest/src/opensips-1.9.1_src.tar.gz

安装CentOS

(若已有环境可跳过此步骤)

1、安装虚拟机,VMWare Server 2.0遇到问题无法显示console(Chrome里),换为Virtualbox 4.2后可正常使用;

2、在虚拟机里安装CentOS 6.3,选择standard server类型安装。

对这种纯命令行界面的虚拟机,可以用telnet直接访问,操作剪贴板什么的比较方便;

若虚拟机映射的网卡没有自动启动,用ifup eth0命令启动。

若(Virtualbox的)虚拟机是复制过来的,可能需要先删除 /etc/udev/rules.d/70-persistent-net.rules,再修改/etc/sysconfig/network-scripts/ifcfg-eth0里的HWAddr地址。

若需要配置网卡ip地址,先ifconfig -a查看网卡设备号和MAC地址,然后编辑/etc/sysconfig/network-scripts/ifcfg-eth0文件,示例如下:

DEVICE="eth0" BOOTPROTO\="none" HWADDR\="08:00:27:81:30:F4" NM\_CONTROLLED\="yes" ONBOOT\="yes" TYPE\="Ethernet" UUID\="dcd43c45-adf4-480b-b461-179ee8d2e8d6" IPADDR\=192.168.1.120 NETMASK\=255.255.255.0 GATEWAY\=192.168.1.1

/etc/resolv.conf里指定dns以便安装软件包(CentOS6以后可以在ifg-eth0里指定dns了)

nameserver 202.181.202.140 nameserver 208.67.220.220

安装Opensips(根据官方的Tutorial视频整理的主要步骤)

opensips提供了一个视频教程(这个页面有下载链接,90M),推荐使用menuconfig方式,更方便且不容易出错。以下为步骤摘要:

yum install gcc make
yum install flex bison ncurses libncurses-dev ncurses-devel
yum install mysql mysql-server mysql-libs mysql-devel

wget http://opensips.org/pub/opensips/1.8.2/src/opensips-1.8.2\_src.tar.gz
tar zxvf opensips-1.8.2\_src.tar.gz
cd opensips-1.8.2-tls

make menuconfig (勾选db\_mysql,其他不用动)
菜单里选"Compile And Install Opensips"
退出menuconfig

vi /usr/etc/opensips/opensipsctlrc,把与mysql有关的注释去掉(DB\_PATH和USERCOL保留注释)
service mysqld start  
opensipsdbctl create(提示的两个问题都选no)
osipsconfig (选择ENABLE\_TCP,USE\_AUTH,USE\_DBACC,USE\_DBUSERLOC,USE\_DIALOG,然后generate residential script)  
用生成的opensips\_residential\_xxx.cfg替换原先的opensips.cfg

vi /usr/etc/opensips/opensips.cfg (改listen地址和mpath,后者一般是/usr/lib/opensips/modules)  
opensipsctl start (netstat -anp查端口)  
service iptables stop (关闭防火墙)

如果启动opensips时提示错误,检查/var/log/messages(若opensips.cfg里设置了log_stderror=no则日志都进入此文件,链接),一般是模块参数未设置引起的。例如在log里发现:

“ERROR:uri:db\_checks\_fixup1: configuration error - no database URL is configured!”

则在opensips.cfg里的loadmodule "uri.so"后添加modparam("uri", "db\_url","mysql://opensips:opensipsrw@localhost/opensips")即可。

创建测试用户:

opensipsctl add 101 101

如果创建用户时提示ERROR: domain unknown: use usernames with domain or set default domain in SIP\_DOMAIN,可修改opensipsctlrc文件将SIP\_DOMAIN设为本机域名或IP地址。

进一步配置Opensips

设置日志输出方式

opensips.cfg里有几个参数控制日志的输出:

debug=3 #此值控制日志输出的详细程度,3为普通,4为详细(会产生很多日志)。  
log\_stderror=no #设置为no表示将日志输出到文件,否则输出到控制台(应该是以前台方式启动opensips服务时才有用)。  
log\_facility=LOG\_LOCAL0 #应该是用于在syslog服务的配置文件里区分opensips产生的日志(见下面“使用独立的log文件”)。  
fork=yes #设置为yes表示在后台启动opensips服务,设置为no表示在前台启动。

使用独立的log文件

opensips使用syslog服务,所以缺省情况下日志会进入/var/log/message这个文件,如果希望使用独立的log文件,可以这样设置:

touch /var/log/opensips.log  
vi /etc/rsyslog.conf  --> 增加一行:local0.\*             /var/log/opensips.log  
/etc/init.d/rsyslog restart

配置STUN模块

opensips自带一个stun模块,可以实现stun服务器的功能(需要双网卡)。配置方法也很简单(官方文档),在opensips.cfg里添加如下内容:

\#### STUN module  
loadmodule "stun.so"  
modparam("stun", "primary\_ip", "11.22.33.44") #opensips服务器的ip地址  
modparam("stun", "primary\_port", "5060") #必须与opensips的udp端口相同(一般是5060)  
modparam("stun", "alternate\_ip", "55.66.77.88") #另一网卡的ip地址  
modparam("stun", "alternate\_port", "3479") #另一端口号

配置好stun以后,可以使用stun-client来测试,以windows下为例,测试命令为:

stun-client-0-96.exe 11.22.33.44:5060 -v

安装配置RTPProxy模块

rtpproxy模块通常与nathelper模块一起使用。首先要确保服务器上已经安装了rtpproxy,启动rtpproxy:

rtpproxy -F

然后在opensips.cfg文件里做如下配置:

loadmodule "rtpproxy.so"  
modparam("rtpproxy", "rtpproxy\_sock", "unix:/var/run/rtpproxy.sock") # CUSTOMIZE ME

安装配置MediaProxy模块

MediaProxy官方文档链接

一个在CentOS6上安装MediaProxy2.5.2的参考链接

下载mediaproxy源码(和所需要的各种依赖包),并安装(过程略)。安装完成后:

config.ini.sample复制到/etc/mediaproxy/config.ini,把tls目录也复制过来。

echo 1 > /proc/sys/net/ipv4/ip\_forward
media-dispatcher restart
media-relay restart

opensips.cfg里配置mediaproxy模块,如下:

\#### MediaProxy module  
loadmodule "mediaproxy.so"  
modparam("mediaproxy", "disable", 0)  
#modparam("mediaproxy", "mediaproxy\_socket", "/var/run/mediaproxy/dispatcher.sock")  
modparam("mediaproxy", "mediaproxy\_timeout", 500)  
modparam("mediaproxy", "signaling\_ip\_avp", "$avp(nat\_ip)")  
modparam("mediaproxy", "media\_relay\_avp", "$avp(media\_relay)")

若mediaproxy提示No suitable relay found,可能是certification方面的问题。 参考链接

(未完)

抓取SIP包

在Opensips所在服务器上使用tcpdump可以抓取SIP包以便分析问题(注意要抓取的网卡是eth0或eth1):

tcpdump -nqt -s 0 -A -i eth0 port 5060 -w /home/capture\_file\_name.pcap

参考:http://jonathanmanning.com/2009/10/26/how-to-voip-sip-capture-with-tcpdump-on-linux/

要抓手机上的包稍微复杂一些,要先root手机,然后把tcpdump复制到手机上使用:

adb shell
su
tcpdump -nqt -s 0 -w /sdcard/packets\_xx.pcap
adb pull /sdcard/packets\_xx.pcap

具体请参考这篇文章

安装opensips-cp

从sourceforge下载opensips-cp源码压缩包后,里面附有名为INSTALL的文档,建议根据这个文档进行安装,网上能查到的一些资料往往是过期的或不准确的。

yum install httpd php php-mysql php-xmlrpc php-pear

pear install MDB2
pear install MDB2#mysql
pear install MDB2#mysqli
pear install log

/etc/php.ini里:
short\_open\_tag置为On
/usr/share/pear加到inculde\_path变量里(一些教程写的是加/usr/share/php,实际检验要加/usr/share/pear)

wget http://sourceforge.net/projects/opensips-cp/files/opensips-cp/5.0/opensips-cp\_5.0.tgz/download
tar -zxvf opensips-cp\_5.0.tgz

将解压缩后的文件夹(名字一般是“5.0”)复制到/var/www目录下,并改名为opensips-cp

vi /etc/httpd/conf/httpd.conf,添加下面一行:
Alias /cp "/var/www/opensips-cp/web"

chown apache:apache /var/www/opensips-cp/config/access.log (如果是其他版本linux,用户名可能是www-data或其他)

(随源码附带的安装文档INSTALL有点看不懂,postgresql应该是与mysql二选一。)

安装必须的admin:

cd /var/www/opensips-cp/config/tools/admin/add\_admin/
mysql -Dopensips -p<ocp\_admin\_privileges.mysql
mysql -uroot opensips进入mysql命令行,执行下面的命令添加管理员用户:
INSERT INTO ocp\_admin\_privileges (username,password,ha1,available\_tools,permissions) values ('admin','admin',md5('admin:admin'),'all','all');

安装cdrviewer:

cd /var/www/opensips-cp/config/tools/system/cdrviewer/
mysql -Dopensips -p < cdrs.mysql
mysql -Dopensips -p<opensips\_cdrs.mysql
cd /var/www/opensips-cp/cron\_job
vi generate-cdrs\_mysql.sh (填写数据库连接信息)

注意,generate-cdrs\_mysql.sh这个文件里的call opensips\_cdrs\_1\_6()可能要改为call opensips\_cdrs(),必须要与opensips\_cdrs.mysql里定义的名称一致。

vi /etc/crontab 添加定时任务,例如每三分钟生成一次:

\*/3 \* \* \* \* root /var/www/opensips-cp/cron\_job/generate-cdrs\_mysql.sh

安装smonitor:
(此处INSTALL文档有笔误,这里已更正)

cd /var/www/opensips-cp/config/tools/system/smonitor/ 
mysql -Dopensips -p < tables.mysql

vi /etc/crontab 添加定时任务,例如每分钟一次:

\* \* \* \* \* root php /var/www/opensips-cp/cron\_job/get\_opensips\_stats.php > /dev/null

安装add_user:

(最前面已经装过了ocp\_admin\_privileges.mysql,这里应该不需要再做一次,INSTALL文档的小问题不少)

启动opensips-cp:

service mysqld start
service httpd start

打开浏览器访问http://xxx.xxx.xxx.xxx/cp/ 应该能看到登录界面,用之前创建的admin用户登录。

其他有用链接

Opensips官方论坛

关于sip和sip的客户端

Best practices for SIP NAT traversal

一些问题和解决

服务器端保持连接:使用 nat_traversal或nathelper模块(根据讨论组里的一些帖子,这两个模块的功能几乎相同),让opensips每个一段时间向客户端发一个包,使得路由器上的端口映射将保持(即洞口一直打开)。在客户端抓包时应该可以看到这些来自服务器的sip包,一般名称为OPTIONS。

客户端接收到INVITE命令后没有RING:很奇怪的问题,但在我这里时不时的发生,客户端程序为Boghe v2.0.153.836,暂时还没有找到原因和解决方法。

路由器修改SIP包:使用Volans VE602W作为路由器,从客户端发出的REGISTER包里的Via字段会被修改为公网地址,导致opensips服务器判断是否来自内网(nat_traversal模块中的nat_client_test方法)失败,其他三个路由器(TPLink、Mercury和Buffalo没有这种情况)。暂时没有找到解决方法。这里有一个类似问题。

客户端接收到重复的OPTIONS消息:由于重复(通过不同路由器)登录到opensips,Opensips有时会发送多个OPTIONS包给客户端,直到服务器认为客户端已经掉线。若客户端在REGISTER消息的Contact字段里添加了expires=xxx时,服务器会在location表里记录客户端失效的时间,若这个时间很长则服务器会一直尝试连接客户端。

有时接通以后没有视频画面:遇到过这样的问题:拨打十次,每次都能接通,但有时没有画面。后来发现是服务器防火墙禁止了一些端口(用iptables --list INPUT查询发现服务器仅允许udp 35000~50000进入)。解决方法是启动rtpproxy时指定端口范围,例如rtpproxy -m 40000 -M 50000 -F。

Contact URI字段没有被改为公网IP:通过增加调试信息发现虽然fix_nated_contact()方法已经被调用,但服务器端发回的sip包里Contact URI里的内网地址并没有被替换为公网地址。在公司没有这个问题,在家有这个问题(更换路由器无效),暂时没找到原因。(更正:这个问题本身有误,应该观察从服务器返回的200OK消息,而不是服务器接收到的原始消息)

单向有声音/视频或仅音频能拨通:可能是SIP包的长度超出了网络设备的MTU值,在UDP协议下,如果客户端不能处理过长的SIP包(一般是带有SDP的那些SIP消息,而且视频请求比音频请求产生的SIP消息要大),多出的部分可能会被丢弃,导致服务器发送/接收的SIP包失效。解决办法有:1)切换到TCP协议;2)精简SIP包尺寸,有些客户端生成的SIP包里带有不必要的字段可以删除掉(如果能够定制开发的话),另外这里有一个参考链接;3)使用支持超长UDP包或SIP包比较小的客户端(我用的基于doubango的boghe这部分做的不太好,换用x-lite后发现同样的请求SIP包长度小很多:18xx vs 10xx)。

清除在线用户:opensipsctl ul rm id可以删除一个在线用户,一个用户段时间内多次登录时会造成重复记录,这时可能需要清除掉这个用户的在线状态。

(本文原文链接:https://www.cnblogs.com/bjzhanghao/archive/2013/02/13/2910903.html)

Android SDK开发包国内下载地址

不知道是因为最近kaihui还是怎么的,打开android sdk官方网站特别的慢,想下载最新版本的platform几乎变成不可能完成的任务,不知道为什么Google不像Apache那样在各国设立镜像站。为了预防今后再出现这样的情况,这次干脆把android开发所需要的各种包总结一下,顺便提供本地下载链接,省得以后找起来麻烦。

通过分析SDK Manager里要用到的repository文件,我下载了目前google提供的各类安卓开发包并上传到了网盘。由于网盘有CDN支持,即使不用迅雷,下载速度依然很快。如果你从官网下载很慢,不妨试试这些国内链接。

更新2017/12/20:新增了android studio 145 for windows版本。

更新2016/8/21:更新了platform-tools和tools的版本,并修复了部分失效链接。

更新2016/3/17:更新了android platform 6.0下载的版本(r01->r02),增加了level 23的document下载,增加了level22和23的source下载,增加了material design icons下载。注:部分百度网盘链接增加了提取码,原因和方法见说明

更新2015/12/18:修复了android studio、document、source和sys-img的失效链接,增加了mac和linux版本的android studio下载。

更新2015/9/21:增加了android 6.0的仿真器rom下载(x86),增加了1.3.2版android studio的下载。

更新2015/9/1:增加了android 6.0 (level 23)的sdk下载;增加support r22和support r23的下载。

更新2015/6/29:增加了android 5.1.1的platform下载。

更新2015/3/11:完善了sysimg部分,增加了Level 21的x86平台sysimg链接。

更新2015/1/5:增加了android 5.0的sample下载。

更新2014/12/19:增加了Support包下载,更新了doc资源版本和下载链接;更新了Android Studio版本到1.0.1,更新了SDK Tools到r24。

更新2014/12/2:更新了SDK Tools的版本,从22.6到23.0.2;增加了Android Studio下载。

更新2014/10/23:增加了部分Android-L资源下载。

更新2014/10/23:感谢CodeDream分享的另一个国内下载网址,内容比较全(没有adt-bundle)速度较快,推荐。

更新2014/8/15:更新了level14-17的samples包;增加了level18-20的samples包;增加了level20版本的源码包;增加了level18-20的platform包。

更新2014/8/7:增加了level18和level19的源码包,并更新了其他版本源码包的链接。

更新2014/7/1: 百度和微云的大部分链接都失效了,重新更新了adt-bundle和sdk的下载链接,部分文件版本有升级。

更新2014/03/11: 更新了adt-bundle和sdk的下载链接,sdk版本由22.3更新为22.6,增加了腾讯微云的下载链接作为备份。

更新2013/12/27: bd网盘病得不轻,分享链接以后几分钟再访问,就显示“啊哦,你来晚了”。甚至网盘里的文件都被删除,导致楼主硬盘里也没有这些文件了,回收站里只能恢复出空文件夹。楼主会再花几天时间重新下载,放到其他网盘里,见谅。“善待生命,远离bd网盘。”

更新2013/12/27: 最近bd网盘又犯病,导致很多链接都失效了,如果楼主更新链接不及时,请访问后面这个地址对照文件名挑选所需文件:http://pan.baidu.com/s/1i3iIsOP,口令eer5。

更新2013/11/13: 更新了adt-bundle的版本到20131030,更新了android sdk的版本到r22.3。

更新2013/8/22: 更新了adt-bundle的版本到20130729。

更新2013/6/5:更新了adt-bundle-17-windows-64bit.zip的网盘链接。

更新2013/3/4:有一小部分下载链接失效,经查是由于未知原因被百度网盘禁止分享了,请过一段时间再试。

更新2013/3: 有些包分操作系统版本,例如windows版、macos版和linux版,下载时注意文件名里的标识。

此帖长期更新,若有未及时更新的版本或失效链接,请留言通知主页君。

Android Studio

Google官方推荐新入门用户使用基于IntelliJ的Android Studio IDE进行开发,提供了更多的功能,原有基于Eclipse的ADT开发环境已降低更新频率,并将在2015年底左右停止更新。

文件名文件大小说明其他下载地址
android-studio-bundle-141.2288178-windows.exe1.1GWindows版,所需的全都包含了,推荐。提取码见说明官网
android-studio-ide-145.3276617-windows.zip340MWindows版,解压缩直接使用。 
android-studio-ide-141.2178183-windows.exe307MWindows版,仅IDE部分 
android-studio-ide-141.2288178-mac.dmg347MMac版。提取码见说明官网
android-studio-ide-141.2288178-linux.zip363MLinux版。提取码见说明官网

注:Android Studio有自动更新功能,即使是旧版本(v0.8.x)的,也可以先升级到v0.9.9,然后再升级到v1.x,升级包体积不大还是比较方便的。

可能是我电脑比较差(i5/8G/250G),感觉Android Studio运行起来比基于Eclipse的开发环境卡很多,加上操作方式和工程结构不一样,一下子很难适应。(注2015/9/21:1.3.2版感觉比1.0.1版快了很多,配合x86的仿真器实用性大大增强,推荐大家使用。)

ADT Bundle

多合一下载包,里面包含了:sdk + 特定版本platform + eclipse + adt + 兼容包,解压缩即可使用。唯一的缺点是体积比较大,如果你是从零开始配Android开发环境就下载吧。

文件名文件大小说明其他下载地址
adt-bundle-windows-x86-20131030.zip480.0M Android 4.2多合一开发包, Windows 32位。官网 微云
adt-bundle-windows-x86_64-20140321.zip510.0M Android 4.2(4.4?)多合一开发包, 注意所含eclipse是64位的。官网 微云
adt-bundle-mac-x86_64-20131030.zip448.0M Mac OS官网 微云
adt-bundle-linux-x86-20131030.zip473.0M Linux 32位官网 微云
adt-bundle-linux-x86_64-20131030.zip474.0M Linux 64位官网 微云

假设你把sdk安装到d:\android-sdk,则里面的目录结构应该是这样的:

d:\android-sdk\tools
这个目录里有ddms.bat等文件

d:\android-sdk\system-images\android-17\armeabi-v7a
这个目录里有userdata.img等文件(r14及以上才有这个目录)

d:\android-sdk\platforms\android-4.0.2
这个目录里有android.jar等文件

d:\android-sdk\platform-tools
这个目录里有adb.exe等文件

d:\android-sdk\extras
这个目录里有android等目录

当你下载下面列出的部件时,也请参考上面的目录结构示例将内容放在正确的位置。

Android SDK

SDK就是开发包,里面包含了两大类命令行工具:一类是SDK Tools,如android.bat、ddms.bat和emulator.exe等等,这些命令位于<sdk>\tools目录,但运行仿真器所需的rom并不包含在内;另一类是Platform Tools,包含了如adb.exe、aidl.exe、aapt.exe等等命令,它们位于<sdk>\platform-tools目录。

请区别清这几个名称:SDK、SDK Tools、Platform Tools、Platform Package。

文件名文件大小说明其他下载地址
installer_r24.3.4-windows.exe133M需要提取码,见说明官网
android-sdk_r24.3.4-windows.zip178M需要提取码,见说明官网
installer_r24.0.2-windows.exe87.1M 官网
android-sdk_r24.0.2-windows.zip133.0M 官网
installer_r23.0.2-windows.exe88.7M官方推荐下载这个安装包,是32位和64位通用的。官网 微云
android-sdk_r23.0.2-windows.zip134.0M文件名里虽然是"sdk",其实不含platform-tools,
叫"sdk tools"更合适。
官网 微云
android-sdk_r23.0.2-macosx.zip86.7M官网 微云
android-sdk_r23.0.2-linux.tgz134.0M官网 微云

SDK安装/解压缩后,只具有基本的功能,还无法开始进行开发。你还需要platform-tools和至少一个platform package才算完整。在eclipse里通过SDK Manager是可以在线安装的,但有时手动安装也许更快。

文件名文件大小说明其他下载地址
platform-tools_r24-linux.zip3M   
platform-tools_r24-macosx.zip3M   
platform-tools_r24-windows.zip3M   
platform-tools_r23.1.0-linux.zip3M   
platform-tools_r23.1.0-macosx.zip3M   
platform-tools_r23.1.0-windows.zip2M   
platform-tools_r14-linux.zip10.4M将platform-tools目录解压到sdk所在目录   官网
platform-tools_r14-macosx.zip10.8M官网
platform-tools_r14-windows.zip10.6M官网

假如你已经安装过android sdk,想单独升级tools,可以从下面的文件中选择所需要的压缩包下载,然后替换掉sdk目录下的对应子目录。

文件名文件大小说明其他下载地址
tools_r25.2.2-linux.zip261M   
tools_r25.2.2-macosx.zip187M   
tools_r25.2.2-windows.zip288M   
tools_r20.0.3-linux.zip78.8M和第一个表里的"sdk"相比,只少了avd manager和sdk manager。
建议仅在需要升级时下载,用tools目录替换原来的同名目录。
官网
tools_r20.0.3-macosx.zip55.5M官网
tools_r20.0.3-windows.zip86.0M官网

ADT

ADT(Android Development Tools)是一个Eclipse插件,如果没有这个插件,我们开发Android应用就得不停在命令行里敲各种命令,除非你是记事本开发狂人,否则还是老老实实享受ADT带来的方便吧。至于Eclipse本身可以去eclipse.org下载,这里就不再提供了。

文件名文件大小说明其他下载地址
ADT-21.0.0.zip12.9M 官网 微云
ADT-20.0.3.zip11.8M 官网 微云
ADT-12.0.0.zip5.4M如果你不习惯新版的ADT,这个版本也许适合你。官网 微云

ADT的版本号基本上是跟着SDK Tools走,即每出一个新版本的SDK Tools,就出一个同样版本的ADT。不过实际使用中,即使是老版本的ADT也能对新版SDK支持得不错。

Platforms

Android系统版本从1.0到写这篇帖子时的4.2,大大小小已经经历了10多个版本,每个版本发布时Google都会提供一个sdk platform package供开发者使用。一般这个压缩包是在Eclipse开发环境里用SDK Manager来下载的,但在国内选择这种方式会很痛苦,因为每个platform都有几十上百兆大,装一个就得几个小时,好像还不能断点续传(?)。

在国内,更方便的做法是先下载离线包,然后解压缩到android sdk的安装目录下,重启Eclipse后就会自动识别出来。

文件名文件大小说明其他下载地址
android-23_r02.zip67.2MAndroid 6.0 revision 02,提取码见说明官网
android-23_r01.zip67.1MAndroid 6.0 
android-22_r02.zip63.7MAndroid 5.1.1 
android-21_r01.zip63.9M Android 5.0东软
android-L_r04.zip66.2MAndroid L东软
android-20_r01.zip60.6M 官网
android-19_r03.zip60.8M 官网
android-18_r01.zip46.4M 官网
android-17_r01.zip 45.6MAndroid 4.2官网 微云
android-16_r03.zip45.7MAndroid 4.1, 4.1.1, JELLY_BEAN官网 微云
android-15_r03.zip42.3MAndroid 4.0.3, 4.0.4, ICE_CREAM_SANDWICH_MR1官网 
android-14_r03.zip43.7MAndroid 4.0, 4.0.1, 4.0.2, ICE_CREAM_SANDWICH官网 微云
android-3.2_r01-linux.zip103.0MAPI Level 13, HONEYCOMB_MR2
文件名虽然有linux但其实是平台无关的,下同,直至2.1。
官网 
android-3.1_r03-linux.zip101.0MAPI Level 12, HONEYCOMB_MR1官网 
android-3.0_r02-linux.zip99.6MAPI Level 11, HONEYCOMB官网 
android-2.3.3_r02-linux.zip81.5MAPI Level 10, GINGERBREAD_MR1官网 微云
android-2.3.1_r02-linux.zip75.0MAPI Level 9, GINGERBREAD官网 
android-2.2_r03-linux.zip71.1MAPI Level 8, FROYO官网 
android-2.1_r03-linux.zip66.8MAPI Level 7, ECLAIR_MR1官网 
android-2.0_r01-windows.zip72.7MAPI Level 5, ECLAIR官网 
android-2.0_r01-macosx.zip71.4M官网 
android-2.0_r01-linux.zip71.6M官网 
android-2.0.1_r01-windows.zip76.6MAPI Level 6, ECLAIR_0_1官网 
android-2.0.1_r01-macosx.zip75.3M官网 
android-2.0.1_r01-linux.zip75.5M官网 
android-1.6_r03-windows.zip61.6MAPI Level 4, DONUT官网 
android-1.6_r03-macosx.zip59.5M官网 
android-1.6_r03-linux.zip60.5M官网 
android-1.5_r04-windows.zip52.0MAPI Level 3, CUPCAKE官网 
android-1.5_r04-macosx.zip50.0M官网 
android-1.5_r04-linux.zip50.8M官网 
android-1.1_r1-windows.zip44.6MAPI Level 2   官网 
android-1.1_r1-macosx.zip43.4M官网 
android-1.1_r1-linux.zip43.3M官网 

更详细的Android版本对照表可以参考这里

System Images

从Level 14开始,每个platform package都被分为两部分了,一部分包含这个版本下开发所需的jar包,例如android-16_r03.zip;另一部分是system image(即仿真器rom文件),例如sysimg_armv7a-16_r03.zip。如果你要在电脑上使用仿真器,需要有对应版本的system image文件;而如果你只在真机上调试程序,则不需要下载仿真器rom。

下载后的sysimg文件直接解压缩到sdk/system-images目录下,例如sdk/system-images/android-17。

文件名文件大小说明其他下载地址
sysimg_x86_64-23_r03.zip322Mx86版 64位东软
sysimg_x86-23_r03.zip229Mx86版东软
sysimg_x86_64-21_r01271Mx86版官网
sysimg_armv7a-17_r01.zip111.0M仅仿真器rom官网 微云
sysimg_armv7a-16_r03.zip107.0M仅仿真器rom官网 微云
sysimg_armv7a-15_r02.zip91.7M仅仿真器rom官网 
sysimg_armv7a-14_r02.zip95.0M仅仿真器rom官网 

最近的版本除了arm仿真器,还有x86仿真器可供下载(由intel提供),在x86电脑上运行能够提速。

另:补充 凌寒00 网友提供的安装说明:“在sdk下建system-images文件夹,然后进入其中建立对应于api level的文件夹 类似于这样 android-17 ,然后把下载的映像文件解压后放到里面就可以了。
...路径示例 F:\adt-bundle-windows-x86_64-20140624\sdk\system-images\android-17\armeabi-v7a。”

Documents

供Android开发参考用的官方文档,文件比较大。我习惯有一个本地的文档,然后配合Everything使用,非常方便,文档里有不少内容源码里是没有的。

文件名文件大小说明其他下载地址
docs-23_r01.zip316M需要提取码,见说明 
docs-L_r01.zip198.0M  
docs-21_r01.zip258.0M  
docs-19_r02.zip172.0M  
docs-17_r01.zip163.0M 官网
docs-16_r03.zip156.0M 官网
docs-15_r02.zip126.0M 官网
docs-14_r01.zip104.0M 官网

Sources

我比较懒,从来没有用git下载过android源代码,如果你想用git下载,可以参考这篇文章里的操作方法。

官方目前提供了一些源代码压缩包,如下表所列,这些压缩包可以attach到eclipse里方便随时F3查看;最重要的是,有了源代码以后,Eclipse里代码辅助出来的参数名再也不会是"arg0"、"arg1"这样的了。

文件名文件大小说明其他下载地址
sources-23_r01.zip30.2M需要提取码,见说明 
sources-22_r01.zip27.5M需要提取码,见说明 
sources-21_r01.zip26.9M 东软
sources-20_r01.zip22.2M 官网
sources-19_r01.zip20.6M 官网 微云
sources-18_r01.zip19.2M 官网 微云
sources-17_r01.zip18.0M 官网 微云
sources-16_r02.zip17.0M 官网
sources-15_r02.zip15.7M 官网 
sources-14_r01.zip15.4M 官网 
sources-8-froyo.zip33.3M (非官方)官网
sources_2.1.zip30.0M (非官方)官网
sources_1.6.zip22.8M (非官方)官网 

Samples

Google提供了丰富的开发示例,如果时间允许多看看这些例子代码和运行效果,对提升手机应用的设计开发能力肯定大有帮助。

文件名文件大小说明其他下载地址
samples-23_r02.zip121M需要提取码,见说明 
samples-22_r06.zip118M需要提取码,见说明 
samples-21_r04.zip91.3M从官方下载后压缩得到。 
samples-L_r02.zip39.2M 东软
samples-20_r01.zip40.9M 官网
samples-19_r05.zip30.4M 官网
samples-18_r01.zip18.9M 官网
samples-17_r01.zip14.1M 官网
samples-16_r01.zip14.0M 官网
samples-15_r02.zip15.6M 官网 
samples-14_r02.zip15.5M 官网 
samples-3.2_r01-linux.zip11.6M 官网 
samples-3.1_r01-linux.zip11.5M 官网 
samples-3.0_r01-linux.zip11.4M 官网 
samples-2.3_r01-linux.zip8.1M 官网 
samples-2.3.3_r01-linux.zip8.1M 官网 
samples-2.2_r01-linux.zip7.6M 官网 
samples-2.1_r01-linux.zip7.3M 官网 

Supports

兼容包。要支持低版本android系统需要在项目里引入相应的兼容包,例如Android 2.1里没有Fragment的概念,那么要开发一个使用Fragment的应用,就要引入support-v4这个jar包,并使用android.support.v4.Fragment来(替代android.app.Fragment)进行开发。

文件名 文件大小说明其他下载地址 
support_r23.2.110.3M需要提取码,见说明 
support_r23.zip9.1M 东软
support_r22.2.zip8.5M 东软
 support_r19.1.zip 4.9M  
 support_r20.zip 5.25M  
 support_r21.0.3.zip 7.32MCardView,GridLayout都在这里面,Library源码形式 

补充解释一下,support-v4表示需要手机上的android版本至少是level 4(即1.6)才能运行;support-v13包含support-v4里的所有api,所以如果项目里包含了v13.jar就不用再包含v4.jar。

Material Design Icons

Google官方提供的Material Design图标库,每个图标有多个颜色和多个尺寸可供使用。

文件名文件大小说明其他下载地址
material-design-icons-master.zip57.5M需要提取码,见说明 

关于提取码的说明

从今年(2016年)开始,新增的网盘下载链接都添加了提取码,主要有两个原因:1)完全公开的百度网盘分享地址经常失效,博主要花大量时间更新失效链接,有提取码的链接则稳定很多;2)博主新做了一个网站,希望增加点人气(这谁丢的鸡蛋~)

总之,要获取提取码:点击打开 折扣君(rushy.cn)搜索“android”即可查看所有提取码 —— 这个网站是博主自己的,无广告无木马,请放心访问。

Update: 提取码整理如下表。

文件名文件大小下载地址提取码
android-23_r02.zip67.1Mhttp://pan.baidu.com/s/1qXjPT84j403
docs-23_r01.zip316Mhttp://pan.baidu.com/s/1jGZmMBOw77c
support_r23.2.110.3Mhttp://pan.baidu.com/s/1kUoea9p86j7
samples-23_r02.zip121Mhttp://pan.baidu.com/s/1i4qjGjVkozs
samples-22_r06.zip118Mhttp://pan.baidu.com/s/1gerAa9lyw9w
material-design-icons-master.zip57.5Mhttp://pan.baidu.com/s/1eQPl4Dcq44e
sources-23_r01.zip30.2Mhttp://pan.baidu.com/s/1qX2gKyg3s42
sources-22_r01.zip27.5Mhttp://pan.baidu.com/s/1nusJx3Njujw
installer_r24.3.4-windows.exe133Mhttp://pan.baidu.com/s/1bszUQMj101
android-sdk_r24.3.4-windows.zip178Mhttp://pan.baidu.com/s/1c1cNbkWia5c
android-sdk_r24.3.4-linux.tgz294Mhttp://pan.baidu.com/s/1nutz9Dv4mn2
android-sdk_r24.3.4-macosx.zip93Mhttp://pan.baidu.com/s/1kTXON4b9uav
android-studio-ide-141.2288178-linux.zip363Mhttp://pan.baidu.com/s/1skg0suLe1f9
android-studio-ide-141.2288178-mac.dmg347Mhttp://pan.baidu.com/s/1hr1bfcoixql
android-studio-bundle-141.2288178-windows.exe1.1Ghttp://pan.baidu.com/s/1qXqBAEg2yso

以上内容随时补充更新,欢迎提醒和纠错,发在评论区域就可以了。

(博客迁移前链接::https://www.cnblogs.com/bjzhanghao/archive/2012/11/14/android-platform-sdk-download-mirror.html

[Android问答] 如何获得手机屏幕分辨率?

file

获得手机屏幕分辨率这个问题并不复杂,但是问的人实在很多,所以还是集中回答一下。

从Android 3.2(API Level 13)开始,在Activity里使用下面的方法来获取屏幕分辨率(单位是像素):

Display display = getWindowManager().getDefaultDisplay(); //Activity#getWindowManager()
Point size = new Point();
display.getSize(size); int width = size.x; int height = size.y;

如果代码不是写在Activity里,用下面的方法(通过WINDOW_SERVICE获取display对象):

WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW\_SERVICE);
Display display \= wm.getDefaultDisplay();
display.getSize(size); int width = size.x; int height = size.y;

如果Android版本小于3.2,那么因为Display对象还没有getSize()方法,应该用下面的方法获取屏幕分辨率:

Display display = getWindowManager().getDefaultDisplay(); int width = display.getWidth(); 
int height = display.getHeight();   

最后,附Android系统版本与API Level对照表(官方文档在这里,如果打不开,也可以在android源文件的android.os.Build里找到这些对应关系):

Platform Version API Level VERSION_CODE Notes
Android 5.0 21 LOLLIPOP (正式的名称)
  21 L (暂时使用的名称)
Android 4.4W 20 KITKAT_WATCH  
Android 4.4 19 KITKAT  
Android 4.3 18 JELLY_BEAN_MR2  
Android 4.2 17 JELLY_BEAN_MR1  
Android 4.1, 4.1.1 16 JELLY_BEAN Platform Highlights
Android 4.0.3, 4.0.4 15 ICE_CREAM_SANDWICH_MR1 Platform Highlights
Android 4.0, 4.0.1, 4.0.2 14 ICE_CREAM_SANDWICH
Android 3.2 13 HONEYCOMB_MR2
Android 3.1.x 12 HONEYCOMB_MR1 Platform Highlights
Android 3.0.x 11 HONEYCOMB Platform Highlights
Android 2.3.4, 2.3.3 10 GINGERBREAD_MR1 Platform Highlights
Android 2.3.2, 2.3.1, 2.3 9 GINGERBREAD
Android 2.2.x 8 FROYO Platform Highlights
Android 2.1.x 7 ECLAIR_MR1 Platform Highlights
Android 2.0.1 6 ECLAIR_0_1
Android 2.0 5 ECLAIR
Android 1.6 4 DONUT Platform Highlights
Android 1.5 3 CUPCAKE Platform Highlights
Android 1.1 2 BASE_1_1  
Android 1.0 1 BASE  

参考资料

Display | Android Developers

Android: How to get screen dimensions

What is API Level?

(博客迁移前链接:https://www.cnblogs.com/bjzhanghao/archive/2012/11/12/2765835.html)

[Android问答] 开发环境问题集锦

file

工欲善其事,必先利其器。

和iOS开发相比,Android的开发环境的版本比较多,随之而来的问题也多。显然,我们不应该浪费宝贵的时间在解决开发环境带来的问题上,为此本文总结了常见的开发环境问题和解决方法,供大家查询和随时补充。

Debug certificate expired

Android SDK生成的用于调试的证书文件debug.keystore有效期是365天,当使用超过一年后控制台就会报这个错误。

Error generating final archive: Debug Certificate expired on 10/09/18 16:30

解决方法是手工删除debug.keystore文件,Windows系统下位于"C:\Documents and Settings\username\.android"目录,Linux和Mac系统下位于"~/.android/"目录。下次启动应用时,Eclipse会自动新建一个debug.keystore文件。最好"Project->Clean"一下项目以便触发编译器重新编译。

Failed to install apk on device: timeout

导致这个问题的确切原因不清楚,可能是由于不正确关闭adb连接。

Failed to install helloworld.apk on device 'emulator-5554': timeout

解决方法1:更换电脑usb口(不使用前置usb口)或重装手机驱动,将手机关机后再开机。

解决方法2:在Eclipse里选择Window->Preferences->Android->DDMS->ADB connection time out,将缺省的5000ms改为更大的值,例如20000ms

解决方法3:在命令行窗口里依次输入如下命令:

adb kill-server
adb start\-server

invalid command-line parameter

这是由于Eclipse开发环境无法找到所需的可执行文件造成的。

\[2011-07-10 07:10:22 - demo\] Android Launch! \[2011-07-10 07:10:24 - demo\] adb is running normally.
\[2011-07-10 07:10:24 - demo\] Performing com.demo.DemoActivity activity launch
\[2011-07-10 07:10:25 - demo\] Automatic Target Mode: launching new emulator with compatible AVD 'xxx' \[2011-07-10 07:10:25 - demo\] Launching a new emulator with Virtual Device 'xxx' \[2011-07-10 07:11:06 - Emulator\] invalid command-line parameter: Files\\Android\\android-sdk\\tools/emulator-arm.exe.

解决方法是在Eclipse里选择"Window->Preferences->Android"选项,检查"SDK Location"的路径是否包含了空格,如果是"c:\Program Files\android"这种,改为"c:\Progra~1\android",这样命令行就可以正常调用到了。

小提示:在命令行窗口里输入"dir /x"命令就可以列出8.3格式的文件名,看下面的结果:

2012-09-25  23:52    <DIR>          WATCHD~1 WatchData 2012-09-01  11:01    <DIR> Winamp 2012-07-24  22:22    <DIR>          WINDOW~4 Windows Live 2012-07-24  22:21    <DIR>          WI3957~1     Windows Live SkyDrive

INSTALL_FAILED_INSUFFICIENT_STORAGE

安装应用程序时遇到存储容量不足时会报这个错误:

Installation error: INSTALL\_FAILED\_INSUFFICIENT\_STORAGE
Please check logcat output for more details.
Launch canceled!

如果是在模拟器上运行应用,可以扩大AVD的内存容量。

如果是在真机上运行,可以在AndroidManifest.xml里修改安装偏好,让应用直接安装到SD卡上解决。

<manifest xmlns:android\="http://schemas.android.com/apk/res/android" package\="com.example" **android:installLocation\="preferExternal"** \> ... </manifest\>

Unable to open sync connection

虽然很多人遇到这个问题,但问题的根源并不确切,可能有多种原因造成adb报这个错误:

\[2010-10-12 09:36:48 - myapp\] Android Launch! \[2010-10-12 09:36:48 - myapp\] adb is running normally. \[2010-10-12 09:36:48 - myapp\] Performing com.mycompany.myapp.MyActivity activity launch \[2010-10-12 09:36:48 - myapp\] Automatic Target Mode: using device 'xxx' \[2010-10-12 09:36:48 - myapp\] Uploading myapp.apk onto device 'xxx' \[2010-10-12 09:36:48 - myapp\] Failed to upload myapp.apk on device 'xxx' \[2010-10-12 09:36:48 - myapp\] java.io.IOException: Unable to open sync connection! \[2010-10-12 09:36:48 - myapp\] Launch canceled!

解决方法1:拔掉手机连接线再重新连上;

解决方法2:在手机上关闭Debug选项再重新打开,这个选项在手机的"设置->应用程序->开发->USB调试"里。

Too many open files

这个问题与系统可同时打开文件数量设置有关,但一般不需要修改相关设置,用上一个问题(Unable to open sync connection)的方法即可解决。

第三方Jar包,NoClassDefFoundError

升级ADT版本以后容易出现这个问题:本来一切正常的Android项目,升级以后所有的第三方Jar包里的类都提示NoClassDefFoundError了。

原因可能出现在不同版本ADT使用的编译ant脚本的区别,可能的解决方法有两个:

方法1:在Eclipse里右键点击你的Android工程,选择"Properties->Java Build Path->Order and Export",在这里把所有第三方Jar包前面的复选框都勾上。

方法2:检查你的第三方Jar包文件是否放在工程目录下的"libs"目录,如果不是,改过来。

Failed to allocate memory: 8

一般是AVD的设置有问题,很可能是RAM值设得太高,降低些试试。早期adt版本里有个bug,就是RAM值里必须包含"MB",例如是"512MB"而不是"512",否则提示上述错误信息。

也有人提到过分辨率是原因之一,但我没有实际遇到过,如果只改小RAM没有解决问题,试着把分辨率也调低看看。

参考资料

“Debug certificate expired” error in Eclipse Android plugins

Android error: Failed to install *.apk on device *: timeout

The Android emulator is not starting, showing “invalid command-line parameter”

Solution: Android INSTALL_FAILED_INSUFFICIENT_STORAGE error

Android adb “Unable to open sync connection!”

com.android.ddmlib.SyncException: Too many open files

NoClassDefFoundError - Eclipse and Android

Android emulator failed to allocate memory 8

(博客迁移前链接:https://www.cnblogs.com/bjzhanghao/archive/2012/11/11/2765341.html

[Android问答] ListView如何加载远程图片?(附代码)

 ListView在Android应用里扮演非常重要的角色,但很多开发者在使用ListView时都遇到过不少麻烦。一个常见的问题是:列表中要显示一系列记录,每条记录带有一张缩略图(产品照片、用户头像等等),而这个缩略图是通过一个远程URL地址来标识的。这样的应用场景该如何实现呢?

file

为了避免下载图片带来的延迟,所有远程图片都应该使用异步方式加载,即使用单独的线程下载图片,待图片下载完毕后显示在ImageView里。Android里可以像普通Java一样启动新线程,但当这个线程要更新界面时,必须使用Handler来请求,否则会为应用程序带来潜在危害。

RemoteImageHelper

为了将复杂的逻辑分离,我们单独写一个名为RemoteImageHelper的类来处理“异步下载图片并更新到界面”这个问题,这个类能够实现以下功能:

  • 图片开始下载前,ImageView里显示一个表示“正在加载”的占位图;
  • 图片在后台下载,下载完成后显示在ImageView里;
  • 若图片下载失败,ImageView显示一个表示下载失败的占位图;

下面让我们来看一下实现代码:

首先需要有一个方法下载远程图片,这里我们不用把图片下载到手机上,直接返回一个InputStream类型的结果即可。如果运行时这个方法报错,请检查是否在AndroidManifest.xml里添加了android.permission.INTERNET权限。

private InputStream download(String urlString) throws MalformedURLException, IOException {
    InputStream inputStream \= (InputStream) new URL(urlString).getContent(); return inputStream;
}

然后是最主要的异步加载图片方法,“正在下载”和“下载失败”的图片可根据需要自己替换。代码如下所示:

private final Map<String, Drawable> cache = new HashMap<String, Drawable>(); public void loadImage(final ImageView imageView, final String urlString, boolean useCache) { if (useCache && cache.containsKey(urlString)) {
        imageView.setImageDrawable(cache.get(urlString));
    } //Show a "Loading" image here
 imageView.setImageResource(R.drawable.image\_indicator);

    Log.d(this.getClass().getSimpleName(), "Image url:" + urlString); final Handler handler = new Handler() {
        @Override public void handleMessage(Message message) {
            imageView.setImageDrawable((Drawable) message.obj);
        }
    };

    Runnable runnable \= new Runnable() { public void run() {
            Drawable drawable \= null; try {
                InputStream is \= download(urlString);
                drawable \= Drawable.createFromStream(is, "src"); if (drawable != null) {
                    cache.put(urlString, drawable);
                }
            } catch (Exception e) {
                Log.e(this.getClass().getSimpleName(), "Image download failed", e); //Show a "download fail" image 
                drawable = imageView.getResources().getDrawable(R.drawable.image\_fail);
            } //Notify UI thread to show this image using Handler
            Message msg = handler.obtainMessage(1, drawable);
            handler.sendMessage(msg);
        }
    }; new Thread(runnable).start();
}

关于缓存:在这个例子里我们使用一个内存中的HashMap作为图片缓存,它实现简单但当应用退出后缓存就会被清除。在实际项目里,你可以考虑实现一个基于文件的缓存机制,即将下载的图片保存到SD卡上,注意要定期清除长期不用的图片以节约存储空间。

使用RemoteImageHelper

如何使用这个类呢?下面是一个例子。请注意,为了达到更好的演示效果,代码里在调用loadImage()方法时第三个参数用false禁止了图片缓存功能,在实际项目中,你很可能需要改为true来避免重复下载图片以便提高性能。

List<MyRecord> exampleRecords;
**LazyImageHelper lazyImageHelper** **\= new LazyImageHelper();** class MyAdapter extends ArrayAdapter<MyRecord> { public MyAdapter(Context context) { super(context, R.layout.record\_row, R.id.lblLabel, exampleRecords);
    }

    @Override public View getView(int position, View convertView, ViewGroup parent) {
        View view \= super.getView(position, convertView, parent);
        MyRecord record \= getItem(position);

        TextView lblLabel \= (TextView) view.findViewById(R.id.lblLabel);
        ImageView imageView \= (ImageView) view.findViewById(R.id.img);

        lblLabel.setText(record.getLabel()); //For demo purpose, cache is DISABLED here.
        **lazyImageHelper.loadImage(imageView, record.getImageUrl(), false);** //To enable cache, simply use following code: //lazyImageHelper.loadImage(imageView, record.getImageUrl(), true);

        return view;
    }
}

以上代码中的MyRecord是一个简单的POJO类,表示一个业务对象,它具有id、label和imageUrl三个属性。你可以在完整的工程代码中找到它。

代码下载

上述示例工程编译后的APK文件点击这里下载,可运行在Android 2.1或以上版本。

上述示例工程的源代码点击这里下载。

参考资料

Handler

android的消息处理机制

How do I do a lazy load of images in ListView

Issue 13959:Make listviews more programmer friendly

(博客搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2012/11/11/load-images-in-android-listview.html)

[Android问答] 如何实现“退出应用”功能?

file

刚从桌面应用开发转做手机开发的同学常常被这个问题困扰——用户按下Home键后,应用不是“完全退出”而是“运行在后台”,它仍然占用着系统资源,这么多后台运行的应用必然导致系统变慢,是不是应该在我的应用里给用户提供一个“退出菜单”或“退出按钮”呢?

我在Android开发文档里暂时没有找到关于这个问题的解释,但经过在网上调查很多资料以后,我认为答案是比较明显的:不应提供“退出应用”功能

虽然文档里没有明确说明,但假如这是常用功能,应该有简便的方法实现,而实际上要靠代码“退出”一个应用并非易事。以下总结了能够模拟退出效果的两个方案:

方案1:打开系统主屏来模拟应用退出的效果,这和用户按Home键没有什么区别。

Intent intent = new Intent(Intent.ACTION\_MAIN);
intent.addCategory(Intent.CATEGORY\_HOME);
intent.setFlags(Intent.FLAG\_ACTIVITY\_NEW\_TASK);
startActivity(intent);

方案2:直接杀掉当前应用进程。这个方法太暴力了,我找到一段iOS开发文档,上面强烈不建议使用杀进程的方式来退出应用,原因也适用于Android系统:这样退出的效果容易让用户以为应用崩溃了。

int pid=android.os.Process.myPid();
android.os.Process.killProcess(pid);

此外,有人建议调用System.exit(0)退出应用,实际测试发现这个方法常常只能关闭当前Activity,或是根本不起作用。

由此可以看出,Android系统的设计里本来就没有“退出应用”的机制,当用户按下Home键或在应用首页里按下Back键后,应用被置于后台,而何时要彻底杀掉应用进程则由系统决定。Android和iOS都已抛弃了“退出应用”这个概念,对手机用户来讲,他只需要知道“启动应用”——概念越少越简单。

参考资料:

Quitting an application - is that frowned upon?
android - exit application code
How to close/exit an application in android?
Proper way to exit iPhone application?
How do I programmatically quit my iOS application?

[Android问答] 旋转屏幕导致Activity重建怎么办?

file

Android开发文档上专门有一小节解释这个问题。简单来说,Activity是负责与用户交互的最主要机制,任何“设置”(Configuration)的改变都可能对Activity的界面造成影响,这时系统会销毁并重建Activity以便反映新的Configuration。

“屏幕方向”(orientation)是一个Configuration,通过查看Configuration类的javadoc可以看到其他Configuration还有哪些:如fontScalekeyboardHiddenlocale等等。

当屏幕旋转时,这个Configuration就发生了改变,因此当前显示的Activity需要被重建,Activity对象会被终止,它的onPause()onStop()onDestroy()方法依次触发,然后一个新的Activity对象被创建,onCreate()方法被触发。假设屏幕旋转前,用户正在手机上填写一个注册表单,如果处理不当,用户会发现旋转后的表单变成空白的了,严重影响使用体验。

要解决这个问题有三种方法:

方法1:禁止旋转屏幕

毫无疑问,这是最懒的办法了,相当于回避了本文提出的问题,方法如下看看就好:

<activity android:name=".MyActivity"
          android:screenOrientation="portrait"
          android:label="@string/app_name">

方法2:旋转后恢复现场

既然Activity会被销毁,那么我们就可以使用前文介绍过的“持久化/恢复现场”方法来解决。即在onPause()里将用户当前已经输入的内容保存到数据库或Preference,在onCreate()方法里读取并填充到表单中,这也是官方推荐的方法。

需要补充一点,如果Activity重建需要耗费大量资源或需要访问网络导致时间很长,可以实现onRetainNonConfigurationInstance()方法将所需数据先保存到一个对象里,像下面这样:

@Override
public Object onRetainNonConfigurationInstance() {
    final MyDataObject data = collectMyLoadedData();
    return data;
}

重建时,在onCreate()方法里通过getLastNonConfigurationInstance()方法获得之前保存的数据,如下所示:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();
    if (data == null) {//表示不是由于Configuration改变触发的onCreate()
        data = loadMyData();
    }
    ...
}

方法3:手工处理旋转

一般情况下Configuration的改变会导致Activity被销毁重建,但也有办法让指定的Configuration改变时不重建Activity,方法是在AndroidManifest.xml里通过android:configChanges属性指定需要忽略的Configuration名字,例如下面这样:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

这样设置以后,当屏幕旋转时Activity对象不会被销毁——作为替代,Activity的onConfigurationChanged()方法被触发,在这里开发者可以获取到当前的屏幕方向以便做必要的更新。既然这种情况下的Activity不会被销毁,旋转后Activity里正显示的信息(例如文本框中的文字)也就不会丢失了。

假如你的应用里,横屏和竖屏使用同一个layout资源文件,onConfigurationChanged()里甚至可以什么都不做。但如果横屏与竖屏使用不同的layout资源文件,例如横屏用res/layout-land/main.xml,竖屏用res/layout-port/main.xml,则必须在onConfigurationChanged()里重新调用setContentView()方法以便新的layout能够生效,这时虽然Activity对象没有销毁,但界面上的各种控件都被销毁重建了,你需要写额外的代码来恢复界面信息。

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "横屏模式", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "竖屏模式", Toast.LENGTH_SHORT).show();
    }
}

官方的Android开发文档不建议使用这种方式处理Configuration改变:

Note: Using this attribute should be avoided and used only as a last-resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.

最佳实践

考虑到旋转屏幕并不是使Activity被销毁重建的唯一因素,仍然推荐前文介绍过的方法:在onPause()里持久化Activity状态,在onCreate()里恢复现场,可以做到一举多得;虽然Google不推荐设置android:configChanges属性的方式,但如果你的Activity横向纵向共用同一个layout文件,方法3无疑是最省事的。

参考资料:

Configuration Changes
Handling Runtime Changes
Activity restart on rotation Android
How to handle screen orientation change when progress dialog and background thread active?

(搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2012/11/09/2761897.html)