一、android 精典博文内容推荐

app集成支付宝、app缓存管理、app列表圆角设计、App自动更新之通知栏下载(有续)、索引ListView、App数据格式之解析Json、拖拽ListView  http://www.cnblogs.com/qianxudetianxia/category/293007.html

二、Android命名规范(自定义)

此规范参考自android源码,并加以改进,仅供个人使用,如果你觉得还有可取之处,可以参考下,以后有好的规则,再补充

总体规范:

  类名要清晰,能反映出这个类的作用,最好能达到见名知义的效果

  方法名要使用动宾短语 eg: public boolean moveTaskToBack(boolean nonRoot);

  构造函数使用pascal命名规则,又叫大驼峰规则,首字母大写

  普通方法和成员变量采用小驼峰规则(camel规则),首字母小写

  普通方法的局部变量采用下划线规则,以_开头

1.类的成员变量

  所有公开的类常量:定义为静态final类型,名称全部大写 eg: public static final String ACTION_MAIN = "android.intent.action.MAIN";

  静态变量:名称以s开头 eg: private static long sInstanceCount = 0;

  非静态的私有变量,protected的变量:以m开头 eg: private Intent mIntent;protected ViewParent mParent;

2.方法的命名

  方法参数:名称以p开头,表示param的意思 eg: public int getCount(int pCount);

  方法内的局部变量_开头,

    eg public int getCount (int pCount){

        int _count;

      } 

三、android ListActivity自定义标题栏

android 自定义标题栏的步骤是

protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);        // 这里要主要requestWindowFeature和setContentView先后顺序哦        setContentView(R.layout.main);        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_1);    }

但是这个在ListActivity中好像无效,因为ListActivity没有调用setContentView方法,网上的一些解决方法都是在onCreate中调用setContentView,也就是自己实现layout,

有没有更简单的方法呢,使用上面的那样,

其实是有的,在ListActivity中有一个方法很容易被忽略,ensureList(),这是唯一一个设置了layout的地方,但是不是在oncreate中设置的,listActivity没有实现onCreate方法,

继续找,发现在onRestoreInstanceState(), setListAdapter()和getListView()中调用了,也就是说在这3个方法中都有可能会执行setContentView方法,

知道这个就好办了,

解决方法一:在oncreate方法中调用getListView()代替掉上面的setContentView(R.layout.main)

protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);        //代替掉setContentView        getListView();        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_1);    }

解决方法二:找到你的activity调用setListAdapter的地方,在后面加上面最后一句

protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);        /**         * 你自己的代码         */        setListAdapter(adapter);        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_1);    }

四、Android 设置dialog背景全透明无边框的最简单的方法

做dialog的全透明无边框背景,网上找了n久,都有问题,其实很简单,就两句搞定。

<style name="Translucent_NoTitle" parent="android:style/Theme.Dialog"><item name="android:background">#00000000</item> <!-- 设置自定义布局的背景透明 --><item name="android:windowBackground">@android:color/transparent</item>  <!-- 设置window背景透明,也就是去边框 --></style>

其他的都可以不用设置,有些属性会继承下来,唯一一个没被继承的是 <item name=" android:windowIsTranslucent ">true</item>,这个不设置也没影响 此方法同样可以用于activity,设置activity半透明
res/values/styles.xml<resources>    <style name="Transparent  ">      <item name="android:windowBackground">@color/transparent_background</item>      <item name="android:windowNoTitle">true</item>      <item name="android:windowIsTranslucent">true</item>        <item name="android:windowAnimationStyle">@+android:style/Animation.Translucent</item>    </style>  </resources>  
 res/values/color.xml<?xml version="1.0" encoding="utf-8"?>  <resources>    <color name="transparent_background">#50000000</color>  </resources>  

注意:color.xml的#5000000前两位是透明的效果参数从00--99(透明--不怎么透明),后6位是颜色的设置

manifest.xml<activity android:name=".TransparentActivity" android:theme="@style/Transparent">  </activity>  

五、android layout_gravity失效的问题

相信对于Android的初学者来说,大家都曾经被layout里这两个极其相似的属性迷惑过。
简单使用一下搜索工具,我们就不难找到下面这样的答案:

layout_gravity 表示组件自身在父组件中的位置
gravity 表示组件的子组件在组件中的位置

看似很简单嘛

为什么这么简单的道理,总有同学会发现,在“某些时候”,layout_gravity这个属性不好使了,失去了它应有的作用

问题究竟出在哪里了呢?

当作为父layout的LinearLayout的属性为android:orientation="vertical"的时候,android:layout_gravity="?"这里设为横向的时候才能生效。比如:left,right,center_horizontal等;
当作为父layout的LinearLayout的属性为android:orientation="horizental"的时候,android:layout_gravity="?"这里设为纵向的时候才能生效。比如:top,bottom,center_vertical等;
有一个比较特殊的是center,不管是横向还是纵向的时候,它总有一个方向起作用, 因为LinearLayout他只可能有一个方向,

这nm的,确实让人蛋疼。其实也有点道理吧,就是LinearLayout横向的时候,如果有多个孩子,那就不知道把谁放最右了,

有两个解决方法吧,

