1:Android Permission denied(不允许连接Socket) 错误
原因是: 需要访问到网络,所以,在AndroidManifest.xml中,需要进行如下配置:
<uses-permission android:name="android.permission.INTERNET" />
2:ListView滚动变黑解决方法
ListView增加一个属性android:cacheColorHint="#00000000"
3:Item用自己的背景盖住了Selector光标
ListView增加一个属性:android:drawSelectorOnTop="true"这样光标就会跑到Item上面的图层
4:在利用Tab标签(自定义按钮)实现不同Activity切换,不同Activity均已经设置了模式为singleTask或singleInstance时,但是每次点击Tab标签中的特定Activity时,每次都还是会执行
onCreate方法,原因如下:
1:管理Tab标签(实现Activity切换的Tab标签)的容器(Activity)必须继承ActivityGroup
2:Activity设置的启动模式必须为singleTask或singleInstance
3:LocalActivityManager中的startActivity方法对于的Activity对应的ID,必须为需要跳转过去的Activity名称,否则失效。
4:存放tab标签(自定义按钮)对应的layout中必须有一个FrameLayout放置子activity。
5:模拟器提示访问网络出现如下异常:
java.net.UnknownHostException: Host is unresolved
原因是模拟器没有开通代理访问网络。
6:开发过程中,当listview控件中有button、checkbox等控件时,可能是由于这些子控件中获取到了focus事件,导致listview中onItemClick事件失效,只需要按如下方式处理即可:
1)每一个控件重新设置focusable属性
2)Item Layout的根控件设置其android:descendantFocusability=”blocksDescendant”即可
7:开发自定义控件步骤
1)创建res/values/***.xml资源文件(里面的内容节点declare-styleable,子节点中的内容为该自定义控件的属性字段)
2)创建res/layout/***.xml布局文件(对应主的布局中定义声明自定义控件xmlns:custom="http://schemas.android.com/apk/res/com.test.jzh ")
custom可以随意编写;com.test.jzh则需要依据自定义控件所在package路径而定,一定为该工程的包名。
3)编写自定义控件的实体操作类,完成控件所展示的界面、功能操作等。
开发自定义控件需要注意的事情:
1:自定义控件需要重写android系统控件的如下构造函数
View(Context context)
View(Context context, AttributeSet attrs)
同时构造函数也可以做些其他的事情
2:自定义控件也可以在初始化的时候构造从Layout布局中完成初始化动作
3:自定义空时如果需要实现控件布局飞翻转、移动位置(非正常的控件)需求时,可以借助于重写控件的onDraw方法,让Canvas画布做相应的处理,如:
Canvas.rotate(-90);---旋转
Canvas.translate(-getHeight(),0);---移动
1:运行时 在logcat中看到虚拟机找不到CustomeView这个类。最后发现是要在xml中加上整个package name(如红色所示)(xmlns:app="http://schemas.android.com/apk/res/com.custome"),因为自定义的派生类不再java虚拟机的classpath中
2:在setContentView中inflate xml时,没有把id值传给CustomeView的实例,最后发现很多在xml中的属性都会通过View的构造函数 View(Context context, AttributeSet attr)中的第二个参数传递进来的,而我的派生类只提供了 CustomeView(Context context)的够咱函数,导致id值无法传入
8:Listview中性能优化方案(需要加载图片)
1)将图片以文件(文件名称编号唯一)的形式缓存到手机中、后面每次列表加载时先判断文件是否存在,存在则直接读取出来显示;否则直接网络请求,再写入缓存中。
2)Adapte设置getview可以用---convertView = LayoutInflater.from(context).inflate(R.layout.main, null, false);也可以用自定义了继承自LinearLayout的MBlogListItemView,如:
public class TestItemLayout extends LinearLayout {public TextView text1;
public ImageView icon1;
public TextView text2;
public ImageView icon2;
public TestItemLayout(Context context) {
super(context);
((LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
R.layout.list_item_icon_text, this);
icon1 = (ImageView) findViewById(R.id.icon1);
text1 = (TextView) findViewById(R.id.text1);
icon2 = (ImageView) findViewById(R.id.icon2);
text2 = (TextView) findViewById(R.id.text2);
}
}
9:中文API
http://www.cnblogs.com/over140/
10:输入框中如何出现下一页。
在edittext控件中增加android:singleLine="true"即可。
11:将listview默认选中的背景色去除。
android:cacheColorHint="@null"
android:listSelector="#00000000"
12:listview中包含图片等外部数据时,如果现实内容滚动比较卡,原因可能是加载listview是主UI和Listview中的图片等加载界面混淆在一起。
解决方法:设置是否滚动标志,加载getView时以此作为依据,判断是否加载图片。
13:如果给android程序做压力测试,答案是monkey。
adb shell monkey -p com.huawei.basic.android -v 1000
14:工程如果不会自动生成gen文件夹或者报“Unable to resolve target android-9”,解决方法如下
工程-属性-android-选择合适的Project Build Target.
15:"Cannot reduce the visibility of the inherited method from",解决方法如下:
1)选择合适的android platform版本。
2)选择system lib中的layoutlib和android。
16:各个Activity通过Intent传递数据,是通过Bundle携带的,需要判断好Bundle。
17:android开发过程中如果遇见java是提供该类或者其他的,但是就是报(**** is not visible),原因就是sun的jar包和android冲突所致
18:android在实现listview中图片统一风格的方案有两种。1:通过程序做统一处理,但是消耗性能;2:通过在image底部或者上面再罩一个透明的图片,效果非常好。
19:ERROR: Application requires API version 10. Device API version is 8
解决方法:
1:在AndroidManifest.xml 里, <uses-sdk android:minSdkVersion="8" /> 找到這一行,這行是表示要執行這個應用程式所需要的最低版本,把數字改成模擬器上面的版本。
2:在default.properties 里
target=android-8
把target改为要运行模拟器的版本就OK了。
20:如果工程出现gen文件夹不自动生成、case expressions must be constant expressions、Cannot reduce the visibility of the inherited method from Activity等问题,原因可能是eclipse默认的workspace有问题,可以考虑重新建立一个。
21:Canvas、Paint、SurfaceView这三者之间的关系,Canvas是一个画布,而Paint是一个工具,画布中需要画东西必须通过Paint去画,而SurfaceView是一个显示画布的控件,即最后Canvas画布中的内容都是需要通过SurfaceView去呈现在Android界面中,样例:
GameView gv= new GameView(this);=====surfaceView
LinearLayout hotWordsContainer = (LinearLayout) findViewById(R.id.linearLayout1);
hotWordsContainer.addView(gv);
22:Adapter\LayoutInflater
1)Adapter具体见下图
2)LayoutInflater
Inflater英文意思是膨胀,在Android中应该是扩展的意思吧。
LayoutInflater的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout文件夹下的xml布局文件,并且实例化!而 findViewById()是找具体某一个xml下的具体 widget控件(如:Button,TextView等)。
如:
- LayoutInflater inflater = LayoutInflater.from(this);
- View view=inflater.inflate(R.layout.ID, null);
- 或者干脆并成一句:
- View view=LayoutInflater.from(this).inflate(R.layout.ID, null);
23:Handler的定义和特点
定义: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button, Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭". 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。
特定:handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用: (1): 安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行。
24:android手机root权限破解
使用SuperOneClick工具即可,但是需要安装net framework。
25:在listview底部增加控件view时,不显示的原因是需要先将lv.addFootView(v)放在setAdapter之前就可解决.
26:程序在设计时需要统一管理Handler,提供一个内存块Map,并提供常用的注册、去注册、发送消息等常用的功能。
27:Listview滚动事件
scrollState有三种状态,分别是
开始滚动(SCROLL_STATE_FLING )
正在滚动(SCROLL_STATE_TOUCH_SCROLL ),
已经停止(SCROLL_STATE_IDLE ),对于滚动事件的处理,很有必要知道
。
28:adb常用命令
adb shell
如果在操作命令是出现“permission denied”,则提示只需要执行su命令即可。
adb server is out of date. killing...
ADB server didn't ACK
* failed to start daemon *
error:
原因:豌豆荚之类的软件开启了USB调试开关,关闭即可。
如果操作android手机时,执行名称出现“read-only file system”
mount -o remount rw /
。
修改权限----chmod 777 文件夹或者文件
29:在使用listview时,如果需要更新listview中的现实的数据时,只需要更新listview绑定的Adapter中的list内存数据,然后再发送adapter.adapter.notifyDataSetChanged();
30:Only the original thread that created a view hierarchy can touch its views.
原因:在Activity中使用线程更新UI时,由于单独新建的线程中直接操作了UI内容,导致上面的问题,解决方式是将更新UI放置进handle去处理。
31:sqlite分页语句
select * from table_name order by last_message_date desc Limit 10 offset nBaseRow---从第nBaseRow行(基于0的索引)(包括该行)开始,取其后的10 条记录。
32:android源码下载地址汇总:
http://618119.com/archives/2011/01/01/201.html
33:android好的设计需要考虑
1:Handle需要做一个统一管理。
2:SharedPreference也需要做一个统一管理
34:Activity中如果listview不执行滑动事件。
原因可能就是没有注册。像这样:listView.setOnScrollListener(this);
35:使用SQLiteOpenHelper对数据库进行版本管理
SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。
36:Listview使用总结
1---listview在实现分页时,如果每次分页加载数据后滚动条都运行至最顶部,原因可能:每次重新adapter时都重新了new了。
2---调试Android程序时,如果新的代码更新了数据库,但是安装调试到手机里面的程序,还是老的,解决方法:删除手机上面该应用的数据即可,重新安装。
1:进行上拉分页时,原理:1)先定义好一个底部加载layout;2)Activity初始化时将1)控件加载至listview中。3)如果触发分页操作,则加载数据,如果无数据,则直接从listview中remove即可。
2:进行下拉分页时,list在增加Header、Footer时,在已经setAdapter时,是不能再AddHeader或者AddFooter的,否则出现如下异常:
Cannot add header view to list -- setAdapter has already been called.
提示我已经设置了适配器,原来addHeaderView(View v)方法 只能在父控件 setAdapter之前调用!
仔细想想也很容易解释,addHeaderView是为list加入 头视图,而setAdapter是为控件匹配内容。哪有先匹配了内容,再插入view的道理,皮之不存毛将焉附.
好实例:
https://github.com/johannilsson/android-pulltorefresh/zipball/master
http://files.cnblogs.com/xiaoQLu/DemoSectionListView_Plus.rar
37:AsyncTask总结
AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。
1) 子类化AsyncTask
2) 实现AsyncTask中定义的下面一个或几个方法
onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。
doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.
为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
1) Task的实例必须在UI thread中创建
2) execute方法必须在UI thread中调用
3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法
4) 该task只能被执行一次,否则多次调用时将会出现异常
38:Android中处理崩溃异常
要实现这一机制,不过首先我们还是来了解以下两个类:
android.app.Application和java.lang.Thread.UncaughtExceptionHandler。
Application:用来管理应用程序的全局状态。在应用程序启动时Application会首先创建,然后才会根据情况(Intent)来启动相应的Activity和Service。本示例中将在自定义加强版的Application中注册未捕获异常处理器。
Thread.UncaughtExceptionHandler:线程未捕获异常处理器,用来处理未捕获异常。如果程序出现了未捕获异常,默认会弹出系统中强制关闭对话框。我们需要实现此接口,并注册为程序中默认未捕获异常处理。这样当未捕获异常发生时,就可以做一些个性化的异常处理操作。
39:Caused by: java.lang.ClassNotFoundException: ****.MainActivity in loader dalvik.system.PathClassLoader
原因:
1、AndroidManifest.xml配置文件启动Activity配置问题
2、重新clean工程,去除历史垃圾数据。
40:android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1(数据库查询得到的cursor里面只有1个结果,你却查找第-1个)
解决方法:
1:检查遍历是否时,是否先执行了cursor.moveToFirst()。
2:检查遍历cursor索引是否正确。
41:当发现sqlist developer 工具查询和Android手机执行的结果不一致时,原因可能是:
1):SQL本身的问题。
2):查询URI指定的数据库不一致
String sql = " canonical_addresses.address, threads._id from canonical_addresses, threads where threads.recipient_ids = canonical_addresses._id --";
cursor = this.mContext.getContentResolver().query(
Uri.parse(FusionField.SMS_PHONE_URI), new String[]{sql}, null, null,null);
42:Android如何做到多个版本(资源文件不同、apk包名不同)公用一份逻辑方案
1:新建一个工程,里面包含多个版本的工程目录,同时核心的业务逻辑也是一个单独的工程。
2:不同版本公用引用同一个核心的业务逻辑工程,确保本版本可以编译。
3:由于不同版本资源不同,且不同版本的包结构也不同,故只需要在编译版本时,将核心模块的工程中设计到res的R.java文件指定的import路径修改即可。
43:其实apk程序的包名不一定需要和工程的包结构一致。
44:导出android系统的短信库(需要获取android用户的root权限)
# cd /data/data/com.android.providers.telephony
cd /data/data/com.android.providers.telephony
# ls
ls
app_parts
databases
lib
shared_prefs
# cd database
cd database
cd: can't cd to database
# cd databases
cd databases
# ls
ls
telephony.db
mmssms.db
# chmod 777 mmssms.db
chmod 777 mmssms.db
# cd ..
cd ..
# chmod 777 databases
chmod 777 databases
# cd ..
cd ..
# chmod 777 com.android.providers.telephony
chmod 777 com.android.providers.telephony
# cd ..
cd ..
# chmod 777 data
chmod 777 data
# cd ..
cd ..
# chmod 777 data
chmod 777 data
#
45:Activity类创建后,它里面的声明的对象实例等都和它息息相关,即Activity销毁,则里面的所有实例也就销毁了。
46:android service
Service是android 系统中的一种组件,它跟Activity的级别差不多,但是他不能自己运行,只能后台运行,并且可以和其他组件进行交互。Service的启动有两种方式:context.startService() 和 context.bindService()。
使用context.startService() 启动Service是会会经历:
context.startService() ->onCreate()- >onStart()->Service running
context.stopService() | ->onDestroy() ->Service stop
如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
stopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。
所以调用startService的生命周期为:onCreate --> onStart(可多次调用) --> onDestroy
使用使用context.bindService()启动Service会经历:
context.bindService()->onCreate()->onBind()->Service running
onUnbind() -> onDestroy() ->Service stop
onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。
所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。
47:Android Project在用ant install部署时报taskdef class com.android.ant.SetupTask cannot be found异
原因:local.properties的路径设置问题
解决办法:查看路径是否是单反斜杠,如果是,改成双反斜杠,如:sdk.dir=e:\android-sdk-windows修改成sdk.dir=e:\\android-sdk-windows
48:Android文字高亮计算
主要通过使用SpannableString类即可实现。
49:学习过程中遇见的经典网站
http://www.slideshare.net/
http://*.com/
https://github.com
http://code.google.com/hosting/search?q=label%3aAndroid
http://labs.skinkers.com/content/android_dp_px_calculator/
http://code.google.com/p/android-unused-resources/(检测资源文件是否被利用)
http://developer.android.com/tools/help/proguard.html(还原混淆后的log方法)
http://iandroiddev.com/archive
http://www.eoeandroid.com/forum.php?mod=viewthread&tid=168008
50:android新功能提示指引页面如何实现。
1)通过布局文件实现,正常时未隐藏不显示的,可以通过逻辑让其显示
2)通过SharedPreferences保存使用状态。
51:Tab切换Activity方案
1)通过TabActivity
本方案只是针对通过Tab标签实现Activity切换,不同Tab切换时实现Activity相互切换,其中过度可以实现交互动画,本方案就是针对该需求而设计。
在讲解方案前,需要明确了解如下几个基本知识
1:TabActivity
2:TabHost
TabHost主要由两部分组成,标签和内容,其中内容是一个FrameLayout,当用户单击不同的标签可以显示不同的内容。使用标签可以达到分页的效果,是页面的内容更加丰富,更加具有亲和力,当然与此同时,也会增加页面的复杂程度
3:TabWidget
TabWidget就是Tab的一个集合,也就是Tab栏。
4:TabSpec
选项卡的标识,可以设定选项卡的标题、可以设置图片等,并且设置选项卡内容。
TabHost,TabWidget,FrameLayout之间的关系:
TabHost好比一个选项卡的容器,包括多个选项卡和选项卡的内容,其中选项卡的内容是一个FrameLayout容器,TabWidget可以理解为选项卡栏.
正确的main.xml文件应该包含这三个组件TabHost,TabWidget,FrameLayout
下面是具体的开发设计步骤:
1) 定义一个主的Activity,该Activity必须要继承至TabActivity,只有继承了该TabActivity的才可以实现Tab切换,同时必须要实现OnTabChangeListener(用于控制tab切换事件,也可以在这里实现动画效果), OnGestureListener(用户控制何时触发左右tab切换)两个接口。
2) 自定义一个TabHost控件(包括TabWidget标签栏+FrameLayout内容),需要重写addTab和setCurrentTab两个方法,第一个方法用于增加标签,而另一个是设置内容(Activity)切换动画。
2)通过ActivityGroup
在一个主界面中做Activity切换一般都会用TabActivity,使用方便,Activity互相之间相对独立,但是可定制性不强,而且修改起来很麻烦。当然也可以把layout分开,把逻辑代码全写在主界面的逻辑代码中,但是很明显可维护性相当差,这里通过ActivityGroup来解决这个问题。
52:android:layout_weight="1"可以实现比例权重,挺方便的。
53:android观察者模式
ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。触发器分为表触发器、行触发器,相应地ContentObserver也分为“表“ContentObserver、“行”ContentObserver,当然这是与它所监听的Uri MIME Type有关的
使用ContentObserver的情况主要有一下两者情况:
1、需要频繁检测的数据库或者某个数据是否发生改变,如果使用线程去操作,很不经济而且很耗时
2、在用户不知晓的情况下对数据库做一些事件,比如:悄悄发送信息、拒绝接受短信黑名单等;
3、需要监控特定的URI内容变化的情况。
在上述情形下,使用ContentObserver无疑是最好的利刃了。
54:一种对View(可以使布局,也可以使具体的控件)指定区域进行触碰控方法。
原理很简单:
1)注册View的触碰监听事件view.setOnTouchListener(****);
2)实现该接口接口中的方法,如果是只需要出发点击事件,只需要实现MotionEvent.ACTION_DOWN即可
private OnTouchListener viewOnTouchListener = new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
int id = v.getId();
int action = event.getAction();
if (id == R.id.viewlayout)
{
switch (action)
{
case MotionEvent.ACTION_DOWN:
int screenWidth = v.getWidth();
float leftDistance = v.getWidth() / 3;
float rightDistance = v.getWidth() * 2 / 3;
float fingerPointX = event.getX();
if (fingerPointX < leftDistance && fingerPointX > 0)
{
//TODO
}
else if (fingerPointX > rightDistance && fingerPointX < screenWidth)
{
//TODO
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_CANCEL:
}
}
return false;
}
};
55:编译Android工程时,如果出现了“the currently displayed page contains invalid values”,原因:
工程中没有project.properties和project.cfg文件,直接拷贝过来即可。
56:编译运行Android工程时,如果出现了“Android library projects cannot be launched ”,原因:
In the Package Explorer, right-click the library project and select Properties.
In the Properties window, select the “Android” properties group at left and locate the Library properties at right.
Select the “is Library” checkbox and click Apply.
Click OK to close the Properties window.
发现is Library是选中的,取消选择后,程序可以编译了。
56:Android通过Paint画文本时,如何得到文本占屏幕的宽度。
paint.setTextSize(10);//先设置字体大小
float width = paint.measureText("中文字符");//获取字符长度
57:Project **** is missing required source folder: 'gen'解决方法
1)Project-->Properties-->Java Build Path-->Order and Export中把gen目录上下移动一下,OK下去。
2)Project-->Properties-->Java Build Path-->Source下把gen目录删除,再通过Add Folder...加上去。Eclipse自动会把gen放在src之前。
58:MotionEvent事件在onInterceptTouchEvent()、onTouchEvent()中的传递顺序
1)onInterceptTouchEvent()用于处理事件并改变事件的传递方向。处理事件这个不用说了,你在函数内部编写代码处理就可以了。而决定传递方向的是返回值,返回为false时事件会传递给子控件的onInterceptTouchEvent();返回值为true时事件会传递给当前控件的onTouchEvent(),而不在传递给子控件,这就是所谓的Intercept(截断)。
2)onTouchEvent() 用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。可能你要问是否消费了又区别吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。
59:Android多种异步刷新机制
1)Handle
2)AsynTask
3)Activity.runOnUiThread
60:经典代码
Listview中点击Item时,选中项上移至顶部的动画效果
public void move(View v) {
int list_child_item_height = 0;
// if (mList.getCount() > 0) {
// View listItem = AppMgrAdapter.this.getView(0, null, mList);
// listItem.measure(0, 0); // 计算子项View 的宽高
// list_child_item_height = listItem.getMeasuredHeight();
// LogX.e(TAG, "itme高度 = " + list_child_item_height);
// }
int nums = mList.getChildCount();
int height = 0;
for (int i = 0; i < nums; i++) {
View view = mList.getChildAt(i);
// mList.onKeyDown(KeyEvent.KEYCODE_DPAD_UP, null);
AppManageMent app = (AppManageMent) view.getTag();
if (app.getChildIndex() == selectedPosition) {
int Pos[] = { -1, -1 }; // 保存当前坐标的数组
view.getLocationOnScreen(Pos); // 获取选中的 Item
// 在屏幕中的位置,以左上角为原点 (0,
// 0)
LogX.e(TAG, "selected appInfo x = " + Pos[0] + "y = " + Pos[1]);
break;
} else {
int Pos[] = { -1, -1 }; // 保存当前坐标的数组
view.getLocationOnScreen(Pos); // 获取选中的 Item
// 在屏幕中的位置,以左上角为原点 (0,
// 0)
LogX.e(TAG, "appInfo" + i + " x = " + Pos[0] + "y = " + Pos[1]);
if (Pos[1] >= 169) {//169是顶部菜单栏高度
height = height + itmeHeight;// itemHeight是listview每一项高度
} else {
height = height + (itmeHeight - (169 - Pos[1]));
}
}
}
LogX.e(TAG, "移动的高度 = " + height);
// if(height > 0){
final int moveHeight = height;
Animation upAnimation = new TranslateAnimation(0, 0, 0, -height);
if (moveHeight > 0) {
upAnimation.setDuration(1000);
} else {
upAnimation.setDuration(0);
}
// upAnimation.setFillBefore(true);
upAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mList.setSelectionFromTop(selectedPosition, 0);
mList.clearAnimation();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
Listview下拉刷新出现Loading加载布局时,当有新数据时,保证当前Listview整体列表不动的核心代码
int loadingHeight = 87+30;
if (selectIndex == 0)
{
View listItem = mGroupChatLogAdapter.get().getView(position-1, null, mChatListView);
listItem.measure(0, 0);
int height = listItem.getMeasuredHeight();
if(height == loadingHeight)
{
mChatListView.setSelectionFromTop(position,0);
}
else if(height > loadingHeight)
{
mChatListView.setSelectionFromTop(position,-(height-loadingHeight));
}
else if(height < loadingHeight && height > 0)
{
mChatListView.setSelectionFromTop(position,loadingHeight-height);
}
}
61:ViewGroup如何实现无限循环,思想如下
1:在最左边View同时将最右边的View加入在其左边;同时在其右边View将最左边的View加入其右边;
2:当用户移动至最左边时,动画执行屏幕移动时,同时发行请求Handler,将View填充至最左边;最右边也同理。
ViewGroup核心代码:
public void snapToScreen(int whichScreen)
{
boolean isSendHandler = false;
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
final int delta = whichScreen * getWidth() - getScrollX();
int delayMills = Math.abs(delta);
//这段代码设计精妙之处在动画之前过程中,发送定时Handle,动画完成后同时执行Handler,绝妙之极
if(whichScreen == 0)
{
sendHandlerMsg(what0,delayMills);
}
else if (whichScreen == getChildCount() - 1)
{
sendHandlerMsg(what1,delayMills);
}
else
{
delayMills = (int) (Math.abs(delta) * 1.5);
}
mScroller.startScroll(getScrollX(), 0, delta, 0, delayMills);
// 如果需要移动的tab和当前tab是同一个,则不需要发送Handler
if (whichScreen != mCurrentScreenIndex)
{
isSendHandler = true;
}
mCurrentScreenIndex = whichScreen;
selectView(mCurrentScreenIndex, isSendHandler);
invalidate();
}
62:如果界面中存在多个Listview时,切换时如何保证listivew中第一个可见的条目所在屏幕中的位置保证一致。
private void setListView(ListView sourceListView, ListView desListView)
{
if (null != sourceListView && null != desListView)
{
int[] location = new int[2];
if (0 == listViewYLocation)
{
//获取该VIEW控件相对于手机屏幕的绝对坐标位置
desListView.getLocationOnScreen(location);
listViewYLocation = location[1];
}
if (sourceListView.getCount() > 0)
{
//获取源ListView中第一个显示的item---在ListView中,使用getChildAt(index)的取值,只能是当前可见区域(列表可滚动)的子项!
View convertView = sourceListView.getChildAt(0);
if (null != convertView)
{
//view距离屏幕顶端距离
int convertViewLocationY = 0;
//ListView中item距离ListView的顶部距离
int itemLocationY = 0;
//获取该VIEW控件相对于手机屏幕的绝对坐标位置
convertView.getLocationOnScreen(location);
convertViewLocationY = location[1];
itemLocationY = - (listViewYLocation - convertViewLocationY);
int selectIndex = sourceListView.getFirstVisiblePosition();
desListView.setSelectionFromTop(selectIndex, itemLocationY);
}
}
}
}
63:
private boolean isFirstItem()
{
if (mChatListView != null)
{
if (mChatListView.getCount() == 0)
{
return true;
}
else if (mChatListView.getFirstVisiblePosition() == 0)
{
final View firstVisibleChild = mChatListView.getChildAt(0);
final View secondVisibleChild = mChatListView.getChildAt(1);
// 只要Listview中的第一个item是Loading,则触发请求,不论该item在屏幕中可见部分是多少像素。
if (firstVisibleChild != null && firstVisibleChild == headerView)
{
//开始执行加载Loading动画
headerView.startAnimation(animationHeaderLoading);
int[] firstVisibleLocation = new int[2];
int[] listviewLocation = new int[2];
if (null != firstVisibleChild)
{
// 获取该VIEW控件相对于手机屏幕的绝对坐标位置
firstVisibleChild.getLocationOnScreen(firstVisibleLocation);
secondVisibleItem = (GroupMessageItem) secondVisibleChild.getTag();
firstVisibleYLocation = firstVisibleLocation[1];
mChatListView.getLocationOnScreen(listviewLocation);
listviewYLocation = listviewLocation[1];
}
return true;
}
}
}
return false;
}
64:Listview特别之处:
1)由于listivew删除头部的前提条件是1)header先要add至listview;2)listview.setAdapter,再可以remove头部
2)如果需要做listview整体上移动作,而listview顶部右一个布局问题,需要实现listivew上移动画是在该布局的下面完成,由于listivew整体移动时依据以其父布局文件,
故而listivew一定要控制在其父布局下面即可。
3)如果listview执行上移动画时,底部会出现空白区域,解决思路可以尝试对包含Listview的容器截图,对图片进行移动。
titleLayout.setDrawingCacheEnabled(true);
titleLayout.buildDrawingCache();
Bitmap bitmap = titleLayout.getDrawingCache();
animationImageView.setImageBitmap(bitmap);
animationImageView.setVisibility(View.VISIBLE);
titleLayout.setVisibility(View.INVISIBLE);
translateAnimation = new TranslateAnimation(0f, 0f, 0f, -lineViewFlow.getHeight());
translateAnimation.setDuration(animationMillilis);
animationImageView.startAnimation(translateAnimation);
lineViewFlow.setVisibility(View.GONE);
65:旋转动画,如果出现没有按照中心点运行,可能的原因就是布局问题。
66:如果需要做在指定的时间内容界面无任何操作,执行某个动作,可以通过发送延时Handle。
67:动画执行和Ui操作不同步时,导致的原因可能是布局文件的层次结构导致。
68:如果布局需要实现上下两层的话,可以通过RelativeLayout实现,同时最上面的布局,应该放置在布局文件的最底部
69:如果view设置成View.INVISIBLE后,未生效,可能的原因
1)布局的问题
2)view是否设置了setFillAfter(true);
70:Android客户端布局文件中的每个空间的位置如果相对于布局本身不动的话,则离左边、右边、上边、下边都是为0,所以大家在理解布局文件的的元素布局是一定要搞清楚,为0的意思不是在手机最顶部的原点位置,切记!
71:性能优化和体验优化总结
1)如果在支持比较费时的操作且需要用户立刻显示界面时,可以采用AsynTask、发送延时Handler、Thread等。
72:Application 'com.hotalk' has its 'debuggable' attribute set to FALSE and cannot be debugged.
是由于AndroidManifest.xml文件中的Application中设置了debug模式.73:如果运行eclipse时,出现ADB server didn't ACK * failed to start daemon * error: unknown host service问题,且通过重启adb、eclipse、升级adt,都无效时,可以考虑如下: 1)到任务栏清除ADB.exe 2)关闭PC上面的手机连接助手工具进程。 3)重启adb
74:Android 实现Activity后台运行 第一种方法 Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
第二种方法:此方法其实不是主要是屏蔽Keycode_Back,让它不结束(finish())Activity,直接显示HOME界面。 PackageManager pm = getPackageManager(); ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), 0);
if (keyCode == KeyEvent.KEYCODE_BACK) { ActivityInfo ai = homeInfo.activityInfo; Intent startIntent = new Intent(Intent.ACTION_MAIN); startIntent.addCategory(Intent.CATEGORY_LAUNCHER); startIntent.setComponent(new ComponentName(ai.packageName, ai.name)); startActivitySafely(startIntent); return true; } else { return super.onKeyDown(keyCode, event); }
75:解决出现ANR问题的部分技术细节 1)错误的使用SQLiteDatabase事物,需要捕获潜在的异常,不要因为未调用的transExecSQL中的endTransaction方法,导致30秒异常 2)重复Handler注册和发送信息
76:eclipse启动日志中出现如下异常: *** java list.cache' not found. 解决方法:删除eclipse对应workspace下面的.metadata文件夹
77:有些时候通过程序对控件的位置进行调整(XXX.setMargins(0, 0, 0, 0);)时,往往会在特殊机型中失效,原因可能如下: 控件对应父布局RelativeLayout、LinearLayout使用导致,建议使用RelativeLayout相对布局。
78:onInterceptTouchEvent和onTouchEvent调用时序 SDK中说明: 1. down事件首先会传递到onInterceptTouchEvent()方法 2. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false, 那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最 终的目标view的onTouchEvent()处理 3. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true, 那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样 传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。 4. 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一 层次的view的onTouchEvent()处理 5. 如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递 给该view的onTouchEvent()处理
79:代码中合入手势事件1:实现OnGestureListener接口中的方法,主要是onFling方法2:定义GestureDetector事件mGestureDetector = new GestureDetector(this); new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (mGestureDetector.onTouchEvent(event)) { return true; } return false; } };3:需要重写Activity中的dispatchTouchEvent方法public boolean dispatchTouchEvent(MotionEvent event) { if (mGestureDetector.onTouchEvent(event)) { event.setAction(MotionEvent.ACTION_CANCEL); } return super.dispatchTouchEvent(event); }http://blog.csdn.net/xiezhenxiang/article/details/6659506
80:ViewPager使用总结1:在使用过程中如果出现"Could not find class 'android.support.v4.view.ViewPager'",处理方式可以通过设置eclipse中Java Build Path ->Order and Export中将android-support-v4.jar置顶
2:Matrix类可以完成控件的缩放、移动、翻转、扭曲等效果,针对这个控件不能是.9图片,因为.9图片是没有实际宽度和高度的。
3:ViewPager使用中需要涉及到PagerAdapter\OnPageChangeListener等类。 1)如何实现View循环功能,PagerAdapter中的instantiateItem可以实现页面循环功能,具体看代码 1、初始化时先设置ViewPager.setCurrentItem(无限大),ViewPager控件初始化时,会依据PageAdapter中view的个数平均在选中项的周围初始化View。 2、int newPosition = arg1 % mListViews.size(); try { ((ViewPager) arg0).addView(mListViews.get(newPosition), 0); } catch (Exception e) { } return mListViews.get(newPosition); 2)如何实现ViewPager滑动过程中,Tab指示图片也在跟随移动,这个具体需要使用到OnPageChangeListener中的onPageScrolled方法,样例代码如下 int newPosition = position % views.size(); float toXDelta = (newPosition + arg1) * offsetOfImageByScroll(Tab均分后一屏宽度); //当从最左边向最右边滑动时 if(viewPagerCurrentIndex == 0 && newPosition == views.size() - 1) { toXDelta = (arg1 - 1) * offsetOfImageByScroll; } setCursorImageLeft(toXDelta + offsetOfImageByParentLeft(Tab指示图片里当前Tab左边的距离)); 3)实现Tab点击事件对应各自的View if(Math.abs(selectIndex - viewPagerCurrentIndex) > 1) { mPager.setCurrentItem(viewPagerVirtualCurrentIndex + (selectIndex - viewPagerCurrentIndex - 1)); } mPager.setCurrentItem(viewPagerVirtualCurrentIndex + (selectIndex - viewPagerCurrentIndex)); 4:通过dimen尺寸资源文件设置layout布局文件中的高度、宽度等其他参数,具体使用如下: 1)在res中的values目录下定义一个dimens.xml,格式如下 <resources> <dimen name="key">value</dimen></resources> 2)通过程序之间获取该值getResources().getDimension(R.dimen.key);
81:布局文件使用总结1:当一个layout配置文件中存在多个RelativeLayout(层叠关系),由于它们渲染是依据layout文件上下顺序进行渲染,故需要展示在最上面的,则应该在最下面
2:当自定义一个控件时(嵌入至layout配置文件中),运行后却无法显示,可能的原因如下1)通过new生产的该控件对象,请修改为通过配置文件中控件ID进行匹配2)layout配置文件其他控件覆盖了
82:解决头像异步加载后,显示的头像和实际不符的问题:出现这个问题的原因可能是采用控件缓存holder被其他Item赋值了,导致头像异常解决方法:可以对handler中的控件设置tag,而在异步加载时通过View.findViewWithTag(tag)再对其进行赋值,确保唯一。83:Handler是运行在主UI线程能力,故至只能在UI中创建 1)通过在Activity、Service中创建 2)如果需要在后台代码中创建,可以通过借助于Handler(Looper looper),而其中的looper则可以通过HandlerThread.getLooper()
84:某些情况下对ImageView通过程序设置图片时,有些时候会失效,原因:1)通过setBackgroundResource设置时,可能失效,可以通过setImageResource。
85:Android通过注册广播接收屏幕解锁事件,但是屏幕加锁事件是不能做接收,只能通过亮屏和暗屏广播做处理。备注:如果是在没有锁屏情况下,亮屏(打电话过程中会出现)--用户没有触发手机的按键事件,示其为解屏。 ACTION_SCREEN_ON:KeyguardManager keyMan = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);if (!keyMan.inKeyguardRestrictedInputMode()) {// 如果是在没有锁屏情况下,亮屏(打电话过程中会出现)FusionField.isScreenUnLocked = true;}86:如何编写自定义设置字体控件需求:android中设置字体只是针对文本内容有效,故这个就是需求的根源,在显示该文本内容时借助于TextView控件(或自定义文本控件)的setTextSize,通过对该方法设置不同的值,再通过刷新所承载该文本控件的父控件(如:Listview),从而完成该功能。思路:1)编写自定义控件(内嵌拖动条控件),实现拖动控制,需要实现SeekBar.OnSeekBarChangeListener内部的方法。2)将该自定义控件合入需要的布局中。
87:android中MotionEvent整理:1:MotionEvent.getX()和getY()得到的值为基于当前控件View相对于手指移动的X、Y坐标,而非基于手机顶部的相对坐标。
88:如何控制程序横竖屏切换 在AndroidManifest.xml文 件中配置对应的Activity即可,如android:screenOrientation="portrait"(andscape是横向,portrait是纵向) 89:更换主题后,导致布局错乱的原因可能是由于布局中设置高度或者宽度等没有设置绝对值,而是wrap_content90:自定义Menu的设计思路:最好的方案是依据layout去控制menu需要显示的位置,而不是通过代码控制,这样做的好处是可以精确无误的控制布局\减少代码维护从而不是很好适配机型的问题\ 可以很好的发挥代码的设计能力。 1)编写布局问题,控制好需要显示的问题。 2)依托PopupWindow类完成相关布局的顶层展示 3)注意事项: opWindow.setFocusable(true); popWindow.update(); //显示及位置设置 popWindow.showAtLocation(headView, Gravity.FILL, 0, 0); //显示及自定义位置设置 popWindow.showAsDropDown(headView, 0, -headView.getHeight());
91:先描述下Android加载.so文件的步骤:
1:通过Android NDK生成相应的.so文件,并会在eclipse对应的工程中生成libs\armeabi文件夹,而so文件必须放置到该目录在,java程序才可以通过System.loadLibrary访问该文件。
2:打包apk时.so文件就可以打包到apk文件里,在apk装到手机上以后 在libs\armeabi下的.so文件应该就会解压到/data/data/package/lib目录下。
3:这样程序就可以直接访问该so文件。
备注:.so的名字必须有'lib'前缀 否则apk解压/安装到手机的时候不会把libs\armeabi下的.so拷贝到/data/data/package/lib目录下。
92:android:sharedUserId权限通过Shared User id--就是指Linux用户,不同用户所属权限不一样,拥有同一个User id的多个APK可以配置成运行在同一个进程中.所以默认就是可以互相访问任意数据. 也可以配置成运行成不同的进程, 同时可以访问其他APK的数据目录下的数据库和文件.就像访问本程序的数据一样.比如某个公司开发了多个Android 程序, 那么可以把数据,图片等资源集中放到APK A中去. 然后这个公司的所有APK都使用同一个User ID, 那么所有的资源都可以从APK A中读取.
当在开发过程中A或者B中任意一个去除了android:sharedUserId属性,可能导致的问题就是A或者B读取相互直接的数据失败。
93:Listview滑动性能优化:1. getView将获取字符串和图片放入到Adapter的构造方法中,以后getView可以直接使用内存中的数据,不需要进行IO操作 2. 将getView使用的函数变为内联函数,提高运行效率 3. getView 中费时操作放入Manager层,提高getView效率。 4. 减少变量声明和在getView中new变量,提高内存和性能 5. 使用变量,则直接使用需要的子类,不要使用父类的引用,提高性能。比如,使用ArrayList<String>, 不要使用List<String> list = new ArrayList<String>() 6. 缩短变量应用层次,比如 LayoutInflater.from(mContext).inflate(resID, parent, false),可以将LayoutInflater.from(mContext)变为一个Adapter的私有成员。如LayoutInflater factory = LayoutInflater.from(mContext)
Apk反编译:1. 首先找到Android软件安装包中的classes.dex把.apk文件改名为.zip,然后解压缩,得到其中的classes.dex文件,它就是java文件编译再通过dx工具打包成的,所以现在我们就用上述提到的2个工具来逆方向导出java源文件
2. 把classes.dex拷贝到dex2jar.bat所在目录。在命令行模式下定位到dex2jar.bat所在目录,运行 dex2jar.bat classes.dex ,生成classes.dex.dex2jar.jar
3. 运行JD-GUI工具(它是绿色无须安装的)打开上面的jar文件,即可看到源代码
94:对于同一个Listview中,需要展示很多布局文件的内容时,大多采用View复用技术,即ConvertView,有些时候列表在滑动过程中不同的布局内容会形成错乱,解决方法:通过在listview中对应的Adapter需要重新getViewTypeCount和getItemViewType方法。当ListView中存在不同视图的Item的时候,Adapter中存在一个int getViewTypeCount()方法返回item使用的View类型的数量(默认为1)。listView根据Adapter的这个方法的返回值,在回收站中建立对应数量的保存区域。而Adapter的int getItemViewType(int position):根据position获取对应item使用的View类型。 ListView会在回收站中根据类型建立不同的保存区域,listView会在调用Adapter 的getView方法之前,根据position获取正确类型的View进行复用。 public int getItemViewType(int position) { // TODO Auto-generated method stub if(letter[position].length() == 1) { return FIRST_LETTER_ITEM; } else { return WORD_ITEM; } } @Override public int getViewTypeCount() { // TODO Auto-generated method stub //因为有两种视图,所以返回2 return 2; }
95:通过 LayoutInflater.from(mContext).inflate(R.layout.****, null, false)获取view时,有些时候会出现显示的内容为空,可能的原因:1:由于该布局文件可能是依附在某个父布局文件中,故而需要将inflate中的第二个参数设置非null
96:android项目中values中文件的作用小结1、colors.xml——当中定义各种颜色值。2、strings.xml——当中定义使用到的字符串常量。3、styles.xml——当中是各个控件的“样式”,样式由一个个属性所组成。我们在编辑xml文件的时候,不同的类所能设置的属性有共同的,也有不同的,都是由样式来控制的。具体可以去看styles.xml这个文件的内容。4、themes.xml其实也是样式,只是适用的范围大一点5、attrs.xml——当中定义的是类的属性,属性是为了能在xml文件中被引用到,换句话说就是指定类中变量(也就是属性的实际作用者)的值。这些属性会在类的构造函数中用到。看过一两个源码就会明白,构造函数中的TypedArray其实就是属性的数组,数组的成员会被赋给类里的成员,完成从xml的初始化。类的构造函数一般有三个,一个是Class(context),这个用于在代码中创建一个类,所以只包含一个上下文;Class(context, attrs)和Class(context, attrs, defStyle)用于从xml创建类的情况。6、dimens.xml定义常量文件--直接在代码或者布局文件中使用即可7、array.xml定义的各类数据8、idxml——为应用的相关资源提供唯一的资源id。id是为了获得xml中的对象而需要的参数,也就是Objects. = findViewById(R.id.id_name)中的id_name。这些值可以在代码中用android.R.id引用到。若在ids.xml中定义了ID,则在layout中可如下定义@id/price_edit,否则@+id/price_edit。
97:android环境变量配置,直接在cmd中输入adb命令即可:1:新增一个系统环境变量android,里面的值--:.; D:/****/tools;D:/****/platform-tools;2: 将该变量(%android%)增加至PATH系统环境值尾部。
98:当点击图片控件等需要背景效果时(selector实现),但是而背景区域是要大于图片本身,这个实现方案有如下两种:1:通过在该image上层,增加一个RelativeLayout,用于控制背景效果区域。2:通过图片控件自身的android:background和android:scaleType来完成。android:scaleType用于控制图片在该控件中显示的样式http://blog.csdn.net/strliu/article/details/7284848
99:Android优化工具使用1:Android-Lint:查错与代码优化利器http://blog.csdn.net/thl789/article/details/80374732:DDMS中start method profiling--程序每个细节耗时统计工具,可以方便统计出每个程序片段耗时
转载自:http://jzhua.iteye.com/blog/1168395