-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
37ab092
commit 8222fd6
Showing
4 changed files
with
285 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package com.yuexue.tifenapp.wxapi; | ||
|
||
import android.os.Build; | ||
|
||
import org.apache.http.NameValuePair; | ||
|
||
import java.util.Iterator; | ||
|
||
/** | ||
* Created by haoxiqiang on 15/3/13. | ||
*/ | ||
public class AndroidMileage { | ||
|
||
final static int[] versionCodes; | ||
final static String[] versionMileages; | ||
final static int size; | ||
|
||
static { | ||
versionCodes = new int[]{ | ||
Build.VERSION_CODES.BASE, Build.VERSION_CODES.BASE_1_1, Build.VERSION_CODES.CUPCAKE, | ||
Build.VERSION_CODES.DONUT, Build.VERSION_CODES.ECLAIR, Build.VERSION_CODES.ECLAIR_0_1, | ||
Build.VERSION_CODES.ECLAIR_MR1, Build.VERSION_CODES.FROYO, Build.VERSION_CODES.GINGERBREAD, | ||
Build.VERSION_CODES.GINGERBREAD_MR1, Build.VERSION_CODES.HONEYCOMB, Build.VERSION_CODES.HONEYCOMB_MR1, | ||
Build.VERSION_CODES.HONEYCOMB_MR2, Build.VERSION_CODES.ICE_CREAM_SANDWICH, Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1, | ||
Build.VERSION_CODES.JELLY_BEAN, Build.VERSION_CODES.JELLY_BEAN_MR1, Build.VERSION_CODES.JELLY_BEAN_MR2, | ||
Build.VERSION_CODES.KITKAT, Build.VERSION_CODES.KITKAT_WATCH, Build.VERSION_CODES.LOLLIPOP | ||
}; | ||
versionMileages = new String[]{ | ||
"October 2008: The original, first, version of Android. Yay!", | ||
"February 2009: First Android update, officially called 1.1.", | ||
" May 2009: Android 1.5.", | ||
"September 2009: Android 1.6.", | ||
"November 2009: Android 2.0", | ||
"December 2009: Android 2.0.1", | ||
"January 2010: Android 2.1", | ||
"June 2010: Android 2.2", | ||
"November 2010: Android 2.3", | ||
"February 2011: Android 2.3.3.", | ||
"February 2011: Android 3.0.", | ||
"May 2011: Android 3.1.", | ||
"June 2011: Android 3.2.", | ||
"October 2011: Android 4.0.", | ||
"December 2011: Android 4.0.3.", | ||
"June 2012: Android 4.1.", | ||
"November 2012: Android 4.2, Moar jelly beans!", | ||
"July 2013: Android 4.3, the revenge of the beans.", | ||
"October 2013: Android 4.4, KitKat, another tasty treat.", | ||
"Android 4.4W: KitKat for watches, snacks on the run.", | ||
"Lollipop. A flat one with beautiful shadows. But still tasty.", | ||
}; | ||
|
||
size = Math.min(versionCodes.length, versionMileages.length); | ||
} | ||
|
||
public static class Mileage implements NameValuePair { | ||
|
||
public String name; | ||
public String value; | ||
|
||
@Override | ||
public String getName() { | ||
return name; | ||
} | ||
|
||
@Override | ||
public String getValue() { | ||
return value; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "versionCode:" + name + " desc:" + value; | ||
} | ||
} | ||
|
||
|
||
public Iterator<Mileage> iterator() { | ||
return new ArrayIterator(); | ||
} | ||
|
||
private class ArrayIterator implements Iterator<Mileage> { | ||
/** | ||
* Number of elements remaining in this iteration | ||
*/ | ||
private int remaining = size; | ||
|
||
/** | ||
* Index of element that remove() would remove, or -1 if no such elt | ||
*/ | ||
private int removalIndex = -1; | ||
|
||
@Override | ||
public boolean hasNext() { | ||
return remaining != 0; | ||
} | ||
|
||
@Override | ||
public Mileage next() { | ||
Mileage mileage = new Mileage(); | ||
removalIndex = size-remaining; | ||
mileage.name = String.valueOf(versionCodes[removalIndex]); | ||
mileage.value = versionMileages[removalIndex]; | ||
remaining-=1; | ||
return mileage; | ||
} | ||
|
||
@Override | ||
public void remove() { | ||
versionCodes[removalIndex]=-1; | ||
versionMileages[removalIndex]="It was set null"; | ||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
Android设计模式源码解析之迭代器(Iterator)模式 | ||
======================================== | ||
> 本文为 [Android 设计模式源码解析](https://github.com/simple-android-framework-exchange/android_design_patterns_analysis) 中 迭代器模式 分析 | ||
> Android系统版本: 5.0 | ||
> 分析者: [haoxiqiang](https://github.com/Haoxiqiang),分析状态:完成,校对者:,校对状态:未完成 | ||
|
||
|
||
## 1. 模式介绍 | ||
### 模式的定义 | ||
迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。 | ||
|
||
### 使用场景 | ||
面向对象设计原则中的单一职责原则,对于不同的功能,我们要尽可能的把这个功能分解出单一的职责,不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。 | ||
Java JDK 1.2 版开始支持迭代器。每一个迭代器提供next()以及hasNext()方法,同时也支持remove()(1.8的时候remove已经成为default throw new UnsupportedOperationException("remove"))。对Android来说,集合Collection实现了Iterable接口,就是说,无论是List的一大家子还是Map的一大家子,我们都可以使用Iterator来遍历里面的元素,[可以使用Iterator的集合](http://docs.oracle.com/javase/8/docs/api/java/util/package-tree.html) | ||
|
||
## 2. UML类图 | ||
|
||
![iterator_2.png](iterator_2.jpg) | ||
|
||
### 角色介绍 | ||
* hasNext:用来判断集合中是否存在未被遍历到的元素 | ||
* remove:移除元素 | ||
* next:将游标(位置)移动到下一个位置 | ||
|
||
|
||
## 3. 模式的简单实现 | ||
|
||
下面直接写出几种集合的遍历方式 | ||
|
||
### HashMap的遍历 | ||
``` | ||
HashMap<String, String> colorMap=new HashMap<>(); | ||
colorMap.put("Color1","Red"); | ||
colorMap.put("Color2","Blue"); | ||
Iterator iterator = colorMap.keySet().iterator(); | ||
while( iterator. hasNext() ){ | ||
String key = (String) iterator.next(); | ||
String value = colorMap.get(key); | ||
} | ||
``` | ||
### JSONObject的遍历 | ||
``` | ||
String paramString = "{menu:{\"1\":\"sql\", \"2\":\"android\", \"3\":\"mvc\"}}"; | ||
JSONObject menuJSONObj = new JSONObject(paramString); | ||
JSONObject menuObj = menuJSONObj.getJSONObject("menu"); | ||
Iterator iter = menuObj.keys(); | ||
while(iter.hasNext()){ | ||
String key = (String)iter.next(); | ||
String value = menuObj.getString(key); | ||
} | ||
``` | ||
下面我们自己实现一个Iterator的集合 | ||
|
||
``` | ||
... | ||
public Iterator<Mileage> iterator() { | ||
return new ArrayIterator(); | ||
} | ||
private class ArrayIterator implements Iterator<Mileage> { | ||
/** | ||
* Number of elements remaining in this iteration | ||
*/ | ||
private int remaining = size; | ||
/** | ||
* Index of element that remove() would remove, or -1 if no such elt | ||
*/ | ||
private int removalIndex = -1; | ||
@Override | ||
public boolean hasNext() { | ||
return remaining != 0; | ||
} | ||
@Override | ||
public Mileage next() { | ||
Mileage mileage = new Mileage(); | ||
removalIndex = size-remaining; | ||
mileage.name = String.valueOf(versionCodes[removalIndex]); | ||
mileage.value = versionMileages[removalIndex]; | ||
remaining-=1; | ||
return mileage; | ||
} | ||
@Override | ||
public void remove() { | ||
versionCodes[removalIndex]=-1; | ||
versionMileages[removalIndex]="It was set null"; | ||
} | ||
} | ||
... | ||
``` | ||
使用的过程如下,我们特意使用了remove方法,注意这个只是一个示例,和大多数的集合相比,该实现并不严谨 | ||
|
||
``` | ||
AndroidMileage androidMileage = new AndroidMileage(); | ||
Iterator<AndroidMileage.Mileage> iterator =androidMileage.iterator(); | ||
while (iterator.hasNext()){ | ||
AndroidMileage.Mileage mileage = iterator.next(); | ||
if(mileage.name.equalsIgnoreCase("16")){ | ||
//remove掉的是当前的这个,暂时只是置空,并未真的移掉 | ||
iterator.remove(); | ||
} | ||
Log.e("mileage",mileage.toString()); | ||
} | ||
``` | ||
### 原理分析 | ||
一个集合想要实现Iterator很是很简单的,需要注意的是每次需要重新生成一个Iterator来进行遍历.且遍历过程是单方向的,HashMap是通过一个类似HashIterator来实现的,我们为了解释简单,这里只是研究ArrayList(此处以Android L源码为例,其他版本略有不同) | ||
|
||
``` | ||
@Override public Iterator<E> iterator() { | ||
return new ArrayListIterator(); | ||
} | ||
private class ArrayListIterator implements Iterator<E> { | ||
/** Number of elements remaining in this iteration */ | ||
private int remaining = size; | ||
/** Index of element that remove() would remove, or -1 if no such elt */ | ||
private int removalIndex = -1; | ||
/** The expected modCount value */ | ||
private int expectedModCount = modCount; | ||
public boolean hasNext() { | ||
return remaining != 0; | ||
} | ||
@SuppressWarnings("unchecked") public E next() { | ||
ArrayList<E> ourList = ArrayList.this; | ||
int rem = remaining; | ||
if (ourList.modCount != expectedModCount) { | ||
throw new ConcurrentModificationException(); | ||
} | ||
if (rem == 0) { | ||
throw new NoSuchElementException(); | ||
} | ||
remaining = rem - 1; | ||
return (E) ourList.array[removalIndex = ourList.size - rem]; | ||
} | ||
public void remove() { | ||
Object[] a = array; | ||
int removalIdx = removalIndex; | ||
if (modCount != expectedModCount) { | ||
throw new ConcurrentModificationException(); | ||
} | ||
if (removalIdx < 0) { | ||
throw new IllegalStateException(); | ||
} | ||
System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining); | ||
a[--size] = null; // Prevent memory leak | ||
removalIndex = -1; | ||
expectedModCount = ++modCount; | ||
} | ||
} | ||
``` | ||
|
||
* java中的写法一般都是通过iterator()来生成Iterator,保证iterator()每次生成新的实例 | ||
* remaining初始化使用整个list的size大小,removalIndex表示remove掉的位置,modCount在集合大小发生变化的时候后都会进行一次modCount++操作,避免数据不一致,前面我写的例子这方面没有写,请务必注意这点 | ||
* hasNext方法中,因为remaining是一个size->0的变化过程,这样只需要判断非0就可以得知当前遍历的是否还有未完成的元素 | ||
* next,第一次调用的时候返回array[0]的元素,这个过程中removalIndex会被设置成当前array的index | ||
* remove的实现是直接操作的内存中的数据,是能够直接删掉元素的,不展开了 | ||
|
||
### 题外话 | ||
如果你想写一个集合的数据结构的话,通过实现Iterator来操作集合,这样能够降低学习成本,因为你让外部代码透明的访问集合内部的数据.当然在前面的例子中,你也见到了ConcurrentModificationException这个Exception,如果你在遍历的过程中,集合发生改变,变多变少,内容变化都是算,就会抛出来这个异常. | ||
|