(1)用RelativeLayout吧,这个算是费话吧 ,哈哈

(2)在LinearLayout中设置android:gravity这个从官方api的解释是怎么放置它的内容,LinearLayout的内容不就是他的孩子么,问题解决

六、一个神奇的网站http://linux.linuxidc.com/

本文转自http://itindex.net/detail/15843-linux.linuxidc.com-%E8%B5%84%E6%96%99-android

Shared by Yuan
用户名与密码都是 www.linuxidc.com

linux.linuxidc.com - /2011年资料/Android入门教程/

[转到父目录]             2011年7月16日    21:33     <目录> Android 3D 游戏开发教程             2011年8月18日    13:26     <目录> Android WIFI开发介绍             2011年7月25日    16:53     <目录> Android 实战项目之五子棋附源码             2011年8月12日     8:53     <目录> Android 游戏开发之主角的移动与地图的平滑滚动             2011年7月19日    13:24     <目录> Android 的 Remote Service 开发实例             2011年6月18日     9:41     <目录> Android入门教程系列之1——贪吃蛇改进版             2011年8月13日    20:27     <目录> Android反编译工具             2011年7月18日     8:59       274623 Android图形系统的分析与移植.pdf             2011年8月13日    19:59     <目录> Android学习之三步搞定开机启动程序             2011年8月13日    20:13     <目录> Android学习之多点触摸并不神秘             2011年8月13日    19:54     <目录> Android学习之改变Activity切换方式             2011年8月13日    20:10     <目录> Android学习之解析JSON             2011年8月21日    17:09     <目录> Android小闹钟程序源码             2011年7月19日    21:29     <目录> Android应用开发揭秘             2011年8月20日    19:39     <目录> Android开发:巧妙运用ViewStub写出类似Tab选项卡             2011年8月23日     8:00     <目录> Android技术内幕 PDF             2011年7月26日    19:20     <目录> Android框架及应用开发介绍             2011年8月12日     9:10     <目录> Android游戏开发之切换游戏场景特效的实现             2011年8月18日     8:53     <目录> Android游戏开发之单点触摸与多点触摸的响应方式             2011年7月27日     7:59     <目录> Android游戏开发之地图编辑器的使用以及绘制地图             2011年8月14日     6:33     <目录> Android游戏开发之处理按键的响应方式             2011年8月12日     9:26     <目录> Android游戏开发之处理音乐与音效太鼓达人游戏原理             2011年8月22日    14:18     <目录> Android游戏开发之多线程的操作方式源码             2011年8月22日    14:07     <目录> Android游戏开发之小球重力感应实现源码             2011年8月12日     7:58     <目录> Android游戏开发之摄像头的原理以及更新             2011年8月12日     9:01     <目录> Android游戏开发之数据库SQLite 详细介绍             2011年8月12日     8:38     <目录> Android游戏开发之构建游戏框架View与SurFaceView的区别             2011年8月12日     8:33     <目录> Android游戏开发之检测游戏碰撞的原理实现             2011年8月12日     8:14     <目录> Android游戏开发之游戏帧动画的播放与处理             2011年8月12日     8:47     <目录> Android游戏开发之绘制游戏主菜单与进度条加载进度             2011年8月18日     8:58     <目录> Android游戏开发之触摸轨迹曲线的实现处理             2011年8月12日     9:14     <目录> Android游戏开发之飞行射击类游戏原理实现             2011年7月29日    19:40     <目录> Android游戏引擎ANGLE 实例和源码             2011年7月17日    11:24     <目录> Android的binder机制研究(C++部分)              2011年8月6日     8:29     <目录> Android笔记 Application对象的使用-数据传递以及内存泄漏问题              2011年8月6日     8:33     <目录> Android笔记 SQLite总结 ,字带数据库,附记事本,字典小程序             2011年8月18日    13:40     <目录> Android系统中WiFi网络的研究与实现             2011年8月12日     8:28     <目录> Android软件开发之EditText 详解             2011年8月12日     8:41     <目录> Android软件开发之ListView 详解             2011年8月12日     8:05     <目录> Android软件开发之TextView详解             2011年8月12日     9:04     <目录> Android软件开发之应用程序之间的通信介绍             2011年8月12日     8:51     <目录> Android软件开发之数据的新建 储存 读取 删除             2011年7月25日    17:04     <目录> Android软件开发之盘点             2011年8月12日     8:57     <目录> Android软件开发之盘点界面五大布局             2011年6月25日    18:57     <目录> Google Android SDK开发范例大全             2011年8月18日    14:02     <目录> Google Android学习一点通(高清中文版)             2011年6月25日     9:09     <目录> Professional Android Application Development [PDF]             2011年6月28日    15:43     <目录> Ubuntu 11.04 搭建Android开发环境             2011年7月21日    11:40     <目录> 一款Android上小游戏--交互式人机对战五子棋             2011年7月21日    11:54     <目录> 制作可独立分发的Android模拟器             2011年8月16日     8:56     <目录> 基于 Android NDK 的学习之旅-----Java 调用C             2011年8月16日    10:17     <目录> 基于 Android NDK 的学习之旅-----序言             2011年8月17日    15:46     <目录> 基于Android的高效短信查询软件的实现             2011年7月18日     9:00       307448 基于Android的高效短信查询软件的实现.pdf

