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,如:
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等)。
如:
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://stackoverflow.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.