七、android:layout_weight的巧妙应用(二)

之前我讲过layout_weight的巧妙应用一http://www.cnblogs.com/xiaoQLu/archive/2011/08/08/2130328.html

现在更深入讲下weight的其他应用和原理

先看下图,我要用LinearLayout实现如下效果,2要自适应大小,也就是wrap_content,1要占满剩下的空间怎么办?(当然用相对布局很简单)

如果我要再实现一个更变态点的需求呢,就是2位置要动态变换呢(右图所示效果),根据不同的状态,设置2位置不同控件的隐藏和显示,这种情况下,用RelativeLayout实现就有点麻烦了,你要找到一个基准控件,然后根据他来布局其他控制,如果有一个设置不对,显示的布局就没有这个效果

先分析此问题的难点:

  (1)控件2的宽度不确实的,导致1不知道自己的宽度要设为多少。

  (2)控件2的位置有多个控件,需要动态控制不同控件来显示和隐藏

如果用LinearLayout就简单很多,linearlayout有一个属性,就是本篇的主角android:layout_weight属性,它是属于LinearLayout特有的。

用LinearyLayout实现有两种写法,都差不多。写提供代码

实现一<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="horizontal" >    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_weight="1"        android:text="@string/hello" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/app_name" /></LinearLayout>
实现二<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="horizontal" >    <Button        android:layout_width="0dip"        android:layout_height="wrap_content"        android:layout_weight="1"        android:text="@string/hello" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/app_name" /></LinearLayout>

其实这两种实现只有一点区别,就是第一个button的layout_weidth,一个是fill_parent,另一个是0dip。其实两种都差不多,下边详细讲解:

首先大家要明白一个概念,就是一个控件(View)本身是可以无限大的,也说是说在它自己的onDraw()函数中,你想要它多大,它就可以有多大,但是为什么我们只能看到一部分呢?

这就要"归功"于android:layout_width和height属性,很多人认为这个是设置控制本身大小的,其实这个理解有偏差,layout_width这个属性不是控制一个子控件它本身的大小(自身大小由它

自己决定),而是父布局提供给这个控件的显示窗口大小,这里叫申请大小(下面同理)

然后来讲解详细的计算过程,当LinearLayout包含的视图weight>0时,它会mesure两次(这里以上面第一个布局来讲解)

第一次,计算剩余空间,就是用屏幕的宽度减去子控件申请的宽度。设屏幕宽度为TW,第一个button的申请宽度设为x1,weight为w1,第二个button的申请宽度设为x2,weight为w2,剩余空间设为delta

表达示为 delta =TW - (x1+x2)

第二次,分配空间,即父视图最终提供给子控件的显示窗口的大小,

button1的最终显示大小为  x1+delta*w1/(w1+w2)

button2的最终显示大小为   x2+delta*w2/(w1+w2)

结合上面的实例来说明

上面第一个布局,假设手机分辨率为480x320,btn1申请宽度为fill_parent=320,btn2的申请宽度为wrap_content,这个是会调用控件自身的onMeasure计算出来的,假设计算结果为40,那么

第一步剩余空间就是320-(320+40) = -40,

第二步,分配空间,btn1的最终显示空间为320+(-40)*(1/(1+0)) = 240,btn2的最终显示空间为40+(-40*0/(1+0)) = 40

这样就满足了我们开始的那个需求,

再分析第一个布局,其实本质和第一个布局一样,只是把减去变为加上而已

第一步,剩余空间 = 320-(0+40) = 280;

第二步,分配 btn1最终空间 0+280*1/(1+0) = 280,btn2的最终空间为40+280*0/(0+1)

八、HashMap的遍历效率讨论(转载)

本文转自http://hi.baidu.com/injava/item/aac168cd66af7a090bd93a3e

HashMap的遍历效率讨论

经常遇到对HashMap中的key和value值对的遍历操作,有如下两种方法:

Map<String, String[]> paraMap = new HashMap<String, String[]>();
................
//第一个循环
Set<String> appFieldDefIds = paraMap.keySet();
for (String appFieldDefId : appFieldDefIds) {
String[] values = paraMap.get(appFieldDefId);
......
}


//第二个循环
for(Entry<String, String[]> entry : paraMap.entrySet()){
String appFieldDefId = entry.getKey();
String[] values = entry.getValue();
.......
}

第一种实现明显的效率不如第二种实现。
分析如下 Set<String> appFieldDefIds = paraMap.keySet(); 是先从HashMap中取得keySet

代码如下:
public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}

private class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return HashMap.this.removeEntryForKey(o) != null;
}
public void clear() {
HashMap.this.clear();
}
}

其实就是返回一个私有类KeySet, 它是从AbstractSet继承而来,实现了Set接口。

再来看看for/in循环的语法
for(declaration : expression)
statement

在执行阶段被翻译成如下各式
for(Iterator<E> #i = (expression).iterator(); #i.hashNext();){
declaration = #i.next();
statement
}

因此在第一个for语句for (String appFieldDefId : appFieldDefIds) 中调用了HashMap.keySet().iterator() 而这个方法调用了newKeyIterator()

Iterator<K> newKeyIterator() {
return new KeyIterator();
}
private class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}

所以在for中还是调用了
在第二个循环for(Entry<String, String[]> entry : paraMap.entrySet())中使用的Iterator是如下的一个内部类

private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
}

此时第一个循环得到key,第二个循环得到HashMap的Entry
效率就是从循环里面体现出来的第二个循环此致可以直接取key和value值
而第一个循环还是得再利用HashMap的get(Object key)来取value值

现在看看HashMap的get(Object key)方法
public V get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length); //Entry[] table
Entry<K,V> e = table[i];
while (true) {
if (e == null)
return null;
if (e.hash == hash && eq(k, e.key))
return e.value;
e = e.next;
}
}
其实就是再次利用Hash值取出相应的Entry做比较得到结果,所以使用第一中循环相当于两次进入HashMap的Entry中
而第二个循环取得Entry的值之后直接取key和value,效率比第一个循环高。

其实按照Map的概念来看也应该是用第二个循环好一点,它本来就是key和value的值对,将key和value分开操作在这里不是个好选择。

九、listview反弹实现详解

本文转自http://jianwang0412.iteye.com/blog/1267885

重写listview,通过监听滑动事件,根据滑动时所处的位置,以及滑动的方向,使用view的内置scrollTo或scrollBy函数来移动view到你手势互动的距离(此处为一半),然后当确定消费了给事件后,又回滚到(0,0)点。当然只有在超出了边界时才回滚。而且回滚的过程由TranslateAnimation来控制,这样的好处在代码的解释中。我是基于网络上的listviewpress改了一些(有几处好像是被篡改了,我又按我的理解将它改正过来,运行后没问题)。一下是关键的代码,整个代码见附件中。有不懂的可以问问,大家互相学习。

  1. packagecom.listview.test;
  2. importandroid.content.Context;
  3. importandroid.graphics.Rect;
  4. importandroid.util.AttributeSet;
  5. importandroid.util.Log;
  6. importandroid.view.GestureDetector;
  7. importandroid.view.MotionEvent;
  8. importandroid.view.View;
  9. importandroid.view.GestureDetector.OnGestureListener;
  10. importandroid.view.animation.TranslateAnimation;
  11. importandroid.widget.ListView;
  12. publicclassCustomerListViewextendsListView{
  13. privateContextmContext;
  14. privatebooleanoutBound=false;
  15. privateintdistance;
  16. privateintfirstOut;
  17. publicCustomerListView(Contextc){
  18. super(c);
  19. this.mContext=c;
  20. }
  21. publicCustomerListView(Contextc,AttributeSetattrs){
  22. super(c,attrs);
  23. this.mContext=c;
  24. }
  25. publicCustomerListView(Contextc,AttributeSetattrs,intdefStyle){
  26. super(c,attrs,defStyle);
  27. this.mContext=c;
  28. }
  29. GestureDetectorgestureDetector=newGestureDetector(
  30. newOnGestureListener(){
  31. publicbooleanonDown(MotionEvente){
  32. //TODOAuto-generatedmethodstub
  33. returnfalse;
  34. }
  35. publicbooleanonFling(MotionEvente1,MotionEvente2,
  36. floatvelocityX,floatvelocityY){
  37. //TODOAuto-generatedmethodstub
  38. returnfalse;
  39. }
  40. publicvoidonLongPress(MotionEvente){
  41. //TODOAuto-generatedmethodstub
  42. }
  43. /**捕捉滑动事件e1为此处为的ACTION_DOWN事件(无论什么动作,起始都是该动作),而e2是触发调用onScroll的事件。而在此期间,可能已经
  44. *触发了多次的onScroll,因为我们滑动过程可能比较长,一旦长于某个值,就会触发一次(即一个Move应该是由多个
  45. *move事件组成的,开头当然是个ACTION_DOWN事件),也就会发出一个移动的MotionEvent。但是期间开始此次
  46. *scroll的e1是唯一的。而distance是最近一次调用onScroll以来的距离(前一个e2和现在e2的距离:比如上次是-30,这次是-60(比如向下拉),
  47. *那么distanceY=-60-(-30)=-30)。
  48. */
  49. publicbooleanonScroll(MotionEvente1,MotionEvente2,
  50. floatdistanceX,floatdistanceY){
  51. /**
  52. *firstPos和lastPos是adapter中元素的Id
  53. */
  54. intfirstPos=getFirstVisiblePosition();
  55. intlastPos=getLastVisiblePosition();
  56. intitemCount=getCount();
  57. /**
  58. *滑出边界,而且是一个极点,即可视部分已经已经不存在了,那么直接回到原点
  59. */
  60. if(outBound&&firstPos!=0&&lastPos!=(itemCount-1)){
  61. scrollTo(0,0);
  62. returnfalse;
  63. }
  64. /**
  65. *getChildAt是屏幕上可见的元素的id,比如现在屏幕上可见的是adapter中的
  66. *4号到10号,那么你调用getChildAt应该是0~6号
  67. *listView.getChildAt(i)workswhere0istheveryfirstvisiblerowand
  68. *(n-1)isthelastvisiblerow(wherenisthenumberofvisibleviewsyousee).
  69. *进入该onScroll有4种可能,第一种是刚开始的时候,此时firstPos==0,而且可视的item在getChildAt的
  70. *返回也是第一个元素,即adapter元素的index和可视的view的编号一致,所以firstview不为空(lastview也一样)。
  71. *当你向上滑动时,distanceY是大于0的。此时将不消费此次事件,那么将正常地在没有超出边际出滚动。
  72. *第二种是,若以上是向下拉,那么应该属于超出范围的情况,则要消费此时事件。
  73. *第三种和第一种类似,只是到了当刚好显示最后一个item时,显然firstView和lastView都将是null,因为
  74. *此时的adapter的index和getChildAt的index不是相等的,而是成对应关系,
  75. *即index_adp-firstPos=index_getChild,此时你若使用getChildAt(firstpos-firstpos),那返回的
  76. *将是非null。同理在lastView。第四种是当在第三情况下,向上拉,那么属于超出边界。那么lastView是null这个特征
  77. *将可以判断是否进入了下临界区。
  78. *总结以上四种情况,每当触发临界区时(dispatchTouchEvent时getFirstVisiblePosition()==0
  79. *和getLastVisiblePosition()==getCount()-1),就可以通过distanceY的方向性判断是正常的滑动
  80. *还是将要滑出临界区。若是滑出临界区,说明此次将消费该事件,所以返回true,那么在dispatchTouchEvent
  81. *将设置outBand为true,那么第二次再进入时,将可以通过outBand来确定是否出了临界区。
  82. *
  83. *带方向的函数:onScrollBy/To和onScroll
  84. */
  85. ViewfirstView=getChildAt(firstPos);
  86. ViewlastView=getChildAt(lastPos-1);
  87. /**
  88. *记录下第一次的e2的y轴距离,此次过后outBound就变为了true。这样distance就是跟踪最近的一次e2
  89. *和最开始一次的e2的距离。
  90. */
  91. if(!outBound){
  92. firstOut=(int)e2.getRawY();
  93. }
  94. if(firstView!=null
  95. &&(outBound||(firstPos==0
  96. &&firstView.getTop()==0&&distanceY<0))){
  97. distance=(int)(firstOut-e2.getRawY());//此处应为负值,即view向下滑动
  98. /**
  99. *scrollBy中的值带有方向,x若为正,则应该以view中该x点显示在新的原点上,即拿新的点去
Java代码
  1. <spanstyle="white-space:pre;"></span>*重合y轴,就好像整个布局被往左拉动。
  2. *y为正,则向上滑动|y|距离。负则相反。
  3. */
  4. scrollBy(0,distance/2);
  5. Log.v("onScroll","e2.getRawY():"+e2.getRawY());
  6. Log.v("onScroll","distance:"+distance);
  7. Log.v("onScroll","distanceY:"+distanceY);
  8. returntrue;
  9. }
  10. if(lastView==null&&(outBound||(lastPos==itemCount-1&&distanceY>0))){
  11. Log.d("bottom","bottom");
  12. distance=(int)(firstOut-e2.getRawY());//此处应为正直,因为view向上滑动
  13. scrollBy(0,distance/2);
  14. returntrue;
  15. }
  16. returnfalse;
  17. }
  18. publicvoidonShowPress(MotionEvente){
  19. //TODOAuto-generatedmethodstub
  20. }
  21. publicbooleanonSingleTapUp(MotionEvente){
  22. //TODOAuto-generatedmethodstub
  23. returnfalse;
  24. }
  25. });
  26. /**
  27. *最早响应触屏事件,按下和释放响应两次
  28. */
  29. publicbooleandispatchTouchEvent(MotionEventev){
  30. if(getFirstVisiblePosition()==0){
  31. intact=ev.getAction();
  32. if((act==MotionEvent.ACTION_UP||act==MotionEvent.ACTION_CANCEL)
  33. &&outBound){
  34. outBound=false;
  35. }
  36. if(!gestureDetector.onTouchEvent(ev)){
  37. outBound=false;
  38. }else{
  39. outBound=true;
  40. }
  41. Rectrect=newRect();
  42. getLocalVisibleRect(rect);
  43. /**
  44. *rect.top是个正的距离值,而TanslateAnimation填的是坐标值(有方向的);
  45. */
  46. TranslateAnimationam=newTranslateAnimation(0,0,-rect.top,0);
  47. /**
  48. *若此处时间设为0,将导致一阵的抖动,因为完成回滚的速度不是分步,而是直接到终点
  49. *因为每次触发onScroll时都会做一次回滚,而当传进又一次move时,上一次的move还没作完
  50. *就将被新的一次覆盖,所以不用担心产生抖动。所以此处给它设时间就是抓住它需要时间来完成回滚的目标,相当
  51. *于给它一个时间的缓冲来实现移动,因为当你在移动时,实际是不需要回滚的,只有你释放了手指还才需要回滚。
  52. *注意,此时调用scrollTo已经将位置返回了0(可以把animation当成是模型,只有使用scrollTo才
  53. *能真正触发该移动,结果是已经知道了的,即移动到原点,而过程是TranslateAnimation参谋的,即
  54. *scrollTo在移动时会调用onScrollChange来实际移动,而onScrollChange则根据传入的参数来移动
  55. *而TranslateAnimation则可以控制该参数。可以把scrollTo先去掉,就可以发现newtop和
  56. *afterscrollBy是一样的值)。也就是newTop=0。所以每次迭代相减都是现在的e2减去最初的e2在y轴上的值,
  57. *这样通过scrollBy就可以将view移动到新的位置,而此时top也就又被写成了新的滑动的位置(是滑动距离的一半位置)。
  58. *11-1923:51:11.101:V/onScroll(18396):afterscrollBytop:0
  59. 11-1923:51:11.101:V/onScroll(18396):newtop:0
  60. 11-1923:51:11.249:V/onScroll(18396):afterscrollBytop:0
  61. 11-1923:51:11.249:V/onScroll(18396):newtop:0
  62. 11-1923:51:11.288:V/onScroll(18396):afterscrollBytop:-6
  63. 11-1923:51:11.288:V/onScroll(18396):newtop:0
  64. 11-1923:51:11.319:V/onScroll(18396):afterscrollBytop:-16
  65. 11-1923:51:11.319:V/onScroll(18396):newtop:0
  66. 11-1923:51:11.358:V/onScroll(18396):afterscrollBytop:-20
  67. 11-1923:51:11.358:V/onScroll(18396):newtop:0
  68. 11-1923:51:11.374:V/onScroll(18396):afterscrollBytop:-27
  69. 11-1923:51:11.374:V/onScroll(18396):newtop:0
  70. */
  71. am.setDuration(300);
  72. startAnimation(am);
  73. Log.v("onScroll","afterscrollBytop:"+rect.top);
  74. scrollTo(0,0);
  75. getLocalVisibleRect(rect);
  76. Log.v("onScroll","newtop:"+rect.top);
  77. }
  78. Log.d("getLastVisiblePosition()",getLastVisiblePosition()+"");
  79. Log.d("getCount()",getCount()+"");
  80. if(getLastVisiblePosition()==getCount()-1){
  81. intact=ev.getAction();
  82. if((act==MotionEvent.ACTION_DOWN||act==MotionEvent.ACTION_CANCEL)
  83. &&outBound){
  84. outBound=false;
  85. }
  86. if(!gestureDetector.onTouchEvent(ev)){
  87. outBound=false;
  88. }else{
  89. outBound=true;
  90. }
  91. if(outBound){
  92. Rectrect1=newRect();
  93. getLocalVisibleRect(rect1);
  94. TranslateAnimationam1=newTranslateAnimation(0,0,rect1.top,0);
  95. am1.setDuration(300);
  96. startAnimation(am1);
  97. scrollTo(0,0);
  98. }
  99. }
  100. returnsuper.dispatchTouchEvent(ev);
  101. };
  102. }

listviewPress.zip(82.6 KB)

十、Android SAX解析之错误纠正!!

本文转自http://blog.csdn.net/feng88724/article/details/7013675

在讲这次错误之前,先看一下下面这段代码。 【◆以下解析方法是错误的×】

[java] view plain copy print ?
  1. importjava.util.ArrayList;
  2. importjava.util.List;
  3. importorg.xml.sax.Attributes;
  4. importorg.xml.sax.SAXException;
  5. importorg.xml.sax.helpers.DefaultHandler;
  6. importandroid.util.Log;
  7. publicclassXmlHandlerextendsDefaultHandler{
  8. privatefinalStringTAG=this.getClass().getSimpleName();
  9. /**XML文件中标签定义*/
  10. privatefinalStringTAG_Article="Article";
  11. privatefinalStringTAG_ArticleID="ArticleID";
  12. privatefinalStringTAG_Title="Title";
  13. privatefinalStringTAG_Date="Date";
  14. privatefinalStringTAG_SmallPictures="SmallPictures";
  15. privatefinalStringTAG_LargePictures="LargePictures";
  16. privatefinalStringTAG_Category="Category";
  17. privatestaticfinalStringTAG_HeadNote="HeadNote";
  18. privatestaticfinalStringTAG_SubTitle="SubTitle";
  19. privatestaticfinalStringTAG_Source="Source";
  20. //当前正在解析的TAG
  21. privateStringcurrentName;
  22. //单个文章
  23. privateNewsnews=null;
  24. //文章列表
  25. privateList<News>newsList=null;
  26. //解析开始时间
  27. privatelongstart_time;
  28. privatebooleanflag=false;
  29. @Override
  30. publicvoidcharacters(char[]ch,intstart,intlength)
  31. throwsSAXException{
  32. super.characters(ch,start,length);
  33. if(!flag){
  34. return;
  35. }
  36. //取值
  37. Stringvalue=newString(ch,start,length);
  38. Log.d(TAG,"Element:"+currentName+"ElementValue:"+value);
  39. if(value!=null){
  40. if(TAG_ArticleID.equals(currentName)){
  41. news.setArticleId(value);
  42. }elseif(TAG_Title.equals(currentName)){
  43. news.setTitle(value);
  44. }elseif(TAG_Date.equals(currentName)){
  45. news.setDate(value);
  46. }elseif(TAG_Category.equals(currentName)){
  47. news.setCategory(value);
  48. }elseif(TAG_SmallPictures.equals(currentName)){
  49. news.setSmallPicture(value);
  50. }elseif(TAG_LargePictures.equals(currentName)){
  51. news.setLargePicture(value);
  52. }elseif(TAG_HeadNote.equals(currentName)){
  53. news.setHeadNote(value);
  54. }elseif(TAG_SubTitle.equals(currentName)){
  55. news.setSubTitle(value);
  56. }elseif(TAG_Source.equals(currentName)){
  57. news.setSource(value);
  58. }
  59. }
  60. }
  61. @Override
  62. publicvoidstartDocument()throwsSAXException{
  63. super.startDocument();
  64. start_time=System.currentTimeMillis();
  65. newsList=newArrayList<News>();
  66. }
  67. @Override
  68. publicvoidstartElement(Stringuri,StringlocalName,StringqName,Attributesattributes)throwsSAXException{
  69. super.startElement(uri,localName,qName,attributes);
  70. this.currentName=localName;
  71. flag=true;
  72. if(TAG_Article.equals(localName)){
  73. news=newNews();
  74. }
  75. }
  76. @Override
  77. publicvoidendElement(Stringuri,StringlocalName,StringqName)
  78. throwsSAXException{
  79. super.endElement(uri,localName,qName);
  80. flag=false;
  81. if(TAG_Article.equals(localName)){
  82. newsList.add(news);
  83. }
  84. }
  85. @Override
  86. publicvoidendDocument()throwsSAXException{
  87. super.endDocument();
  88. longend=System.currentTimeMillis();
  89. Log.d(TAG,"ParseList'sXmlCost:"+(end-start_time)+"!!");
  90. }
  91. }


Baidu 或者 Google 一下 “Android Sax 解析” , 给出的Sample无一例外都是如此。 坑爹啊... 甚至连有些书籍中都是这么写的, 比如《Android开发入门与实践》。(本书亲自确认过,其他书情况不详)

没错, 一般情况下,这么写是可以的, 而且在大多数情况下解析出来也是正确的。 但是就是偶尔会出错, 这个时候通常你都莫不着头脑, 怎么回事? 数据没错啊,解析部分代码貌似也没问题.. 真是奇了怪了。 其实问题都出在上面那段代码上!!

大家都认为 SAX 解析过程大致如下:

startDocument -> startElement ->characters ->endElement ->endDocument

没错,就是这样,startElement 读取起始标签,endElement 读取结束标签,characters 呢?当然是读取其值, 这没错,但是大家都天真的以为characters 只执行一次,并且一次就读取了全部内容。错就错在这!

其实characters 是很有可能会执行多次的,当遇到内容中有回车,\t等等内容时,它很有可能就执行多次。 有的人可能会说,那我没有这些是不是就只执行一次了? 看下我实测结果:

测试用XML如下:

[html] view plain copy print ?
  1. <News>
  2. <Article>
  3. <ArticleID>1000555</ArticleID>
  4. <Title><![CDATA[郑州“亚洲第一桥”通车6年成危桥]]></Title>
  5. <Date>2011-11-2514:23:52</Date>
  6. <SmallPictures>livenews/images/s20.png</SmallPictures>
  7. <LargePictures>livenews/images/l20.png</LargePictures>
  8. <Category>闻天下</Category>
  9. <HeadNote></HeadNote>
  10. <SubTitle></SubTitle>
  11. <Author></Author>
  12. <Source>人民日报</Source>
  13. <Abstract></Abstract>
  14. </Article>
  15. <Article>
  16. <ArticleID>1000554</ArticleID>
  17. <Title><![CDATA[内地事业单位拟设统一工资制度]]></Title>
  18. <Date>2011-11-2514:22:33</Date>
  19. <Category><![CDATA[闻天下]]></Category>
  20. <HeadNote></HeadNote>
  21. <SubTitle></SubTitle>
  22. <Author></Author>
  23. <Source></Source>
  24. <Abstract></Abstract>
  25. </Article>
  26. <Article>
  27. <ArticleID>1000553</ArticleID>
  28. <Title></Title>
  29. <Date>2011-11-2514:21:23</Date>
  30. <SmallPictures>livenews/images/s21.png</SmallPictures>
  31. <LargePictures>livenews/images/l21.png</LargePictures>
  32. <Category><![CDATA[星娱乐]]></Category>
  33. <HeadNote></HeadNote>
  34. <SubTitle></SubTitle>
  35. <Author></Author>
  36. <Source><![CDATA[凤凰网综合]]></Source>
  37. <Abstract></Abstract>
  38. </Article>
  39. <News>

可以很明显的看到,在解析 <ArticleID>1000553</ArticleID> 这一段时,characters执行了两次,将内容"1000553"分两次读取.. 用上面那种方式的最终结果就是ArticleID = 00553 了。 那如果你的应用需要根据这个id 进一步获取内容岂不是死翘翘了?(比如这边根据id获取新闻详细内容)

好了,废话不多说了,看下正确的写法! 【★以下解析方法才是正确的 √ 】

[java] view plain copy print ?
  1. importjava.util.ArrayList;
  2. importjava.util.List;
  3. importorg.xml.sax.Attributes;
  4. importorg.xml.sax.SAXException;
  5. importorg.xml.sax.helpers.DefaultHandler;
  6. importandroid.util.Log;
  7. publicclassXmlHandlerextendsDefaultHandler{
  8. privatefinalStringTAG=this.getClass().getSimpleName();
  9. /**XML文件中标签定义*/
  10. privatefinalStringTAG_Article="Article";
  11. privatefinalStringTAG_ArticleID="ArticleID";
  12. privatefinalStringTAG_Title="Title";
  13. privatefinalStringTAG_Date="Date";
  14. privatefinalStringTAG_SmallPictures="SmallPictures";
  15. privatefinalStringTAG_LargePictures="LargePictures";
  16. privatefinalStringTAG_Category="Category";
  17. privatestaticfinalStringTAG_HeadNote="HeadNote";
  18. privatestaticfinalStringTAG_SubTitle="SubTitle";
  19. privatestaticfinalStringTAG_Source="Source";
  20. //单个文章
  21. privateNewsnews=null;
  22. //文章列表
  23. privateList<News>newsList=null;
  24. //解析开始时间
  25. privatelongstart_time;
  26. //(1)
  27. privateStringBuildersb=newStringBuilder();
  28. @Override
  29. publicvoidcharacters(char[]ch,intstart,intlength)
  30. throwsSAXException{
  31. super.characters(ch,start,length);
  32. //(2)不管在startElement到endElement的过程中,执行了多少次characters,都会将内容添加到StringBuilder中,不会丢失内容
  33. sb.append(ch,start,length);
  34. }
  35. @Override
  36. publicvoidstartDocument()throwsSAXException{
  37. super.startDocument();
  38. start_time=System.currentTimeMillis();
  39. newsList=newArrayList<News>();
  40. }
  41. @Override
  42. publicvoidstartElement(Stringuri,StringlocalName,StringqName,Attributesattributes)throwsSAXException{
  43. super.startElement(uri,localName,qName,attributes);
  44. //(3)开始收集新的标签的数据时,先清空历史数据
  45. sb.setLength(0);
  46. if(TAG_Article.equals(localName)){
  47. news=newNews();
  48. }
  49. }
  50. @Override
  51. publicvoidendElement(Stringuri,StringlocalName,StringqName)
  52. throwsSAXException{
  53. super.endElement(uri,localName,qName);
  54. //(4)原来在characters中取值,现改在此取值
  55. Stringvalue=sb.toString();
  56. if(TAG_ArticleID.equals(localName)){
  57. news.setArticleId(value);
  58. }elseif(TAG_Title.equals(localName)){
  59. news.setTitle(value);
  60. }elseif(TAG_Date.equals(localName)){
  61. news.setDate(value);
  62. }elseif(TAG_Category.equals(localName)){
  63. news.setCategory(value);
  64. }elseif(TAG_SmallPictures.equals(localName)){
  65. news.setSmallPicture(value);
  66. }elseif(TAG_LargePictures.equals(localName)){
  67. news.setLargePicture(value);
  68. }elseif(TAG_HeadNote.equals(localName)){
  69. news.setHeadNote(value);
  70. }elseif(TAG_SubTitle.equals(localName)){
  71. news.setSubTitle(value);
  72. }elseif(TAG_Source.equals(localName)){
  73. news.setSource(value);
  74. }
  75. if(TAG_Article.equals(localName)){
  76. newsList.add(news);
  77. }
  78. }
  79. @Override
  80. publicvoidendDocument()throwsSAXException{
  81. super.endDocument();
  82. longend=System.currentTimeMillis();
  83. Log.d(TAG,"ParseList'sXmlCost:"+(end-start_time)+"!!");
  84. }
  85. }


归纳为三点:

1.startElement的时候,new StringBuilder(); 或者sb.setLength(0); (我建议后者)
2.characters的时候,sb.append(ch, start, length);
3.endElement的时候,sb.toString(); 此时StringBuilder中的内容才是解析的结果

通过这种方法就不会再有数据离奇丢失的情况了(同时也不需要像错误方法那样再设个currentTag之类的了,逻辑繁杂了,还出错)!

希望大家可以尽早看到这篇文章,不要继续被吭了!!!

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. android上一些方法的区别和用法的注意事项
  5. android EditText设置不可写
  6. Android(安卓)拨号器的简单实现
  7. android实现字体闪烁动画的方法
  8. Android中dispatchDraw分析
  9. Android中不同应用间实现SharedPreferences数据共享

随机推荐

  1. Android(安卓)TabLayout导航条属性的设置
  2. Android(安卓)检测键盘是否显示及隐藏键
  3. Android(安卓)Studio 的 gradle 插件升级
  4. Android(安卓)调用第三方浏览器打开
  5. android-仿QQtab
  6. Android(安卓)之经典源码
  7. 让Android不播放关机动画,而是显示一个关
  8. android studio Build 设置简介
  9. Android(安卓)Wifi模块分析(六)
  10. Android——TabHost(标签容器)相关知识总结