├── bin ├── afinal-0.2-bin.jar ├── afinal_0.5_bin.jar ├── afinal-0.2.1-bin.jar ├── afinal-0.3.1-bin.jar ├── afinal-0.3.2-bin.jar ├── afinal-0.3.3-bin.jar ├── afinal-0.3.31-bin.jar ├── afinal-0.3.32-bin.jar └── afinal_0.5.1_bin.jar ├── doc ├── afinal-0.3-doc.zip ├── afinal-0.3.1-doc.zip ├── afinal-0.3.2-doc.zip ├── afinal-0.3.3-doc.zip ├── afinal-0.3.32-doc.zip ├── afinal-0.2-change log.txt └── afinal-0.3-change log.txt ├── src_version_list └── afinal_0.5_src.zip ├── src └── net │ └── tsz │ └── afinal │ ├── db │ ├── table │ │ ├── Id.java │ │ ├── OneToMany.java │ │ ├── ManyToOne.java │ │ ├── KeyValue.java │ │ ├── Property.java │ │ └── TableInfo.java │ └── sqlite │ │ ├── SqlInfo.java │ │ ├── OneToManyLazyLoader.java │ │ ├── ManyToOneLazyLoader.java │ │ ├── DbModel.java │ │ ├── CursorUtils.java │ │ └── SqlBuilder.java │ ├── exception │ ├── HttpException.java │ ├── ViewException.java │ ├── DbException.java │ └── AfinalException.java │ ├── http │ ├── entityhandler │ │ ├── EntityCallBack.java │ │ ├── StringEntityHandler.java │ │ └── FileEntityHandler.java │ ├── AjaxCallBack.java │ ├── SyncRequestHandler.java │ ├── RetryHandler.java │ ├── MultipartEntity.java │ ├── HttpHandler.java │ ├── AjaxParams.java │ └── PreferencesCookieStore.java │ ├── bitmap │ ├── download │ │ ├── Downloader.java │ │ └── SimpleDownloader.java │ ├── core │ │ ├── IMemoryCache.java │ │ ├── BaseMemoryCacheImpl.java │ │ ├── SoftMemoryCacheImpl.java │ │ ├── BytesBufferPool.java │ │ ├── BitmapDisplayConfig.java │ │ ├── BitmapProcess.java │ │ ├── BitmapDecoder.java │ │ ├── BitmapCache.java │ │ └── LruMemoryCache.java │ └── display │ │ ├── Displayer.java │ │ └── SimpleDisplayer.java │ ├── annotation │ ├── sqlite │ │ ├── Table.java │ │ ├── Transient.java │ │ ├── ManyToOne.java │ │ ├── OneToMany.java │ │ ├── Property.java │ │ └── Id.java │ └── view │ │ ├── Select.java │ │ ├── ViewInject.java │ │ └── EventListener.java │ ├── core │ ├── FileNameGenerator.java │ ├── Queue.java │ └── AbstractCollection.java │ ├── FinalActivity.java │ └── utils │ ├── Utils.java │ ├── ClassUtils.java │ └── FieldUtils.java └── README.md /bin/afinal-0.2-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal-0.2-bin.jar -------------------------------------------------------------------------------- /bin/afinal_0.5_bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal_0.5_bin.jar -------------------------------------------------------------------------------- /doc/afinal-0.3-doc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/doc/afinal-0.3-doc.zip -------------------------------------------------------------------------------- /bin/afinal-0.2.1-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal-0.2.1-bin.jar -------------------------------------------------------------------------------- /bin/afinal-0.3.1-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal-0.3.1-bin.jar -------------------------------------------------------------------------------- /bin/afinal-0.3.2-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal-0.3.2-bin.jar -------------------------------------------------------------------------------- /bin/afinal-0.3.3-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal-0.3.3-bin.jar -------------------------------------------------------------------------------- /bin/afinal-0.3.31-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal-0.3.31-bin.jar -------------------------------------------------------------------------------- /bin/afinal-0.3.32-bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal-0.3.32-bin.jar -------------------------------------------------------------------------------- /bin/afinal_0.5.1_bin.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/bin/afinal_0.5.1_bin.jar -------------------------------------------------------------------------------- /doc/afinal-0.3.1-doc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/doc/afinal-0.3.1-doc.zip -------------------------------------------------------------------------------- /doc/afinal-0.3.2-doc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/doc/afinal-0.3.2-doc.zip -------------------------------------------------------------------------------- /doc/afinal-0.3.3-doc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/doc/afinal-0.3.3-doc.zip -------------------------------------------------------------------------------- /doc/afinal-0.3.32-doc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/doc/afinal-0.3.32-doc.zip -------------------------------------------------------------------------------- /doc/afinal-0.2-change log.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/doc/afinal-0.2-change log.txt -------------------------------------------------------------------------------- /doc/afinal-0.3-change log.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/doc/afinal-0.3-change log.txt -------------------------------------------------------------------------------- /src_version_list/afinal_0.5_src.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/afinal/HEAD/src_version_list/afinal_0.5_src.zip -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/table/Id.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.table; 17 | 18 | public class Id extends Property{ 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/exception/HttpException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.exception; 17 | 18 | public class HttpException extends AfinalException { 19 | private static final long serialVersionUID = 1L; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/entityhandler/EntityCallBack.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http.entityhandler; 17 | 18 | public interface EntityCallBack { 19 | public void callBack(long count,long current,boolean mustNoticeUI); 20 | } 21 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/download/Downloader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.download; 17 | 18 | 19 | public interface Downloader { 20 | 21 | /** 22 | * 请求网络的inputStream填充outputStream 23 | * @param urlString 24 | * @param outputStream 25 | * @return 26 | */ 27 | public byte[] download(String urlString); 28 | } 29 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/IMemoryCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import android.graphics.Bitmap; 19 | 20 | public interface IMemoryCache { 21 | 22 | public void put(String key,Bitmap bitmap); 23 | public Bitmap get(String key); 24 | public void evictAll(); 25 | public void remove(String key); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/table/OneToMany.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.table; 17 | 18 | public class OneToMany extends Property{ 19 | 20 | private Class oneClass; 21 | 22 | public Class getOneClass() { 23 | return oneClass; 24 | } 25 | 26 | public void setOneClass(Class oneClass) { 27 | this.oneClass = oneClass; 28 | } 29 | 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/table/ManyToOne.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.table; 17 | 18 | public class ManyToOne extends Property{ 19 | 20 | private Class manyClass; 21 | 22 | public Class getManyClass() { 23 | return manyClass; 24 | } 25 | 26 | public void setManyClass(Class manyClass) { 27 | this.manyClass = manyClass; 28 | } 29 | 30 | 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/sqlite/Table.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.sqlite; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | @Target(ElementType.TYPE) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | public @interface Table { 26 | public String name(); 27 | } -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/sqlite/Transient.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.sqlite; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | 24 | @Target(ElementType.FIELD) 25 | @Retention(RetentionPolicy.RUNTIME) 26 | public @interface Transient { 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/sqlite/ManyToOne.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.sqlite; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | @Target(ElementType.FIELD) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | public @interface ManyToOne { 26 | public String column() default ""; 27 | } 28 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/sqlite/OneToMany.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.sqlite; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | @Target(ElementType.FIELD) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | public @interface OneToMany { 26 | 27 | public String manyColumn(); 28 | } 29 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/view/Select.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.view; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | @Target(ElementType.FIELD) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | public @interface Select { 26 | 27 | public String selected(); 28 | public String noSelected() default ""; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/sqlite/SqlInfo.java: -------------------------------------------------------------------------------- 1 | package net.tsz.afinal.db.sqlite; 2 | 3 | import java.util.LinkedList; 4 | 5 | public class SqlInfo { 6 | 7 | private String sql; 8 | private LinkedList bindArgs; 9 | 10 | public String getSql() { 11 | return sql; 12 | } 13 | public void setSql(String sql) { 14 | this.sql = sql; 15 | } 16 | 17 | public LinkedList getBindArgs() { 18 | return bindArgs; 19 | } 20 | public void setBindArgs(LinkedList bindArgs) { 21 | this.bindArgs = bindArgs; 22 | } 23 | 24 | public Object[] getBindArgsAsArray() { 25 | if(bindArgs!=null) 26 | return bindArgs.toArray(); 27 | return null; 28 | } 29 | 30 | public String[] getBindArgsAsStringArray() { 31 | if(bindArgs!=null){ 32 | String[] strings = new String[bindArgs.size()]; 33 | for(int i = 0;i(); 44 | 45 | bindArgs.add(obj); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/exception/ViewException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.exception; 17 | 18 | 19 | public class ViewException extends AfinalException { 20 | private static final long serialVersionUID = 1L; 21 | private String strMsg = null; 22 | public ViewException(String strExce) { 23 | strMsg = strExce; 24 | } 25 | 26 | public void printStackTrace() { 27 | if(strMsg!=null) 28 | System.err.println(strMsg); 29 | 30 | super.printStackTrace(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/sqlite/Property.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.sqlite; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | @Target(ElementType.FIELD) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | public @interface Property { 26 | public String column() default ""; 27 | public String defaultValue() default ""; 28 | } 29 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/exception/DbException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.exception; 17 | 18 | public class DbException extends AfinalException { 19 | private static final long serialVersionUID = 1L; 20 | 21 | public DbException() {} 22 | 23 | 24 | public DbException(String msg) { 25 | super(msg); 26 | } 27 | 28 | public DbException(Throwable ex) { 29 | super(ex); 30 | } 31 | 32 | public DbException(String msg,Throwable ex) { 33 | super(msg,ex); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/exception/AfinalException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.exception; 17 | 18 | public class AfinalException extends RuntimeException { 19 | private static final long serialVersionUID = 1L; 20 | 21 | public AfinalException() { 22 | super(); 23 | } 24 | 25 | public AfinalException(String msg) { 26 | super(msg); 27 | } 28 | 29 | public AfinalException(Throwable ex) { 30 | super(ex); 31 | } 32 | 33 | public AfinalException(String msg,Throwable ex) { 34 | super(msg,ex); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/sqlite/OneToManyLazyLoader.java: -------------------------------------------------------------------------------- 1 | package net.tsz.afinal.db.sqlite; 2 | 3 | import net.tsz.afinal.FinalDb; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * 10 | * 一对多延迟加载类 11 | * Created by pwy on 13-7-25. 12 | * @param 宿主实体的class 13 | * @param 多放实体class 14 | */ 15 | public class OneToManyLazyLoader { 16 | O ownerEntity; 17 | Class ownerClazz; 18 | Class listItemClazz; 19 | FinalDb db; 20 | public OneToManyLazyLoader(O ownerEntity,Class ownerClazz,Class listItemclazz,FinalDb db){ 21 | this.ownerEntity = ownerEntity; 22 | this.ownerClazz = ownerClazz; 23 | this.listItemClazz = listItemclazz; 24 | this.db = db; 25 | } 26 | List entities; 27 | 28 | /** 29 | * 如果数据未加载,则调用loadOneToMany填充数据 30 | * @return 31 | */ 32 | public List getList(){ 33 | if(entities==null){ 34 | this.db.loadOneToMany((O)this.ownerEntity,this.ownerClazz,this.listItemClazz); 35 | } 36 | if(entities==null){ 37 | entities =new ArrayList(); 38 | } 39 | return entities; 40 | } 41 | public void setList(List value){ 42 | entities = value; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/sqlite/Id.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.sqlite; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | /** 23 | * @title Id主键配置 24 | * @description 不配置的时候默认找类的id或_id字段作为主键,column不配置的是默认为字段名 25 | * @author michael Young (www.YangFuhai.com) 26 | * @version 1.0 27 | * @created 2012-10-31 28 | */ 29 | @Target(ElementType.FIELD) 30 | @Retention(RetentionPolicy.RUNTIME) 31 | public @interface Id { 32 | public String column() default ""; 33 | } 34 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/view/ViewInject.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.view; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | @Target(ElementType.FIELD) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | public @interface ViewInject { 26 | public int id(); 27 | public String click() default ""; 28 | public String longClick() default ""; 29 | public String itemClick() default ""; 30 | public String itemLongClick() default ""; 31 | public Select select() default @Select(selected="") ; 32 | } 33 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/display/Displayer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.display; 17 | 18 | import net.tsz.afinal.bitmap.core.BitmapDisplayConfig; 19 | import android.graphics.Bitmap; 20 | import android.view.View; 21 | 22 | public interface Displayer { 23 | 24 | /** 25 | * 图片加载完成 回调的函数 26 | * @param imageView 27 | * @param bitmap 28 | * @param config 29 | */ 30 | public void loadCompletedisplay(View imageView,Bitmap bitmap,BitmapDisplayConfig config); 31 | 32 | /** 33 | * 图片加载失败回调的函数 34 | * @param imageView 35 | * @param bitmap 36 | */ 37 | public void loadFailDisplay(View imageView,Bitmap bitmap); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/sqlite/ManyToOneLazyLoader.java: -------------------------------------------------------------------------------- 1 | package net.tsz.afinal.db.sqlite; 2 | 3 | import net.tsz.afinal.FinalDb; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * 10 | * 一对多延迟加载类 11 | * Created by pwy on 13-7-25. 12 | * @param 宿主实体的class 13 | * @param 多放实体class 14 | */ 15 | public class ManyToOneLazyLoader { 16 | M manyEntity; 17 | Class manyClazz; 18 | Class oneClazz; 19 | FinalDb db; 20 | /** 21 | * 用于 22 | */ 23 | private Object fieldValue; 24 | public ManyToOneLazyLoader(M manyEntity, Class manyClazz, Class oneClazz, FinalDb db){ 25 | this.manyEntity = manyEntity; 26 | this.manyClazz = manyClazz; 27 | this.oneClazz = oneClazz; 28 | this.db = db; 29 | } 30 | O oneEntity; 31 | boolean hasLoaded = false; 32 | 33 | /** 34 | * 如果数据未加载,则调用loadManyToOne填充数据 35 | * @return 36 | */ 37 | public O get(){ 38 | if(oneEntity==null && !hasLoaded){ 39 | this.db.loadManyToOne(null,this.manyEntity,this.manyClazz,this.oneClazz); 40 | hasLoaded = true; 41 | } 42 | return oneEntity; 43 | } 44 | public void set(O value){ 45 | oneEntity = value; 46 | } 47 | 48 | public Object getFieldValue() { 49 | return fieldValue; 50 | } 51 | 52 | public void setFieldValue(Object fieldValue) { 53 | this.fieldValue = fieldValue; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/table/KeyValue.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.table; 17 | 18 | import net.tsz.afinal.utils.FieldUtils; 19 | 20 | public class KeyValue { 21 | private String key; 22 | private Object value; 23 | 24 | public KeyValue(String key, Object value) { 25 | this.key = key; 26 | this.value = value; 27 | } 28 | 29 | 30 | public KeyValue() {} 31 | 32 | 33 | public String getKey() { 34 | return key; 35 | } 36 | public void setKey(String key) { 37 | this.key = key; 38 | } 39 | public Object getValue() { 40 | if(value instanceof java.util.Date || value instanceof java.sql.Date){ 41 | return FieldUtils.SDF.format(value); 42 | } 43 | return value; 44 | } 45 | public void setValue(Object value) { 46 | this.value = value; 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/BaseMemoryCacheImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import net.tsz.afinal.utils.Utils; 19 | import android.graphics.Bitmap; 20 | 21 | public class BaseMemoryCacheImpl implements IMemoryCache { 22 | 23 | private final LruMemoryCache mMemoryCache; 24 | 25 | public BaseMemoryCacheImpl(int size) { 26 | mMemoryCache = new LruMemoryCache(size) { 27 | @Override 28 | protected int sizeOf(String key, Bitmap bitmap) { 29 | return Utils.getBitmapSize(bitmap); 30 | } 31 | }; 32 | } 33 | 34 | @Override 35 | public void put(String key, Bitmap bitmap) { 36 | mMemoryCache.put(key, bitmap); 37 | } 38 | 39 | @Override 40 | public Bitmap get(String key) { 41 | return mMemoryCache.get(key); 42 | } 43 | 44 | @Override 45 | public void evictAll() { 46 | mMemoryCache.evictAll(); 47 | } 48 | 49 | @Override 50 | public void remove(String key) { 51 | mMemoryCache.remove(key); 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/SoftMemoryCacheImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import java.lang.ref.SoftReference; 19 | import java.util.HashMap; 20 | 21 | import android.graphics.Bitmap; 22 | 23 | public class SoftMemoryCacheImpl implements IMemoryCache { 24 | 25 | private final HashMap> mMemoryCache; 26 | 27 | public SoftMemoryCacheImpl(int size) { 28 | 29 | mMemoryCache = new HashMap>(); 30 | } 31 | 32 | @Override 33 | public void put(String key, Bitmap bitmap) { 34 | mMemoryCache.put(key, new SoftReference(bitmap)); 35 | } 36 | 37 | @Override 38 | public Bitmap get(String key) { 39 | SoftReference memBitmap = mMemoryCache.get(key); 40 | if(memBitmap!=null){ 41 | return memBitmap.get(); 42 | } 43 | return null; 44 | } 45 | 46 | @Override 47 | public void evictAll() { 48 | mMemoryCache.clear(); 49 | } 50 | 51 | @Override 52 | public void remove(String key) { 53 | mMemoryCache.remove(key); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/sqlite/DbModel.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.sqlite; 17 | 18 | import java.util.HashMap; 19 | 20 | public class DbModel { 21 | 22 | private HashMap dataMap = new HashMap(); 23 | 24 | public Object get(String column){ 25 | return dataMap.get(column); 26 | } 27 | 28 | public String getString(String column){ 29 | return String.valueOf(get(column)); 30 | } 31 | 32 | public int getInt(String column){ 33 | return Integer.valueOf(getString(column)); 34 | } 35 | 36 | public boolean getBoolean(String column){ 37 | return Boolean.valueOf(getString(column)); 38 | } 39 | 40 | public double getDouble(String column){ 41 | return Double.valueOf(getString(column)); 42 | } 43 | 44 | public float getFloat(String column){ 45 | return Float.valueOf(getString(column)); 46 | } 47 | 48 | public long getLong(String column){ 49 | return Long.valueOf(getString(column)); 50 | } 51 | 52 | public void set(String key,Object value){ 53 | dataMap.put(key, value); 54 | } 55 | 56 | public HashMap getDataMap(){ 57 | return dataMap; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/entityhandler/StringEntityHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http.entityhandler; 17 | 18 | import java.io.ByteArrayOutputStream; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | 22 | 23 | import org.apache.http.HttpEntity; 24 | 25 | public class StringEntityHandler { 26 | 27 | public Object handleEntity(HttpEntity entity, EntityCallBack callback,String charset)throws IOException { 28 | if (entity == null) 29 | return null; 30 | 31 | ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 32 | byte[] buffer = new byte[1024]; 33 | 34 | long count = entity.getContentLength(); 35 | long curCount = 0; 36 | int len = -1; 37 | InputStream is = entity.getContent(); 38 | while ((len = is.read(buffer)) != -1) { 39 | outStream.write(buffer, 0, len); 40 | curCount += len; 41 | if(callback!=null) 42 | callback.callBack(count, curCount,false); 43 | } 44 | if(callback!=null) 45 | callback.callBack(count, curCount,true); 46 | byte[] data = outStream.toByteArray(); 47 | outStream.close(); 48 | is.close(); 49 | return new String(data,charset); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/core/FileNameGenerator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.core; 17 | 18 | import java.security.MessageDigest; 19 | import java.security.NoSuchAlgorithmException; 20 | 21 | public class FileNameGenerator { 22 | 23 | 24 | public static String generator(String key) { 25 | String cacheKey; 26 | try { 27 | final MessageDigest mDigest = MessageDigest.getInstance("MD5"); 28 | mDigest.update(key.getBytes()); 29 | cacheKey = bytesToHexString(mDigest.digest()); 30 | } catch (NoSuchAlgorithmException e) { 31 | cacheKey = String.valueOf(key.hashCode()); 32 | } 33 | return cacheKey; 34 | } 35 | 36 | private static String bytesToHexString(byte[] bytes) { 37 | // http://stackoverflow.com/questions/332079 38 | StringBuilder sb = new StringBuilder(); 39 | for (int i = 0; i < bytes.length; i++) { 40 | String hex = Integer.toHexString(0xFF & bytes[i]); 41 | if (hex.length() == 1) { 42 | sb.append('0'); 43 | } 44 | sb.append(hex); 45 | } 46 | return sb.toString(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/AjaxCallBack.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http; 17 | /** 18 | * 19 | * @author michael 20 | * 21 | * @param 目前泛型支持 String,File, 以后扩展:JSONObject,Bitmap,byte[],XmlDom 22 | */ 23 | public abstract class AjaxCallBack { 24 | 25 | private boolean progress = true; 26 | private int rate = 1000 * 1;//每秒 27 | 28 | // private Class type; 29 | // 30 | // public AjaxCallBack(Class clazz) { 31 | // this.type = clazz; 32 | // } 33 | 34 | 35 | public boolean isProgress() { 36 | return progress; 37 | } 38 | 39 | public int getRate() { 40 | return rate; 41 | } 42 | 43 | /** 44 | * 设置进度,而且只有设置了这个了以后,onLoading才能有效。 45 | * @param progress 是否启用进度显示 46 | * @param rate 进度更新频率 47 | */ 48 | public AjaxCallBack progress(boolean progress , int rate) { 49 | this.progress = progress; 50 | this.rate = rate; 51 | return this; 52 | } 53 | 54 | public void onStart(){}; 55 | /** 56 | * onLoading方法有效progress 57 | * @param count 58 | * @param current 59 | */ 60 | public void onLoading(long count,long current){}; 61 | public void onSuccess(T t){}; 62 | public void onFailure(Throwable t,int errorNo ,String strMsg){}; 63 | } 64 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/BytesBufferPool.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import java.util.ArrayList; 19 | 20 | public class BytesBufferPool { 21 | 22 | 23 | public static class BytesBuffer { 24 | public byte[] data; 25 | public int offset; 26 | public int length; 27 | 28 | private BytesBuffer(int capacity) { 29 | this.data = new byte[capacity]; 30 | } 31 | } 32 | 33 | private final int mPoolSize; 34 | private final int mBufferSize; 35 | private final ArrayList mList; 36 | 37 | public BytesBufferPool(int poolSize, int bufferSize) { 38 | mList = new ArrayList(poolSize); 39 | mPoolSize = poolSize; 40 | mBufferSize = bufferSize; 41 | } 42 | 43 | public synchronized BytesBuffer get() { 44 | int n = mList.size(); 45 | return n > 0 ? mList.remove(n - 1) : new BytesBuffer(mBufferSize); 46 | } 47 | 48 | public synchronized void recycle(BytesBuffer buffer) { 49 | if (buffer.data.length != mBufferSize) return; 50 | if (mList.size() < mPoolSize) { 51 | buffer.offset = 0; 52 | buffer.length = 0; 53 | mList.add(buffer); 54 | } 55 | } 56 | 57 | public synchronized void clear() { 58 | mList.clear(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/BitmapDisplayConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import android.graphics.Bitmap; 19 | import android.view.animation.Animation; 20 | 21 | public class BitmapDisplayConfig { 22 | 23 | 24 | private int bitmapWidth; 25 | private int bitmapHeight; 26 | 27 | private Animation animation; 28 | 29 | private int animationType; 30 | private Bitmap loadingBitmap; 31 | private Bitmap loadfailBitmap; 32 | 33 | 34 | public int getBitmapWidth() { 35 | return bitmapWidth; 36 | } 37 | 38 | public void setBitmapWidth(int bitmapWidth) { 39 | this.bitmapWidth = bitmapWidth; 40 | } 41 | 42 | public int getBitmapHeight() { 43 | return bitmapHeight; 44 | } 45 | 46 | public void setBitmapHeight(int bitmapHeight) { 47 | this.bitmapHeight = bitmapHeight; 48 | } 49 | 50 | public Animation getAnimation() { 51 | return animation; 52 | } 53 | 54 | public void setAnimation(Animation animation) { 55 | this.animation = animation; 56 | } 57 | 58 | public int getAnimationType() { 59 | return animationType; 60 | } 61 | 62 | public void setAnimationType(int animationType) { 63 | this.animationType = animationType; 64 | } 65 | 66 | public Bitmap getLoadingBitmap() { 67 | return loadingBitmap; 68 | } 69 | 70 | public void setLoadingBitmap(Bitmap loadingBitmap) { 71 | this.loadingBitmap = loadingBitmap; 72 | } 73 | 74 | public Bitmap getLoadfailBitmap() { 75 | return loadfailBitmap; 76 | } 77 | 78 | public void setLoadfailBitmap(Bitmap loadfailBitmap) { 79 | this.loadfailBitmap = loadfailBitmap; 80 | } 81 | 82 | 83 | public class AnimationType{ 84 | public static final int userDefined = 0; 85 | public static final int fadeIn = 1; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/entityhandler/FileEntityHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http.entityhandler; 17 | 18 | import java.io.File; 19 | import java.io.FileOutputStream; 20 | import java.io.IOException; 21 | import java.io.InputStream; 22 | 23 | import org.apache.http.HttpEntity; 24 | 25 | import android.text.TextUtils; 26 | 27 | public class FileEntityHandler { 28 | 29 | private boolean mStop = false; 30 | 31 | 32 | 33 | public boolean isStop() { 34 | return mStop; 35 | } 36 | 37 | 38 | 39 | public void setStop(boolean stop) { 40 | this.mStop = stop; 41 | } 42 | 43 | 44 | public Object handleEntity(HttpEntity entity, EntityCallBack callback,String target,boolean isResume) throws IOException { 45 | if (TextUtils.isEmpty(target) || target.trim().length() == 0) 46 | return null; 47 | 48 | File targetFile = new File(target); 49 | 50 | if (!targetFile.exists()) { 51 | targetFile.createNewFile(); 52 | } 53 | 54 | if(mStop){ 55 | return targetFile; 56 | } 57 | 58 | 59 | long current = 0; 60 | FileOutputStream os = null; 61 | if(isResume){ 62 | current = targetFile.length(); 63 | os = new FileOutputStream(target, true); 64 | }else{ 65 | os = new FileOutputStream(target); 66 | } 67 | 68 | if(mStop){ 69 | return targetFile; 70 | } 71 | 72 | InputStream input = entity.getContent(); 73 | long count = entity.getContentLength() + current; 74 | 75 | if(current >= count || mStop){ 76 | return targetFile; 77 | } 78 | 79 | int readLen = 0; 80 | byte[] buffer = new byte[1024]; 81 | while (!mStop && !(current >= count) && ((readLen = input.read(buffer,0,1024)) > 0) ) {//未全部读取 82 | os.write(buffer, 0, readLen); 83 | current += readLen; 84 | callback.callBack(count, current,false); 85 | } 86 | callback.callBack(count, current,true); 87 | 88 | if(mStop && current < count){ //用户主动停止 89 | throw new IOException("user stop download thread"); 90 | } 91 | 92 | return targetFile; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/BitmapProcess.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import net.tsz.afinal.bitmap.core.BytesBufferPool.BytesBuffer; 19 | import net.tsz.afinal.bitmap.download.Downloader; 20 | import android.graphics.Bitmap; 21 | import android.graphics.BitmapFactory; 22 | 23 | public class BitmapProcess { 24 | private Downloader mDownloader; 25 | private BitmapCache mCache; 26 | 27 | private static final int BYTESBUFFE_POOL_SIZE = 4; 28 | private static final int BYTESBUFFER_SIZE = 200 * 1024; 29 | private static final BytesBufferPool sMicroThumbBufferPool = new BytesBufferPool(BYTESBUFFE_POOL_SIZE, BYTESBUFFER_SIZE); 30 | 31 | public BitmapProcess(Downloader downloader,BitmapCache cache) { 32 | this.mDownloader = downloader; 33 | this.mCache = cache; 34 | } 35 | 36 | public Bitmap getBitmap(String url, BitmapDisplayConfig config) { 37 | 38 | Bitmap bitmap = getFromDisk(url,config); 39 | 40 | if(bitmap == null){ 41 | byte[] data = mDownloader.download(url); 42 | if(data != null && data.length > 0){ 43 | if(config !=null) 44 | bitmap = BitmapDecoder.decodeSampledBitmapFromByteArray(data,0,data.length,config.getBitmapWidth(),config.getBitmapHeight()); 45 | else 46 | return BitmapFactory.decodeByteArray(data,0,data.length); 47 | 48 | mCache.addToDiskCache(url, data); 49 | } 50 | } 51 | 52 | return bitmap; 53 | } 54 | 55 | 56 | public Bitmap getFromDisk(String key,BitmapDisplayConfig config) { 57 | BytesBuffer buffer = sMicroThumbBufferPool.get(); 58 | Bitmap b = null; 59 | try { 60 | boolean found = mCache.getImageData(key, buffer); 61 | if ( found && buffer.length - buffer.offset > 0) { 62 | if( config != null){ 63 | b = BitmapDecoder.decodeSampledBitmapFromByteArray(buffer.data,buffer.offset, buffer.length ,config.getBitmapWidth(),config.getBitmapHeight()); 64 | }else{ 65 | b = BitmapFactory.decodeByteArray(buffer.data, buffer.offset, buffer.length); 66 | } 67 | } 68 | } finally { 69 | sMicroThumbBufferPool.recycle(buffer); 70 | } 71 | return b; 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/display/SimpleDisplayer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.display; 17 | 18 | import net.tsz.afinal.bitmap.core.BitmapDisplayConfig; 19 | import android.graphics.Bitmap; 20 | import android.graphics.drawable.BitmapDrawable; 21 | import android.graphics.drawable.ColorDrawable; 22 | import android.graphics.drawable.Drawable; 23 | import android.graphics.drawable.TransitionDrawable; 24 | import android.view.View; 25 | import android.view.animation.Animation; 26 | import android.view.animation.AnimationUtils; 27 | import android.widget.ImageView; 28 | 29 | public class SimpleDisplayer implements Displayer{ 30 | 31 | public void loadCompletedisplay(View imageView,Bitmap bitmap,BitmapDisplayConfig config){ 32 | switch (config.getAnimationType()) { 33 | case BitmapDisplayConfig.AnimationType.fadeIn: 34 | fadeInDisplay(imageView,bitmap); 35 | break; 36 | case BitmapDisplayConfig.AnimationType.userDefined: 37 | animationDisplay(imageView,bitmap,config.getAnimation()); 38 | break; 39 | default: 40 | break; 41 | } 42 | } 43 | 44 | 45 | public void loadFailDisplay(View imageView,Bitmap bitmap){ 46 | if(imageView instanceof ImageView){ 47 | ((ImageView)imageView).setImageBitmap(bitmap); 48 | }else{ 49 | imageView.setBackgroundDrawable(new BitmapDrawable(bitmap)); 50 | } 51 | } 52 | 53 | 54 | 55 | private void fadeInDisplay(View imageView,Bitmap bitmap){ 56 | final TransitionDrawable td = 57 | new TransitionDrawable(new Drawable[] { 58 | new ColorDrawable(android.R.color.transparent), 59 | new BitmapDrawable(imageView.getResources(), bitmap) 60 | }); 61 | if(imageView instanceof ImageView){ 62 | ((ImageView)imageView).setImageDrawable(td); 63 | }else{ 64 | imageView.setBackgroundDrawable(td); 65 | } 66 | td.startTransition(300); 67 | } 68 | 69 | 70 | private void animationDisplay(View imageView,Bitmap bitmap,Animation animation){ 71 | animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 72 | if(imageView instanceof ImageView){ 73 | ((ImageView)imageView).setImageBitmap(bitmap); 74 | }else{ 75 | imageView.setBackgroundDrawable(new BitmapDrawable(bitmap)); 76 | } 77 | imageView.startAnimation(animation); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/SyncRequestHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http; 17 | 18 | import java.io.IOException; 19 | import java.net.UnknownHostException; 20 | 21 | import net.tsz.afinal.http.entityhandler.StringEntityHandler; 22 | 23 | import org.apache.http.HttpResponse; 24 | import org.apache.http.client.HttpRequestRetryHandler; 25 | import org.apache.http.client.methods.HttpUriRequest; 26 | import org.apache.http.impl.client.AbstractHttpClient; 27 | import org.apache.http.protocol.HttpContext; 28 | 29 | public class SyncRequestHandler { 30 | 31 | private final AbstractHttpClient client; 32 | private final HttpContext context; 33 | private final StringEntityHandler entityHandler = new StringEntityHandler(); 34 | 35 | private int executionCount = 0; 36 | private String charset; 37 | 38 | public SyncRequestHandler(AbstractHttpClient client, HttpContext context,String charset) { 39 | this.client = client; 40 | this.context = context; 41 | this.charset = charset; 42 | } 43 | 44 | private Object makeRequestWithRetries(HttpUriRequest request) throws IOException { 45 | 46 | boolean retry = true; 47 | IOException cause = null; 48 | HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler(); 49 | while (retry) { 50 | try { 51 | HttpResponse response = client.execute(request, context); 52 | return entityHandler.handleEntity(response.getEntity(),null,charset); 53 | } catch (UnknownHostException e) { 54 | cause = e; 55 | retry = retryHandler.retryRequest(cause, ++executionCount,context); 56 | } catch (IOException e) { 57 | cause = e; 58 | retry = retryHandler.retryRequest(cause, ++executionCount,context); 59 | } catch (NullPointerException e) { 60 | // HttpClient 4.0.x 之前的一个bug 61 | // http://code.google.com/p/android/issues/detail?id=5255 62 | cause = new IOException("NPE in HttpClient" + e.getMessage()); 63 | retry = retryHandler.retryRequest(cause, ++executionCount,context); 64 | }catch (Exception e) { 65 | cause = new IOException("Exception" + e.getMessage()); 66 | retry = retryHandler.retryRequest(cause, ++executionCount,context); 67 | } 68 | } 69 | if(cause!=null) 70 | throw cause; 71 | else 72 | throw new IOException("未知网络错误"); 73 | 74 | } 75 | 76 | public Object sendRequest (HttpUriRequest... params) { 77 | try { 78 | return makeRequestWithRetries(params[0]); 79 | } catch (IOException e) { 80 | e.printStackTrace(); 81 | } 82 | return null; 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/RetryHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http; 17 | 18 | import java.io.IOException; 19 | import java.io.InterruptedIOException; 20 | import java.net.SocketException; 21 | import java.net.UnknownHostException; 22 | import java.util.HashSet; 23 | 24 | import javax.net.ssl.SSLHandshakeException; 25 | 26 | import org.apache.http.NoHttpResponseException; 27 | import org.apache.http.client.methods.HttpUriRequest; 28 | import org.apache.http.client.HttpRequestRetryHandler; 29 | import org.apache.http.protocol.ExecutionContext; 30 | import org.apache.http.protocol.HttpContext; 31 | 32 | import android.os.SystemClock; 33 | 34 | public class RetryHandler implements HttpRequestRetryHandler { 35 | private static final int RETRY_SLEEP_TIME_MILLIS = 1000; 36 | 37 | //网络异常,继续 38 | private static HashSet> exceptionWhitelist = new HashSet>(); 39 | 40 | //用户异常,不继续(如,用户中断线程) 41 | private static HashSet> exceptionBlacklist = new HashSet>(); 42 | 43 | static { 44 | exceptionWhitelist.add(NoHttpResponseException.class); 45 | exceptionWhitelist.add(UnknownHostException.class); 46 | exceptionWhitelist.add(SocketException.class); 47 | 48 | exceptionBlacklist.add(InterruptedIOException.class); 49 | exceptionBlacklist.add(SSLHandshakeException.class); 50 | } 51 | 52 | private final int maxRetries; 53 | 54 | public RetryHandler(int maxRetries) { 55 | this.maxRetries = maxRetries; 56 | } 57 | 58 | @Override 59 | public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { 60 | boolean retry = true; 61 | 62 | Boolean b = (Boolean) context.getAttribute(ExecutionContext.HTTP_REQ_SENT); 63 | boolean sent = (b != null && b.booleanValue()); 64 | 65 | if(executionCount > maxRetries) { 66 | // 尝试次数超过用户定义的测试,默认5次 67 | retry = false; 68 | } else if (exceptionBlacklist.contains(exception.getClass())) { 69 | // 线程被用户中断,则不继续尝试 70 | retry = false; 71 | } else if (exceptionWhitelist.contains(exception.getClass())) { 72 | retry = true; 73 | } else if (!sent) { 74 | retry = true; 75 | } 76 | 77 | if(retry) { 78 | HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute( ExecutionContext.HTTP_REQUEST ); 79 | retry = currentReq!=null && !"POST".equals(currentReq.getMethod()); 80 | } 81 | 82 | if(retry) { 83 | //休眠1秒钟后再继续尝试 84 | SystemClock.sleep(RETRY_SLEEP_TIME_MILLIS); 85 | } else { 86 | exception.printStackTrace(); 87 | } 88 | 89 | return retry; 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/BitmapDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import java.io.FileDescriptor; 19 | 20 | import android.content.res.Resources; 21 | import android.graphics.Bitmap; 22 | import android.graphics.BitmapFactory; 23 | 24 | public class BitmapDecoder { 25 | private BitmapDecoder(){} 26 | 27 | public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,int reqWidth, int reqHeight) { 28 | 29 | final BitmapFactory.Options options = new BitmapFactory.Options(); 30 | options.inJustDecodeBounds = true; 31 | options.inPurgeable = true; 32 | BitmapFactory.decodeResource(res, resId, options); 33 | options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 34 | options.inJustDecodeBounds = false; 35 | try { 36 | return BitmapFactory.decodeResource(res, resId, options); 37 | } catch (OutOfMemoryError e) { 38 | e.printStackTrace(); 39 | return null; 40 | } 41 | } 42 | 43 | 44 | public static Bitmap decodeSampledBitmapFromDescriptor(FileDescriptor fileDescriptor, int reqWidth, int reqHeight) { 45 | 46 | final BitmapFactory.Options options = new BitmapFactory.Options(); 47 | options.inJustDecodeBounds = true; 48 | options.inPurgeable = true; 49 | BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options); 50 | options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 51 | options.inJustDecodeBounds = false; 52 | try { 53 | return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options); 54 | } catch (OutOfMemoryError e) { 55 | e.printStackTrace(); 56 | return null; 57 | } 58 | } 59 | 60 | 61 | public static Bitmap decodeSampledBitmapFromByteArray(byte[] data, int offset, int length, int reqWidth, int reqHeight) { 62 | final BitmapFactory.Options options = new BitmapFactory.Options(); 63 | options.inJustDecodeBounds = true; 64 | options.inPurgeable = true; 65 | BitmapFactory.decodeByteArray(data, offset, length, options); 66 | options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 67 | options.inJustDecodeBounds = false; 68 | return BitmapFactory.decodeByteArray(data, offset, length, options); 69 | } 70 | 71 | private static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) { 72 | final int height = options.outHeight; 73 | final int width = options.outWidth; 74 | int inSampleSize = 1; 75 | 76 | if (height > reqHeight || width > reqWidth) { 77 | if (width > height) { 78 | inSampleSize = Math.round((float) height / (float) reqHeight); 79 | } else { 80 | inSampleSize = Math.round((float) width / (float) reqWidth); 81 | } 82 | 83 | final float totalPixels = width * height; 84 | 85 | final float totalReqPixelsCap = reqWidth * reqHeight * 2; 86 | 87 | while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { 88 | inSampleSize++; 89 | } 90 | } 91 | return inSampleSize; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/table/Property.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.table; 17 | 18 | import java.lang.reflect.Field; 19 | import java.lang.reflect.Method; 20 | import java.util.Date; 21 | 22 | import net.tsz.afinal.utils.FieldUtils; 23 | 24 | /** 25 | * @title 属性 26 | * @description 【非主键】的【基本数据类型】 都是属性 27 | * @author michael Young (www.YangFuhai.com) 28 | * @version 1.0 29 | * @created 2012-10-10 30 | */ 31 | public class Property { 32 | 33 | private String fieldName; 34 | private String column; 35 | private String defaultValue; 36 | private Class dataType; 37 | private Field field; 38 | 39 | private Method get; 40 | private Method set; 41 | 42 | public void setValue(Object receiver , Object value){ 43 | if(set!=null && value!=null){ 44 | try { 45 | if (dataType == String.class) { 46 | set.invoke(receiver, value.toString()); 47 | } else if (dataType == int.class || dataType == Integer.class) { 48 | set.invoke(receiver, value == null ? (Integer) null : Integer.parseInt(value.toString())); 49 | } else if (dataType == float.class || dataType == Float.class) { 50 | set.invoke(receiver, value == null ? (Float) null: Float.parseFloat(value.toString())); 51 | } else if (dataType == double.class || dataType == Double.class) { 52 | set.invoke(receiver, value == null ? (Double) null: Double.parseDouble(value.toString())); 53 | } else if (dataType == long.class || dataType == Long.class) { 54 | set.invoke(receiver, value == null ? (Long) null: Long.parseLong(value.toString())); 55 | } else if (dataType == java.util.Date.class || dataType == java.sql.Date.class) { 56 | set.invoke(receiver, value == null ? (Date) null: FieldUtils.stringToDateTime(value.toString())); 57 | } else if (dataType == boolean.class || dataType == Boolean.class) { 58 | set.invoke(receiver, value == null ? (Boolean) null: "1".equals(value.toString())); 59 | } else { 60 | set.invoke(receiver, value); 61 | } 62 | } catch (Exception e) { 63 | e.printStackTrace(); 64 | } 65 | }else{ 66 | try { 67 | field.setAccessible(true); 68 | field.set(receiver, value); 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | } 74 | 75 | /** 76 | * 获取某个实体执行某个方法的结果 77 | * @param obj 78 | * @param method 79 | * @return 80 | */ 81 | @SuppressWarnings("unchecked") 82 | public T getValue(Object obj){ 83 | if(obj != null && get != null) { 84 | try { 85 | return (T)get.invoke(obj); 86 | } catch (Exception e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | return null; 91 | } 92 | 93 | 94 | public String getFieldName() { 95 | return fieldName; 96 | } 97 | public void setFieldName(String fieldName) { 98 | this.fieldName = fieldName; 99 | } 100 | public String getColumn() { 101 | return column; 102 | } 103 | public void setColumn(String column) { 104 | this.column = column; 105 | } 106 | public String getDefaultValue() { 107 | return defaultValue; 108 | } 109 | public void setDefaultValue(String defaultValue) { 110 | this.defaultValue = defaultValue; 111 | } 112 | public Class getDataType() { 113 | return dataType; 114 | } 115 | public void setDataType(Class dataType) { 116 | this.dataType = dataType; 117 | } 118 | public Method getGet() { 119 | return get; 120 | } 121 | public void setGet(Method get) { 122 | this.get = get; 123 | } 124 | public Method getSet() { 125 | return set; 126 | } 127 | public void setSet(Method set) { 128 | this.set = set; 129 | } 130 | 131 | public Field getField() { 132 | return field; 133 | } 134 | 135 | public void setField(Field field) { 136 | this.field = field; 137 | } 138 | 139 | 140 | } 141 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/table/TableInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.table; 17 | 18 | import java.lang.reflect.Field; 19 | import java.util.HashMap; 20 | import java.util.List; 21 | import net.tsz.afinal.exception.DbException; 22 | import net.tsz.afinal.utils.ClassUtils; 23 | import net.tsz.afinal.utils.FieldUtils; 24 | 25 | 26 | public class TableInfo { 27 | 28 | private String className; 29 | private String tableName; 30 | 31 | private Id id; 32 | 33 | public final HashMap propertyMap = new HashMap(); 34 | public final HashMap oneToManyMap = new HashMap(); 35 | public final HashMap manyToOneMap = new HashMap(); 36 | 37 | private boolean checkDatabese;//在对实体进行数据库操作的时候查询是否已经有表了,只需查询一遍,用此标示 38 | 39 | 40 | private static final HashMap tableInfoMap = new HashMap(); 41 | 42 | private TableInfo(){} 43 | 44 | @SuppressWarnings("unused") 45 | public static TableInfo get(Class clazz){ 46 | if(clazz == null) 47 | throw new DbException("table info get error,because the clazz is null"); 48 | 49 | TableInfo tableInfo = tableInfoMap.get(clazz.getName()); 50 | if( tableInfo == null ){ 51 | tableInfo = new TableInfo(); 52 | 53 | tableInfo.setTableName(ClassUtils.getTableName(clazz)); 54 | tableInfo.setClassName(clazz.getName()); 55 | 56 | Field idField = ClassUtils.getPrimaryKeyField(clazz); 57 | if(idField != null){ 58 | Id id = new Id(); 59 | id.setColumn(FieldUtils.getColumnByField(idField)); 60 | id.setFieldName(idField.getName()); 61 | id.setSet(FieldUtils.getFieldSetMethod(clazz, idField)); 62 | id.setGet(FieldUtils.getFieldGetMethod(clazz, idField)); 63 | id.setDataType(idField.getType()); 64 | 65 | tableInfo.setId(id); 66 | }else{ 67 | throw new DbException("the class["+clazz+"]'s idField is null , \n you can define _id,id property or use annotation @id to solution this exception"); 68 | } 69 | 70 | List pList = ClassUtils.getPropertyList(clazz); 71 | if(pList!=null){ 72 | for(Property p : pList){ 73 | if(p!=null) 74 | tableInfo.propertyMap.put(p.getColumn(), p); 75 | } 76 | } 77 | 78 | List mList = ClassUtils.getManyToOneList(clazz); 79 | if(mList!=null){ 80 | for(ManyToOne m : mList){ 81 | if(m!=null) 82 | tableInfo.manyToOneMap.put(m.getColumn(), m); 83 | } 84 | } 85 | 86 | List oList = ClassUtils.getOneToManyList(clazz); 87 | if(oList!=null){ 88 | for(OneToMany o : oList){ 89 | if(o!=null) 90 | tableInfo.oneToManyMap.put(o.getColumn(), o); 91 | } 92 | } 93 | 94 | 95 | tableInfoMap.put(clazz.getName(), tableInfo); 96 | } 97 | 98 | if(tableInfo == null ) 99 | throw new DbException("the class["+clazz+"]'s table is null"); 100 | 101 | return tableInfo; 102 | } 103 | 104 | 105 | public static TableInfo get(String className){ 106 | try { 107 | return get(Class.forName(className)); 108 | } catch (ClassNotFoundException e) { 109 | e.printStackTrace(); 110 | } 111 | return null; 112 | } 113 | 114 | 115 | public String getClassName() { 116 | return className; 117 | } 118 | 119 | public void setClassName(String className) { 120 | this.className = className; 121 | } 122 | 123 | public String getTableName() { 124 | return tableName; 125 | } 126 | 127 | public void setTableName(String tableName) { 128 | this.tableName = tableName; 129 | } 130 | 131 | public Id getId() { 132 | return id; 133 | } 134 | 135 | public void setId(Id id) { 136 | this.id = id; 137 | } 138 | 139 | public boolean isCheckDatabese() { 140 | return checkDatabese; 141 | } 142 | 143 | public void setCheckDatabese(boolean checkDatabese) { 144 | this.checkDatabese = checkDatabese; 145 | } 146 | 147 | 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/sqlite/CursorUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.sqlite; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map.Entry; 20 | 21 | import net.tsz.afinal.FinalDb; 22 | import net.tsz.afinal.db.table.ManyToOne; 23 | import net.tsz.afinal.db.table.OneToMany; 24 | import net.tsz.afinal.db.table.Property; 25 | import net.tsz.afinal.db.table.TableInfo; 26 | 27 | 28 | import android.database.Cursor; 29 | 30 | public class CursorUtils { 31 | 32 | public static T getEntity(Cursor cursor, Class clazz,FinalDb db){ 33 | try { 34 | if(cursor!=null ){ 35 | TableInfo table = TableInfo.get(clazz); 36 | int columnCount = cursor.getColumnCount(); 37 | if(columnCount>0){ 38 | T entity = (T) clazz.newInstance(); 39 | for(int i=0;i 0){ 86 | DbModel model = new DbModel(); 87 | int columnCount = cursor.getColumnCount(); 88 | for(int i=0;i T dbModel2Entity(DbModel dbModel,Class clazz){ 98 | if(dbModel!=null){ 99 | HashMap dataMap = dbModel.getDataMap(); 100 | try { 101 | @SuppressWarnings("unchecked") 102 | T entity = (T) clazz.newInstance(); 103 | for(Entry entry : dataMap.entrySet()){ 104 | String column = entry.getKey(); 105 | TableInfo table = TableInfo.get(clazz); 106 | Property property = table.propertyMap.get(column); 107 | if(property!=null){ 108 | property.setValue(entity, entry.getValue()==null?null:entry.getValue().toString()); 109 | }else{ 110 | if(table.getId().getColumn().equals(column)){ 111 | table.getId().setValue(entity, entry.getValue()==null?null:entry.getValue().toString()); 112 | } 113 | } 114 | 115 | } 116 | return entity; 117 | } catch (Exception e) { 118 | e.printStackTrace(); 119 | } 120 | } 121 | 122 | return null; 123 | } 124 | 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/FinalActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal; 17 | 18 | import java.lang.reflect.Field; 19 | 20 | import net.tsz.afinal.annotation.view.EventListener; 21 | import net.tsz.afinal.annotation.view.Select; 22 | import net.tsz.afinal.annotation.view.ViewInject; 23 | import android.app.Activity; 24 | import android.text.TextUtils; 25 | import android.view.View; 26 | import android.view.ViewGroup.LayoutParams; 27 | import android.widget.AbsListView; 28 | 29 | public abstract class FinalActivity extends Activity { 30 | 31 | 32 | public void setContentView(int layoutResID) { 33 | super.setContentView(layoutResID); 34 | initInjectedView(this); 35 | } 36 | 37 | 38 | public void setContentView(View view, LayoutParams params) { 39 | super.setContentView(view, params); 40 | initInjectedView(this); 41 | } 42 | 43 | 44 | public void setContentView(View view) { 45 | super.setContentView(view); 46 | initInjectedView(this); 47 | } 48 | 49 | 50 | public static void initInjectedView(Activity activity){ 51 | initInjectedView(activity, activity.getWindow().getDecorView()); 52 | } 53 | 54 | 55 | public static void initInjectedView(Object injectedSource,View sourceView){ 56 | Field[] fields = injectedSource.getClass().getDeclaredFields(); 57 | if(fields!=null && fields.length>0){ 58 | for(Field field : fields){ 59 | try { 60 | field.setAccessible(true); 61 | 62 | if(field.get(injectedSource)!= null ) 63 | continue; 64 | 65 | ViewInject viewInject = field.getAnnotation(ViewInject.class); 66 | if(viewInject!=null){ 67 | 68 | int viewId = viewInject.id(); 69 | field.set(injectedSource,sourceView.findViewById(viewId)); 70 | 71 | setListener(injectedSource,field,viewInject.click(),Method.Click); 72 | setListener(injectedSource,field,viewInject.longClick(),Method.LongClick); 73 | setListener(injectedSource,field,viewInject.itemClick(),Method.ItemClick); 74 | setListener(injectedSource,field,viewInject.itemLongClick(),Method.itemLongClick); 75 | 76 | Select select = viewInject.select(); 77 | if(!TextUtils.isEmpty(select.selected())){ 78 | setViewSelectListener(injectedSource,field,select.selected(),select.noSelected()); 79 | } 80 | 81 | } 82 | } catch (Exception e) { 83 | e.printStackTrace(); 84 | } 85 | } 86 | } 87 | } 88 | 89 | 90 | private static void setViewSelectListener(Object injectedSource,Field field,String select,String noSelect)throws Exception{ 91 | Object obj = field.get(injectedSource); 92 | if(obj instanceof View){ 93 | ((AbsListView)obj).setOnItemSelectedListener(new EventListener(injectedSource).select(select).noSelect(noSelect)); 94 | } 95 | } 96 | 97 | 98 | private static void setListener(Object injectedSource,Field field,String methodName,Method method)throws Exception{ 99 | if(methodName == null || methodName.trim().length() == 0) 100 | return; 101 | 102 | Object obj = field.get(injectedSource); 103 | 104 | switch (method) { 105 | case Click: 106 | if(obj instanceof View){ 107 | ((View)obj).setOnClickListener(new EventListener(injectedSource).click(methodName)); 108 | } 109 | break; 110 | case ItemClick: 111 | if(obj instanceof AbsListView){ 112 | ((AbsListView)obj).setOnItemClickListener(new EventListener(injectedSource).itemClick(methodName)); 113 | } 114 | break; 115 | case LongClick: 116 | if(obj instanceof View){ 117 | ((View)obj).setOnLongClickListener(new EventListener(injectedSource).longClick(methodName)); 118 | } 119 | break; 120 | case itemLongClick: 121 | if(obj instanceof AbsListView){ 122 | ((AbsListView)obj).setOnItemLongClickListener(new EventListener(injectedSource).itemLongClick(methodName)); 123 | } 124 | break; 125 | default: 126 | break; 127 | } 128 | } 129 | 130 | public enum Method{ 131 | Click,LongClick,ItemClick,itemLongClick 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/download/SimpleDownloader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.download; 17 | 18 | import java.io.BufferedInputStream; 19 | import java.io.BufferedOutputStream; 20 | import java.io.ByteArrayOutputStream; 21 | import java.io.File; 22 | import java.io.FileInputStream; 23 | import java.io.FilterInputStream; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.net.HttpURLConnection; 27 | import java.net.URI; 28 | import java.net.URISyntaxException; 29 | import java.net.URL; 30 | 31 | import android.util.Log; 32 | 33 | /** 34 | * @title 根据 图片url地址下载图片 可以是本地和网络 35 | * @author 杨福海(michael) www.yangfuhai.com 36 | */ 37 | public class SimpleDownloader implements Downloader { 38 | 39 | private static final String TAG = SimpleDownloader.class.getSimpleName(); 40 | private static final int IO_BUFFER_SIZE = 8 * 1024; // 8k 41 | 42 | public byte[] download (String urlString){ 43 | if (urlString == null) 44 | return null; 45 | 46 | if (urlString.trim().toLowerCase().startsWith("http")) { 47 | return getFromHttp(urlString); 48 | }else if(urlString.trim().toLowerCase().startsWith("file:")){ 49 | try { 50 | File f = new File(new URI(urlString)); 51 | if (f.exists() && f.canRead()) { 52 | return getFromFile(f); 53 | } 54 | } catch (URISyntaxException e) { 55 | Log.e(TAG, "Error in read from file - " + urlString + " : " + e); 56 | } 57 | }else{ 58 | File f = new File(urlString); 59 | if (f.exists() && f.canRead()) { 60 | return getFromFile(f); 61 | } 62 | } 63 | 64 | return null; 65 | } 66 | 67 | private byte[] getFromFile(File file) { 68 | if(file == null) return null; 69 | 70 | FileInputStream fis = null; 71 | try { 72 | fis = new FileInputStream(file); 73 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 74 | int len = 0; 75 | byte[] buffer = new byte[1024]; 76 | while ((len = fis.read(buffer)) != -1) { 77 | baos.write(buffer, 0, len); 78 | } 79 | return baos.toByteArray(); 80 | } catch (Exception e) { 81 | Log.e(TAG, "Error in read from file - " + file + " : " + e); 82 | } finally { 83 | if (fis != null) { 84 | try { 85 | fis.close(); 86 | fis = null; 87 | } catch (IOException e) { 88 | // do nothing 89 | } 90 | } 91 | } 92 | 93 | return null; 94 | } 95 | 96 | private byte[] getFromHttp(String urlString) { 97 | HttpURLConnection urlConnection = null; 98 | BufferedOutputStream out = null; 99 | FlushedInputStream in = null; 100 | 101 | try { 102 | final URL url = new URL(urlString); 103 | urlConnection = (HttpURLConnection) url.openConnection(); 104 | in = new FlushedInputStream(new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE)); 105 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 106 | int b; 107 | while ((b = in.read()) != -1) { 108 | baos.write(b); 109 | } 110 | return baos.toByteArray(); 111 | } catch (final IOException e) { 112 | Log.e(TAG, "Error in downloadBitmap - " + urlString + " : " + e); 113 | } finally { 114 | if (urlConnection != null) { 115 | urlConnection.disconnect(); 116 | } 117 | try { 118 | if (out != null) { 119 | out.close(); 120 | } 121 | if (in != null) { 122 | in.close(); 123 | } 124 | } catch (final IOException e) { 125 | } 126 | } 127 | return null; 128 | } 129 | 130 | 131 | public class FlushedInputStream extends FilterInputStream { 132 | public FlushedInputStream(InputStream inputStream) { 133 | super(inputStream); 134 | } 135 | 136 | @Override 137 | public long skip(long n) throws IOException { 138 | long totalBytesSkipped = 0L; 139 | while (totalBytesSkipped < n) { 140 | long bytesSkipped = in.skip(n - totalBytesSkipped); 141 | if (bytesSkipped == 0L) { 142 | int by_te = read(); 143 | if (by_te < 0) { 144 | break; // we reached EOF 145 | } else { 146 | bytesSkipped = 1; // we read one byte 147 | } 148 | } 149 | totalBytesSkipped += bytesSkipped; 150 | } 151 | return totalBytesSkipped; 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/utils/Utils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.utils; 17 | 18 | import java.io.File; 19 | 20 | import android.content.Context; 21 | import android.graphics.Bitmap; 22 | import android.os.Environment; 23 | import android.os.StatFs; 24 | import android.util.Log; 25 | 26 | public class Utils { 27 | 28 | private static final String TAG = "BitmapCommonUtils"; 29 | private static final long POLY64REV = 0x95AC9329AC4BC9B5L; 30 | private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL; 31 | 32 | private static long[] sCrcTable = new long[256]; 33 | /** 34 | * 获取可以使用的缓存目录 35 | * @param context 36 | * @param uniqueName 目录名称 37 | * @return 38 | */ 39 | public static File getDiskCacheDir(Context context, String uniqueName) { 40 | final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ? 41 | getExternalCacheDir(context).getPath() : context.getCacheDir().getPath(); 42 | 43 | return new File(cachePath + File.separator + uniqueName); 44 | } 45 | 46 | 47 | 48 | /** 49 | * 获取bitmap的字节大小 50 | * @param bitmap 51 | * @return 52 | */ 53 | public static int getBitmapSize(Bitmap bitmap) { 54 | return bitmap.getRowBytes() * bitmap.getHeight(); 55 | } 56 | 57 | 58 | /** 59 | * 获取程序外部的缓存目录 60 | * @param context 61 | * @return 62 | */ 63 | public static File getExternalCacheDir(Context context) { 64 | final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/"; 65 | return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir); 66 | } 67 | 68 | /** 69 | * 获取文件路径空间大小 70 | * @param path 71 | * @return 72 | */ 73 | public static long getUsableSpace(File path) { 74 | try{ 75 | final StatFs stats = new StatFs(path.getPath()); 76 | return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks(); 77 | }catch (Exception e) { 78 | Log.e(TAG, "获取 sdcard 缓存大小 出错,请查看AndroidManifest.xml 是否添加了sdcard的访问权限"); 79 | e.printStackTrace(); 80 | return -1; 81 | } 82 | 83 | } 84 | 85 | 86 | public static byte[] getBytes(String in) { 87 | byte[] result = new byte[in.length() * 2]; 88 | int output = 0; 89 | for (char ch : in.toCharArray()) { 90 | result[output++] = (byte) (ch & 0xFF); 91 | result[output++] = (byte) (ch >> 8); 92 | } 93 | return result; 94 | } 95 | 96 | public static boolean isSameKey(byte[] key, byte[] buffer) { 97 | int n = key.length; 98 | if (buffer.length < n) { 99 | return false; 100 | } 101 | for (int i = 0; i < n; ++i) { 102 | if (key[i] != buffer[i]) { 103 | return false; 104 | } 105 | } 106 | return true; 107 | } 108 | 109 | public static byte[] copyOfRange(byte[] original, int from, int to) { 110 | int newLength = to - from; 111 | if (newLength < 0) 112 | throw new IllegalArgumentException(from + " > " + to); 113 | byte[] copy = new byte[newLength]; 114 | System.arraycopy(original, from, copy, 0,Math.min(original.length - from, newLength)); 115 | return copy; 116 | } 117 | 118 | 119 | 120 | static { 121 | //参考 http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c 122 | long part; 123 | for (int i = 0; i < 256; i++) { 124 | part = i; 125 | for (int j = 0; j < 8; j++) { 126 | long x = ((int) part & 1) != 0 ? POLY64REV : 0; 127 | part = (part >> 1) ^ x; 128 | } 129 | sCrcTable[i] = part; 130 | } 131 | } 132 | 133 | public static byte[] makeKey(String httpUrl) { 134 | return getBytes(httpUrl); 135 | } 136 | 137 | /** 138 | * A function thats returns a 64-bit crc for string 139 | * 140 | * @param in input string 141 | * @return a 64-bit crc value 142 | */ 143 | public static final long crc64Long(String in) { 144 | if (in == null || in.length() == 0) { 145 | return 0; 146 | } 147 | return crc64Long(getBytes(in)); 148 | } 149 | 150 | public static final long crc64Long(byte[] buffer) { 151 | long crc = INITIALCRC; 152 | for (int k = 0, n = buffer.length; k < n; ++k) { 153 | crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8); 154 | } 155 | return crc; 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/MultipartEntity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http; 17 | 18 | import java.io.ByteArrayInputStream; 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileNotFoundException; 23 | import java.io.InputStream; 24 | import java.io.IOException; 25 | import java.io.OutputStream; 26 | import java.util.Random; 27 | 28 | import org.apache.http.Header; 29 | import org.apache.http.HttpEntity; 30 | import org.apache.http.message.BasicHeader; 31 | 32 | /** 33 | * 参考 http://blog.rafaelsanches.com/2011/01/29/upload-using-multipart-post- 34 | * using-httpclient-in-android/ 拿来主义... :) 35 | * @author michael yang (www.yangfuhai.com) 36 | */ 37 | class MultipartEntity implements HttpEntity { 38 | 39 | private final static char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); 40 | 41 | private String boundary = null; 42 | 43 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 44 | boolean isSetLast = false; 45 | boolean isSetFirst = false; 46 | 47 | public MultipartEntity() { 48 | final StringBuffer buf = new StringBuffer(); 49 | final Random rand = new Random(); 50 | for (int i = 0; i < 30; i++) { 51 | buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]); 52 | } 53 | this.boundary = buf.toString(); 54 | 55 | } 56 | 57 | public void writeFirstBoundaryIfNeeds(){ 58 | if(!isSetFirst){ 59 | try { 60 | out.write(("--" + boundary + "\r\n").getBytes()); 61 | } catch (final IOException e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | 66 | isSetFirst = true; 67 | } 68 | 69 | public void writeLastBoundaryIfNeeds() { 70 | if(isSetLast){ 71 | return; 72 | } 73 | 74 | try { 75 | out.write(("\r\n--" + boundary + "--\r\n").getBytes()); 76 | } catch (final IOException e) { 77 | e.printStackTrace(); 78 | } 79 | 80 | isSetLast = true; 81 | } 82 | 83 | public void addPart(final String key, final String value) { 84 | writeFirstBoundaryIfNeeds(); 85 | try { 86 | out.write(("Content-Disposition: form-data; name=\"" +key+"\"\r\n\r\n").getBytes()); 87 | out.write(value.getBytes()); 88 | out.write(("\r\n--" + boundary + "\r\n").getBytes()); 89 | } catch (final IOException e) { 90 | e.printStackTrace(); 91 | } 92 | } 93 | 94 | public void addPart(final String key, final String fileName, final InputStream fin, final boolean isLast){ 95 | addPart(key, fileName, fin, "application/octet-stream", isLast); 96 | } 97 | 98 | public void addPart(final String key, final String fileName, final InputStream fin, String type, final boolean isLast){ 99 | writeFirstBoundaryIfNeeds(); 100 | try { 101 | type = "Content-Type: "+type+"\r\n"; 102 | out.write(("Content-Disposition: form-data; name=\""+ key+"\"; filename=\"" + fileName + "\"\r\n").getBytes()); 103 | out.write(type.getBytes()); 104 | out.write("Content-Transfer-Encoding: binary\r\n\r\n".getBytes()); 105 | 106 | final byte[] tmp = new byte[4096]; 107 | int l = 0; 108 | while ((l = fin.read(tmp)) != -1) { 109 | out.write(tmp, 0, l); 110 | } 111 | if(!isLast) 112 | out.write(("\r\n--" + boundary + "\r\n").getBytes()); 113 | out.flush(); 114 | } catch (final IOException e) { 115 | e.printStackTrace(); 116 | } finally { 117 | try { 118 | fin.close(); 119 | } catch (final IOException e) { 120 | e.printStackTrace(); 121 | } 122 | } 123 | } 124 | 125 | public void addPart(final String key, final File value, final boolean isLast) { 126 | try { 127 | addPart(key, value.getName(), new FileInputStream(value), isLast); 128 | } catch (final FileNotFoundException e) { 129 | e.printStackTrace(); 130 | } 131 | } 132 | 133 | @Override 134 | public long getContentLength() { 135 | writeLastBoundaryIfNeeds(); 136 | return out.toByteArray().length; 137 | } 138 | 139 | @Override 140 | public Header getContentType() { 141 | return new BasicHeader("Content-Type", "multipart/form-data; boundary=" + boundary); 142 | } 143 | 144 | @Override 145 | public boolean isChunked() { 146 | return false; 147 | } 148 | 149 | @Override 150 | public boolean isRepeatable() { 151 | return false; 152 | } 153 | 154 | @Override 155 | public boolean isStreaming() { 156 | return false; 157 | } 158 | 159 | @Override 160 | public void writeTo(final OutputStream outstream) throws IOException { 161 | outstream.write(out.toByteArray()); 162 | } 163 | 164 | @Override 165 | public Header getContentEncoding() { 166 | return null; 167 | } 168 | 169 | @Override 170 | public void consumeContent() throws IOException, 171 | UnsupportedOperationException { 172 | if (isStreaming()) { 173 | throw new UnsupportedOperationException( 174 | "Streaming entity does not implement #consumeContent()"); 175 | } 176 | } 177 | 178 | @Override 179 | public InputStream getContent() throws IOException, 180 | UnsupportedOperationException { 181 | return new ByteArrayInputStream(out.toByteArray()); 182 | } 183 | } -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/HttpHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.net.UnknownHostException; 21 | 22 | import net.tsz.afinal.core.AsyncTask; 23 | import net.tsz.afinal.http.entityhandler.EntityCallBack; 24 | import net.tsz.afinal.http.entityhandler.FileEntityHandler; 25 | import net.tsz.afinal.http.entityhandler.StringEntityHandler; 26 | 27 | import org.apache.http.HttpEntity; 28 | import org.apache.http.HttpResponse; 29 | import org.apache.http.StatusLine; 30 | import org.apache.http.client.HttpRequestRetryHandler; 31 | import org.apache.http.client.HttpResponseException; 32 | import org.apache.http.client.methods.HttpUriRequest; 33 | import org.apache.http.impl.client.AbstractHttpClient; 34 | import org.apache.http.protocol.HttpContext; 35 | 36 | import android.os.SystemClock; 37 | 38 | 39 | public class HttpHandler extends AsyncTask implements EntityCallBack{ 40 | 41 | private final AbstractHttpClient client; 42 | private final HttpContext context; 43 | 44 | private final StringEntityHandler mStrEntityHandler = new StringEntityHandler(); 45 | private final FileEntityHandler mFileEntityHandler = new FileEntityHandler(); 46 | 47 | private final AjaxCallBack callback; 48 | 49 | private int executionCount = 0; 50 | private String targetUrl = null; //下载的路径 51 | private boolean isResume = false; //是否断点续传 52 | private String charset; 53 | 54 | public HttpHandler(AbstractHttpClient client, HttpContext context, AjaxCallBack callback,String charset) { 55 | this.client = client; 56 | this.context = context; 57 | this.callback = callback; 58 | this.charset = charset; 59 | } 60 | 61 | 62 | private void makeRequestWithRetries(HttpUriRequest request) throws IOException { 63 | if(isResume && targetUrl!= null){ 64 | File downloadFile = new File(targetUrl); 65 | long fileLen = 0; 66 | if(downloadFile.isFile() && downloadFile.exists()){ 67 | fileLen = downloadFile.length(); 68 | } 69 | if(fileLen > 0) 70 | request.setHeader("RANGE", "bytes="+fileLen+"-"); 71 | } 72 | 73 | boolean retry = true; 74 | IOException cause = null; 75 | HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler(); 76 | while (retry) { 77 | try { 78 | if (!isCancelled()) { 79 | HttpResponse response = client.execute(request, context); 80 | if (!isCancelled()) { 81 | handleResponse(response); 82 | } 83 | } 84 | return; 85 | } catch (UnknownHostException e) { 86 | publishProgress(UPDATE_FAILURE,e,0,"unknownHostException:can't resolve host"); 87 | return; 88 | } catch (IOException e) { 89 | cause = e; 90 | retry = retryHandler.retryRequest(cause, ++executionCount,context); 91 | } catch (NullPointerException e) { 92 | // HttpClient 4.0.x 之前的一个bug 93 | // http://code.google.com/p/android/issues/detail?id=5255 94 | cause = new IOException("NPE in HttpClient" + e.getMessage()); 95 | retry = retryHandler.retryRequest(cause, ++executionCount,context); 96 | }catch (Exception e) { 97 | cause = new IOException("Exception" + e.getMessage()); 98 | retry = retryHandler.retryRequest(cause, ++executionCount,context); 99 | } 100 | } 101 | if(cause!=null) 102 | throw cause; 103 | else 104 | throw new IOException("未知网络错误"); 105 | } 106 | 107 | @Override 108 | protected Object doInBackground(Object... params) { 109 | if(params!=null && params.length == 3){ 110 | targetUrl = String.valueOf(params[1]); 111 | isResume = (Boolean) params[2]; 112 | } 113 | try { 114 | publishProgress(UPDATE_START); // 开始 115 | makeRequestWithRetries((HttpUriRequest)params[0]); 116 | 117 | } catch (IOException e) { 118 | publishProgress(UPDATE_FAILURE,e,0,e.getMessage()); // 结束 119 | } 120 | 121 | return null; 122 | } 123 | 124 | private final static int UPDATE_START = 1; 125 | private final static int UPDATE_LOADING = 2; 126 | private final static int UPDATE_FAILURE = 3; 127 | private final static int UPDATE_SUCCESS = 4; 128 | 129 | @SuppressWarnings("unchecked") 130 | @Override 131 | protected void onProgressUpdate(Object... values) { 132 | int update = Integer.valueOf(String.valueOf(values[0])); 133 | switch (update) { 134 | case UPDATE_START: 135 | if(callback!=null) 136 | callback.onStart(); 137 | break; 138 | case UPDATE_LOADING: 139 | if(callback!=null) 140 | callback.onLoading(Long.valueOf(String.valueOf(values[1])),Long.valueOf(String.valueOf(values[2]))); 141 | break; 142 | case UPDATE_FAILURE: 143 | if(callback!=null) 144 | callback.onFailure((Throwable)values[1],(Integer)values[2],(String)values[3]); 145 | break; 146 | case UPDATE_SUCCESS: 147 | if(callback!=null) 148 | callback.onSuccess((T)values[1]); 149 | break; 150 | default: 151 | break; 152 | } 153 | super.onProgressUpdate(values); 154 | } 155 | 156 | public boolean isStop() { 157 | return mFileEntityHandler.isStop(); 158 | } 159 | 160 | 161 | /** 162 | * @param stop 停止下载任务 163 | */ 164 | public void stop() { 165 | mFileEntityHandler.setStop(true); 166 | } 167 | 168 | private void handleResponse(HttpResponse response) { 169 | StatusLine status = response.getStatusLine(); 170 | if (status.getStatusCode() >= 300) { 171 | String errorMsg = "response status error code:"+status.getStatusCode(); 172 | if(status.getStatusCode() == 416 && isResume){ 173 | errorMsg += " \n maybe you have download complete."; 174 | } 175 | publishProgress(UPDATE_FAILURE,new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()),status.getStatusCode() ,errorMsg); 176 | } else { 177 | try { 178 | HttpEntity entity = response.getEntity(); 179 | Object responseBody = null; 180 | if (entity != null) { 181 | time = SystemClock.uptimeMillis(); 182 | if(targetUrl!=null){ 183 | responseBody = mFileEntityHandler.handleEntity(entity,this,targetUrl,isResume); 184 | } 185 | else{ 186 | responseBody = mStrEntityHandler.handleEntity(entity,this,charset); 187 | } 188 | 189 | } 190 | publishProgress(UPDATE_SUCCESS,responseBody); 191 | 192 | } catch (IOException e) { 193 | publishProgress(UPDATE_FAILURE,e,0,e.getMessage()); 194 | } 195 | 196 | } 197 | } 198 | 199 | 200 | private long time; 201 | @Override 202 | public void callBack(long count, long current,boolean mustNoticeUI) { 203 | if(callback!=null && callback.isProgress()){ 204 | if(mustNoticeUI){ 205 | publishProgress(UPDATE_LOADING,count,current); 206 | }else{ 207 | long thisTime = SystemClock.uptimeMillis(); 208 | if(thisTime - time >= callback.getRate()){ 209 | time = thisTime ; 210 | publishProgress(UPDATE_LOADING,count,current); 211 | } 212 | } 213 | } 214 | } 215 | 216 | 217 | } 218 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/annotation/view/EventListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.annotation.view; 17 | 18 | import java.lang.reflect.Method; 19 | 20 | import net.tsz.afinal.exception.ViewException; 21 | 22 | import android.view.View; 23 | import android.view.View.OnClickListener; 24 | import android.view.View.OnLongClickListener; 25 | import android.widget.AdapterView; 26 | import android.widget.AdapterView.OnItemClickListener; 27 | import android.widget.AdapterView.OnItemLongClickListener; 28 | import android.widget.AdapterView.OnItemSelectedListener; 29 | 30 | public class EventListener implements OnClickListener, OnLongClickListener, OnItemClickListener, OnItemSelectedListener,OnItemLongClickListener { 31 | 32 | private Object handler; 33 | 34 | private String clickMethod; 35 | private String longClickMethod; 36 | private String itemClickMethod; 37 | private String itemSelectMethod; 38 | private String nothingSelectedMethod; 39 | private String itemLongClickMehtod; 40 | 41 | public EventListener(Object handler) { 42 | this.handler = handler; 43 | } 44 | 45 | public EventListener click(String method){ 46 | this.clickMethod = method; 47 | return this; 48 | } 49 | 50 | public EventListener longClick(String method){ 51 | this.longClickMethod = method; 52 | return this; 53 | } 54 | 55 | public EventListener itemLongClick(String method){ 56 | this.itemLongClickMehtod = method; 57 | return this; 58 | } 59 | 60 | public EventListener itemClick(String method){ 61 | this.itemClickMethod = method; 62 | return this; 63 | } 64 | 65 | public EventListener select(String method){ 66 | this.itemSelectMethod = method; 67 | return this; 68 | } 69 | 70 | public EventListener noSelect(String method){ 71 | this.nothingSelectedMethod = method; 72 | return this; 73 | } 74 | 75 | public boolean onLongClick(View v) { 76 | return invokeLongClickMethod(handler,longClickMethod,v); 77 | } 78 | 79 | public boolean onItemLongClick(AdapterView arg0, View arg1, int arg2,long arg3) { 80 | return invokeItemLongClickMethod(handler,itemLongClickMehtod,arg0,arg1,arg2,arg3); 81 | } 82 | 83 | public void onItemSelected(AdapterView arg0, View arg1, int arg2,long arg3) { 84 | 85 | invokeItemSelectMethod(handler,itemSelectMethod,arg0,arg1,arg2,arg3); 86 | } 87 | 88 | public void onNothingSelected(AdapterView arg0) { 89 | invokeNoSelectMethod(handler,nothingSelectedMethod,arg0); 90 | } 91 | 92 | public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { 93 | 94 | invokeItemClickMethod(handler,itemClickMethod,arg0,arg1,arg2,arg3); 95 | } 96 | 97 | public void onClick(View v) { 98 | 99 | invokeClickMethod(handler, clickMethod, v); 100 | } 101 | 102 | 103 | private static Object invokeClickMethod(Object handler, String methodName, Object... params){ 104 | if(handler == null) return null; 105 | Method method = null; 106 | try{ 107 | method = handler.getClass().getDeclaredMethod(methodName,View.class); 108 | if(method!=null) 109 | return method.invoke(handler, params); 110 | else 111 | throw new ViewException("no such method:"+methodName); 112 | }catch(Exception e){ 113 | e.printStackTrace(); 114 | } 115 | 116 | return null; 117 | 118 | } 119 | 120 | 121 | private static boolean invokeLongClickMethod(Object handler, String methodName, Object... params){ 122 | if(handler == null) return false; 123 | Method method = null; 124 | try{ 125 | //public boolean onLongClick(View v) 126 | method = handler.getClass().getDeclaredMethod(methodName,View.class); 127 | if(method!=null){ 128 | Object obj = method.invoke(handler, params); 129 | return obj==null?false:Boolean.valueOf(obj.toString()); 130 | } 131 | else 132 | throw new ViewException("no such method:"+methodName); 133 | }catch(Exception e){ 134 | e.printStackTrace(); 135 | } 136 | 137 | return false; 138 | 139 | } 140 | 141 | 142 | 143 | private static Object invokeItemClickMethod(Object handler, String methodName, Object... params){ 144 | if(handler == null) return null; 145 | Method method = null; 146 | try{ 147 | ///onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) 148 | method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class); 149 | if(method!=null) 150 | return method.invoke(handler, params); 151 | else 152 | throw new ViewException("no such method:"+methodName); 153 | }catch(Exception e){ 154 | e.printStackTrace(); 155 | } 156 | 157 | return null; 158 | } 159 | 160 | 161 | private static boolean invokeItemLongClickMethod(Object handler, String methodName, Object... params){ 162 | if(handler == null) throw new ViewException("invokeItemLongClickMethod: handler is null :"); 163 | Method method = null; 164 | try{ 165 | ///onItemLongClick(AdapterView arg0, View arg1, int arg2,long arg3) 166 | method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class); 167 | if(method!=null){ 168 | Object obj = method.invoke(handler, params); 169 | return Boolean.valueOf(obj==null?false:Boolean.valueOf(obj.toString())); 170 | } 171 | else 172 | throw new ViewException("no such method:"+methodName); 173 | }catch(Exception e){ 174 | e.printStackTrace(); 175 | } 176 | 177 | return false; 178 | } 179 | 180 | 181 | private static Object invokeItemSelectMethod(Object handler, String methodName, Object... params){ 182 | if(handler == null) return null; 183 | Method method = null; 184 | try{ 185 | ///onItemSelected(AdapterView arg0, View arg1, int arg2,long arg3) 186 | method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class); 187 | if(method!=null) 188 | return method.invoke(handler, params); 189 | else 190 | throw new ViewException("no such method:"+methodName); 191 | }catch(Exception e){ 192 | e.printStackTrace(); 193 | } 194 | 195 | return null; 196 | } 197 | 198 | private static Object invokeNoSelectMethod(Object handler, String methodName, Object... params){ 199 | if(handler == null) return null; 200 | Method method = null; 201 | try{ 202 | //onNothingSelected(AdapterView arg0) 203 | method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class); 204 | if(method!=null) 205 | return method.invoke(handler, params); 206 | else 207 | throw new ViewException("no such method:"+methodName); 208 | }catch(Exception e){ 209 | e.printStackTrace(); 210 | } 211 | 212 | return null; 213 | } 214 | 215 | 216 | 217 | } 218 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/AjaxParams.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http; 17 | 18 | import java.io.InputStream; 19 | import java.io.File; 20 | import java.io.FileInputStream; 21 | import java.io.FileNotFoundException; 22 | import java.io.UnsupportedEncodingException; 23 | import java.util.LinkedList; 24 | import java.util.List; 25 | import java.util.Map; 26 | import java.util.concurrent.ConcurrentHashMap; 27 | 28 | import org.apache.http.HttpEntity; 29 | import org.apache.http.client.entity.UrlEncodedFormEntity; 30 | import org.apache.http.client.utils.URLEncodedUtils; 31 | import org.apache.http.message.BasicNameValuePair; 32 | 33 | /** 34 | *

35 | * 使用方法: 36 | *

37 | *

 38 |  * AjaxParams params = new AjaxParams();
 39 |  * params.put("username", "michael");
 40 |  * params.put("password", "123456");
 41 |  * params.put("email", "test@tsz.net");
 42 |  * params.put("profile_picture", new File("/mnt/sdcard/pic.jpg")); // 上传文件
 43 |  * params.put("profile_picture2", inputStream); // 上传数据流
 44 |  * params.put("profile_picture3", new ByteArrayInputStream(bytes)); // 提交字节流
 45 |  *
 46 |  * FinalHttp fh = new FinalHttp();
 47 |  * fh.post("http://www.yangfuhai.com", params, new AjaxCallBack(){
 48 |  * 		@Override
 49 |  *		public void onLoading(long count, long current) {
 50 |  *				textView.setText(current+"/"+count);
 51 |  *		}
 52 |  *
 53 |  *		@Override
 54 |  *		public void onSuccess(String t) {
 55 |  *			textView.setText(t==null?"null":t);
 56 |  *		}
 57 |  * });
 58 |  * 
59 | */ 60 | public class AjaxParams { 61 | private static String ENCODING = "UTF-8"; 62 | 63 | protected ConcurrentHashMap urlParams; 64 | protected ConcurrentHashMap fileParams; 65 | 66 | public AjaxParams() { 67 | init(); 68 | } 69 | 70 | public AjaxParams(Map source) { 71 | init(); 72 | 73 | for(Map.Entry entry : source.entrySet()) { 74 | put(entry.getKey(), entry.getValue()); 75 | } 76 | } 77 | 78 | public AjaxParams(String key, String value) { 79 | init(); 80 | put(key, value); 81 | } 82 | 83 | public AjaxParams(Object... keysAndValues) { 84 | init(); 85 | int len = keysAndValues.length; 86 | if (len % 2 != 0) 87 | throw new IllegalArgumentException("Supplied arguments must be even"); 88 | for (int i = 0; i < len; i += 2) { 89 | String key = String.valueOf(keysAndValues[i]); 90 | String val = String.valueOf(keysAndValues[i + 1]); 91 | put(key, val); 92 | } 93 | } 94 | 95 | public void put(String key, String value){ 96 | if(key != null && value != null) { 97 | urlParams.put(key, value); 98 | } 99 | } 100 | 101 | public void put(String key, File file) throws FileNotFoundException { 102 | put(key, new FileInputStream(file), file.getName()); 103 | } 104 | 105 | public void put(String key, InputStream stream) { 106 | put(key, stream, null); 107 | } 108 | 109 | public void put(String key, InputStream stream, String fileName) { 110 | put(key, stream, fileName, null); 111 | } 112 | 113 | /** 114 | * 添加 inputStream 到请求中. 115 | * @param key the key name for the new param. 116 | * @param stream the input stream to add. 117 | * @param fileName the name of the file. 118 | * @param contentType the content type of the file, eg. application/json 119 | */ 120 | public void put(String key, InputStream stream, String fileName, String contentType) { 121 | if(key != null && stream != null) { 122 | fileParams.put(key, new FileWrapper(stream, fileName, contentType)); 123 | } 124 | } 125 | 126 | public void remove(String key){ 127 | urlParams.remove(key); 128 | fileParams.remove(key); 129 | } 130 | 131 | @Override 132 | public String toString() { 133 | StringBuilder result = new StringBuilder(); 134 | for(ConcurrentHashMap.Entry entry : urlParams.entrySet()) { 135 | if(result.length() > 0) 136 | result.append("&"); 137 | 138 | result.append(entry.getKey()); 139 | result.append("="); 140 | result.append(entry.getValue()); 141 | } 142 | 143 | for(ConcurrentHashMap.Entry entry : fileParams.entrySet()) { 144 | if(result.length() > 0) 145 | result.append("&"); 146 | 147 | result.append(entry.getKey()); 148 | result.append("="); 149 | result.append("FILE"); 150 | } 151 | 152 | return result.toString(); 153 | } 154 | 155 | /** 156 | * Returns an HttpEntity containing all request parameters 157 | */ 158 | public HttpEntity getEntity() { 159 | HttpEntity entity = null; 160 | 161 | if(!fileParams.isEmpty()) { 162 | MultipartEntity multipartEntity = new MultipartEntity(); 163 | 164 | // Add string params 165 | for(ConcurrentHashMap.Entry entry : urlParams.entrySet()) { 166 | multipartEntity.addPart(entry.getKey(), entry.getValue()); 167 | } 168 | 169 | // Add file params 170 | int currentIndex = 0; 171 | int lastIndex = fileParams.entrySet().size() - 1; 172 | for(ConcurrentHashMap.Entry entry : fileParams.entrySet()) { 173 | FileWrapper file = entry.getValue(); 174 | if(file.inputStream != null) { 175 | boolean isLast = currentIndex == lastIndex; 176 | if(file.contentType != null) { 177 | multipartEntity.addPart(entry.getKey(), file.getFileName(), file.inputStream, file.contentType, isLast); 178 | } else { 179 | multipartEntity.addPart(entry.getKey(), file.getFileName(), file.inputStream, isLast); 180 | } 181 | } 182 | currentIndex++; 183 | } 184 | 185 | entity = multipartEntity; 186 | } else { 187 | try { 188 | entity = new UrlEncodedFormEntity(getParamsList(), ENCODING); 189 | } catch (UnsupportedEncodingException e) { 190 | e.printStackTrace(); 191 | } 192 | } 193 | 194 | return entity; 195 | } 196 | 197 | private void init(){ 198 | urlParams = new ConcurrentHashMap(); 199 | fileParams = new ConcurrentHashMap(); 200 | } 201 | 202 | protected List getParamsList() { 203 | List lparams = new LinkedList(); 204 | 205 | for(ConcurrentHashMap.Entry entry : urlParams.entrySet()) { 206 | lparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); 207 | } 208 | 209 | return lparams; 210 | } 211 | 212 | public String getParamString() { 213 | return URLEncodedUtils.format(getParamsList(), ENCODING); 214 | } 215 | 216 | private static class FileWrapper { 217 | public InputStream inputStream; 218 | public String fileName; 219 | public String contentType; 220 | 221 | public FileWrapper(InputStream inputStream, String fileName, String contentType) { 222 | this.inputStream = inputStream; 223 | this.fileName = fileName; 224 | this.contentType = contentType; 225 | } 226 | 227 | public String getFileName() { 228 | if(fileName != null) { 229 | return fileName; 230 | } else { 231 | return "nofilename"; 232 | } 233 | } 234 | } 235 | } -------------------------------------------------------------------------------- /src/net/tsz/afinal/core/Queue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Written by Doug Lea with assistance from members of JCP JSR-166 3 | * Expert Group and released to the public domain, as explained at 4 | * http://creativecommons.org/licenses/publicdomain 5 | */ 6 | 7 | package net.tsz.afinal.core; 8 | 9 | import java.util.Collection; 10 | 11 | // BEGIN android-note 12 | // removed link to collections framework docs 13 | // END android-note 14 | 15 | /** 16 | * A collection designed for holding elements prior to processing. 17 | * Besides basic {@link java.util.Collection Collection} operations, 18 | * queues provide additional insertion, extraction, and inspection 19 | * operations. Each of these methods exists in two forms: one throws 20 | * an exception if the operation fails, the other returns a special 21 | * value (either null or false, depending on the 22 | * operation). The latter form of the insert operation is designed 23 | * specifically for use with capacity-restricted Queue 24 | * implementations; in most implementations, insert operations cannot 25 | * fail. 26 | * 27 | *

28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | *
Throws exceptionReturns special value
Insert{@link #add add(e)}{@link #offer offer(e)}
Remove{@link #remove remove()}{@link #poll poll()}
Examine{@link #element element()}{@link #peek peek()}
50 | * 51 | *

Queues typically, but do not necessarily, order elements in a 52 | * FIFO (first-in-first-out) manner. Among the exceptions are 53 | * priority queues, which order elements according to a supplied 54 | * comparator, or the elements' natural ordering, and LIFO queues (or 55 | * stacks) which order the elements LIFO (last-in-first-out). 56 | * Whatever the ordering used, the head of the queue is that 57 | * element which would be removed by a call to {@link #remove() } or 58 | * {@link #poll()}. In a FIFO queue, all new elements are inserted at 59 | * the tail of the queue. Other kinds of queues may use 60 | * different placement rules. Every Queue implementation 61 | * must specify its ordering properties. 62 | * 63 | *

The {@link #offer offer} method inserts an element if possible, 64 | * otherwise returning false. This differs from the {@link 65 | * java.util.Collection#add Collection.add} method, which can fail to 66 | * add an element only by throwing an unchecked exception. The 67 | * offer method is designed for use when failure is a normal, 68 | * rather than exceptional occurrence, for example, in fixed-capacity 69 | * (or "bounded") queues. 70 | * 71 | *

The {@link #remove()} and {@link #poll()} methods remove and 72 | * return the head of the queue. 73 | * Exactly which element is removed from the queue is a 74 | * function of the queue's ordering policy, which differs from 75 | * implementation to implementation. The remove() and 76 | * poll() methods differ only in their behavior when the 77 | * queue is empty: the remove() method throws an exception, 78 | * while the poll() method returns null. 79 | * 80 | *

The {@link #element()} and {@link #peek()} methods return, but do 81 | * not remove, the head of the queue. 82 | * 83 | *

The Queue interface does not define the blocking queue 84 | * methods, which are common in concurrent programming. These methods, 85 | * which wait for elements to appear or for space to become available, are 86 | * defined in the {@link java.util.concurrent.BlockingQueue} interface, which 87 | * extends this interface. 88 | * 89 | *

Queue implementations generally do not allow insertion 90 | * of null elements, although some implementations, such as 91 | * {@link LinkedList}, do not prohibit insertion of null. 92 | * Even in the implementations that permit it, null should 93 | * not be inserted into a Queue, as null is also 94 | * used as a special return value by the poll method to 95 | * indicate that the queue contains no elements. 96 | * 97 | *

Queue implementations generally do not define 98 | * element-based versions of methods equals and 99 | * hashCode but instead inherit the identity based versions 100 | * from class Object, because element-based equality is not 101 | * always well-defined for queues with the same elements but different 102 | * ordering properties. 103 | * 104 | * @see java.util.Collection 105 | * @see LinkedList 106 | * @see PriorityQueue 107 | * @see java.util.concurrent.LinkedBlockingQueue 108 | * @see java.util.concurrent.BlockingQueue 109 | * @see java.util.concurrent.ArrayBlockingQueue 110 | * @see java.util.concurrent.LinkedBlockingQueue 111 | * @see java.util.concurrent.PriorityBlockingQueue 112 | * @since 1.5 113 | * @author Doug Lea 114 | * @param the type of elements held in this collection 115 | */ 116 | public interface Queue extends Collection { 117 | /** 118 | * Inserts the specified element into this queue if it is possible to do so 119 | * immediately without violating capacity restrictions, returning 120 | * true upon success and throwing an IllegalStateException 121 | * if no space is currently available. 122 | * 123 | * @param e the element to add 124 | * @return true (as specified by {@link Collection#add}) 125 | * @throws IllegalStateException if the element cannot be added at this 126 | * time due to capacity restrictions 127 | * @throws ClassCastException if the class of the specified element 128 | * prevents it from being added to this queue 129 | * @throws NullPointerException if the specified element is null and 130 | * this queue does not permit null elements 131 | * @throws IllegalArgumentException if some property of this element 132 | * prevents it from being added to this queue 133 | */ 134 | boolean add(E e); 135 | 136 | /** 137 | * Inserts the specified element into this queue if it is possible to do 138 | * so immediately without violating capacity restrictions. 139 | * When using a capacity-restricted queue, this method is generally 140 | * preferable to {@link #add}, which can fail to insert an element only 141 | * by throwing an exception. 142 | * 143 | * @param e the element to add 144 | * @return true if the element was added to this queue, else 145 | * false 146 | * @throws ClassCastException if the class of the specified element 147 | * prevents it from being added to this queue 148 | * @throws NullPointerException if the specified element is null and 149 | * this queue does not permit null elements 150 | * @throws IllegalArgumentException if some property of this element 151 | * prevents it from being added to this queue 152 | */ 153 | boolean offer(E e); 154 | 155 | /** 156 | * Retrieves and removes the head of this queue. This method differs 157 | * from {@link #poll poll} only in that it throws an exception if this 158 | * queue is empty. 159 | * 160 | * @return the head of this queue 161 | * @throws NoSuchElementException if this queue is empty 162 | */ 163 | E remove(); 164 | 165 | /** 166 | * Retrieves and removes the head of this queue, 167 | * or returns null if this queue is empty. 168 | * 169 | * @return the head of this queue, or null if this queue is empty 170 | */ 171 | E poll(); 172 | 173 | /** 174 | * Retrieves, but does not remove, the head of this queue. This method 175 | * differs from {@link #peek peek} only in that it throws an exception 176 | * if this queue is empty. 177 | * 178 | * @return the head of this queue 179 | * @throws NoSuchElementException if this queue is empty 180 | */ 181 | E element(); 182 | 183 | /** 184 | * Retrieves, but does not remove, the head of this queue, 185 | * or returns null if this queue is empty. 186 | * 187 | * @return the head of this queue, or null if this queue is empty 188 | */ 189 | E peek(); 190 | } 191 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/BitmapCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.nio.ByteBuffer; 21 | 22 | import net.tsz.afinal.bitmap.core.BytesBufferPool.BytesBuffer; 23 | import net.tsz.afinal.bitmap.core.DiskCache.LookupRequest; 24 | import net.tsz.afinal.utils.Utils; 25 | import android.app.ActivityManager; 26 | import android.content.Context; 27 | import android.graphics.Bitmap; 28 | 29 | 30 | public class BitmapCache { 31 | 32 | //默认的内存缓存大小 33 | private static final int DEFAULT_MEM_CACHE_SIZE = 1024 * 1024 * 8; // 8MB 34 | 35 | //默认的磁盘缓存大小 36 | private static final int DEFAULT_DISK_CACHE_SIZE = 1024 * 1024 * 50; // 50MB 37 | private static final int DEFAULT_DISK_CACHE_COUNT = 1000 * 10 ; // 缓存的图片数量 38 | 39 | //BitmapCache的一些默认配置 40 | private static final boolean DEFAULT_MEM_CACHE_ENABLED = true; 41 | private static final boolean DEFAULT_DISK_CACHE_ENABLED = true; 42 | 43 | private DiskCache mDiskCache; 44 | private IMemoryCache mMemoryCache; 45 | private ImageCacheParams mCacheParams; 46 | 47 | 48 | public BitmapCache(ImageCacheParams cacheParams) { 49 | init(cacheParams); 50 | } 51 | 52 | 53 | /** 54 | * 初始化 图片缓存 55 | * @param cacheParams 56 | */ 57 | private void init(ImageCacheParams cacheParams) { 58 | mCacheParams = cacheParams; 59 | 60 | // 是否启用内存缓存 61 | if (mCacheParams.memoryCacheEnabled) { 62 | //是否立即回收内存 63 | if(mCacheParams.recycleImmediately) 64 | mMemoryCache = new SoftMemoryCacheImpl(mCacheParams.memCacheSize); 65 | else 66 | mMemoryCache = new BaseMemoryCacheImpl(mCacheParams.memCacheSize); 67 | } 68 | 69 | // 是否启用sdcard缓存 70 | if (cacheParams.diskCacheEnabled) { 71 | try { 72 | String path = mCacheParams.diskCacheDir.getAbsolutePath(); 73 | mDiskCache = new DiskCache(path, mCacheParams.diskCacheCount, mCacheParams.diskCacheSize, false); 74 | } catch (IOException e) { 75 | //ignore. 76 | } 77 | } 78 | } 79 | 80 | 81 | /** 82 | * 添加图片到内存缓存中 83 | * @param url Url 地址 84 | * @param bitmap 图片数据 85 | */ 86 | public void addToMemoryCache(String url, Bitmap bitmap) { 87 | if (url == null || bitmap == null) { 88 | return; 89 | } 90 | mMemoryCache.put(url, bitmap); 91 | } 92 | 93 | /** 94 | * 添加 数据到sdcard缓存中 95 | * @param url url地址 96 | * @param data 数据信息 97 | */ 98 | public void addToDiskCache(String url, byte[] data) { 99 | if (mDiskCache == null || url == null || data == null) { 100 | return; 101 | } 102 | //Add to disk cache 103 | byte[] key = Utils.makeKey(url); 104 | long cacheKey = Utils.crc64Long(key); 105 | ByteBuffer buffer = ByteBuffer.allocate(key.length + data.length); 106 | buffer.put(key); 107 | buffer.put(data); 108 | synchronized (mDiskCache) { 109 | try { 110 | mDiskCache.insert(cacheKey, buffer.array()); 111 | } catch (IOException ex) { 112 | // ignore. 113 | } 114 | } 115 | 116 | } 117 | 118 | /** 119 | * 从sdcard中获取内存缓存 120 | * @param url 图片url地址 121 | * @param buffer 填充缓存区 122 | * @return 是否获得图片 123 | */ 124 | public boolean getImageData(String url, BytesBuffer buffer){ 125 | if(mDiskCache == null) 126 | return false; 127 | 128 | byte[] key = Utils.makeKey(url); 129 | long cacheKey = Utils.crc64Long(key); 130 | try { 131 | LookupRequest request = new LookupRequest(); 132 | request.key = cacheKey; 133 | request.buffer = buffer.data; 134 | synchronized (mDiskCache) { 135 | if (!mDiskCache.lookup(request)) 136 | return false; 137 | } 138 | if (Utils.isSameKey(key, request.buffer)) { 139 | buffer.data = request.buffer; 140 | buffer.offset = key.length; 141 | buffer.length = request.length - buffer.offset; 142 | return true; 143 | } 144 | } catch (IOException ex) { 145 | // ignore. 146 | } 147 | return false; 148 | } 149 | 150 | /** 151 | * 从内存缓存中获取bitmap. 152 | */ 153 | public Bitmap getBitmapFromMemoryCache(String data) { 154 | if (mMemoryCache != null) 155 | return mMemoryCache.get(data); 156 | return null; 157 | } 158 | 159 | /** 160 | * 清空内存缓存和sdcard缓存 161 | */ 162 | public void clearCache() { 163 | clearMemoryCache(); 164 | clearDiskCache(); 165 | } 166 | 167 | public void clearDiskCache(){ 168 | if(mDiskCache!=null) 169 | mDiskCache.delete(); 170 | } 171 | 172 | public void clearMemoryCache(){ 173 | if (mMemoryCache != null) { 174 | mMemoryCache.evictAll(); 175 | } 176 | } 177 | 178 | public void clearCache(String key) { 179 | clearMemoryCache(key); 180 | clearDiskCache(key); 181 | } 182 | 183 | public void clearDiskCache(String url){ 184 | addToDiskCache(url, new byte[0]); 185 | } 186 | 187 | public void clearMemoryCache(String key){ 188 | if (mMemoryCache != null) { 189 | mMemoryCache.remove(key); 190 | } 191 | } 192 | 193 | /** 194 | * Closes the disk cache associated with this ImageCache object. Note that this includes 195 | * disk access so this should not be executed on the main/UI thread. 196 | */ 197 | public void close() { 198 | if(mDiskCache!=null) 199 | mDiskCache.close(); 200 | } 201 | 202 | 203 | /** 204 | * Image cache 的配置信息. 205 | */ 206 | public static class ImageCacheParams { 207 | public int memCacheSize = DEFAULT_MEM_CACHE_SIZE; 208 | public int diskCacheSize = DEFAULT_DISK_CACHE_SIZE; 209 | public int diskCacheCount = DEFAULT_DISK_CACHE_COUNT; 210 | public File diskCacheDir; 211 | public boolean memoryCacheEnabled = DEFAULT_MEM_CACHE_ENABLED; 212 | public boolean diskCacheEnabled = DEFAULT_DISK_CACHE_ENABLED; 213 | public boolean recycleImmediately = true ; 214 | 215 | 216 | public ImageCacheParams(File diskCacheDir) { 217 | this.diskCacheDir = diskCacheDir; 218 | } 219 | 220 | public ImageCacheParams(String diskCacheDir) { 221 | this.diskCacheDir = new File(diskCacheDir); 222 | } 223 | 224 | /** 225 | * 设置缓存大小 226 | * @param context 227 | * @param percent 百分比,值的范围是在 0.05 到 0.8之间 228 | */ 229 | public void setMemCacheSizePercent(Context context, float percent) { 230 | if (percent < 0.05f || percent > 0.8f) { 231 | throw new IllegalArgumentException("setMemCacheSizePercent - percent must be " 232 | + "between 0.05 and 0.8 (inclusive)"); 233 | } 234 | memCacheSize = Math.round(percent * getMemoryClass(context) * 1024 * 1024); 235 | } 236 | 237 | 238 | public void setMemCacheSize(int memCacheSize) { 239 | this.memCacheSize = memCacheSize; 240 | } 241 | 242 | public void setDiskCacheSize(int diskCacheSize) { 243 | this.diskCacheSize = diskCacheSize; 244 | } 245 | 246 | private static int getMemoryClass(Context context) { 247 | return ((ActivityManager) context.getSystemService( 248 | Context.ACTIVITY_SERVICE)).getMemoryClass(); 249 | } 250 | 251 | public void setDiskCacheCount(int diskCacheCount) { 252 | this.diskCacheCount = diskCacheCount; 253 | } 254 | 255 | public void setRecycleImmediately(boolean recycleImmediately) { 256 | this.recycleImmediately = recycleImmediately; 257 | } 258 | 259 | } 260 | 261 | 262 | } 263 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #afinal交流平台 2 | * QQ群:192341294(群1,2000未满) 246710918(群2,1000未满) 3 | ##作者个人微信 4 | ![mahua](http://7xi3g2.com1.z0.glb.clouddn.com/grwx.png?imageView2/1/w/250/h/250/q/87) 5 | 6 | 7 | ---- 8 | # ![mahua](http://code.google.com/p/afinal/logo?cct=1351516535) Afinal简介 9 | * Afinal 是一个android的sqlite orm 和 ioc 框架。同时封装了android中的http框架,使其更加简单易用; 10 | * 使用finalBitmap,无需考虑bitmap在android中加载的时候oom的问题和快速滑动的时候图片加载位置错位等问题。 11 | * Afinal的宗旨是简洁,快速。约定大于配置的方式。尽量一行代码完成所有事情。 12 | 13 | 14 | ##目前Afinal主要有四大模块: 15 | 16 | * FinalDB模块:android中的orm框架,一行代码就可以进行增删改查。支持一对多,多对一等查询。 17 | 18 | * FinalActivity模块:android中的ioc框架,完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。 19 | 20 | * FinalHttp模块:通过httpclient进行封装http数据请求,支持ajax方式加载。 21 | 22 | * FinalBitmap模块:通过FinalBitmap,imageview加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。FinalBitmap可以配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等。FinalBitmap的内存管理使用lru算法,没有使用弱引用(android2.3以后google已经不建议使用弱引用,android2.3后强行回收软引用和弱引用,详情查看android官方文档),更好的管理bitmap内存。FinalBitmap可以自定义下载器,用来扩展其他协议显示网络图片,比如ftp等。同时可以自定义bitmap显示器,在imageview显示图片的时候播放动画等(默认是渐变动画显示)。 23 | 24 | 25 | --- 26 | ## 使用afinal快速开发框架需要有以下权限: 27 | 28 | ```xml 29 | 30 | 31 | ``` 32 | * 第一个是访问网络 33 | * 第二个是访问sdcard 34 | * 访问网络是请求网络图片的时候需要或者是http数据请求时候需要,访问sdcard是图片缓存的需要。 35 | 36 | ---- 37 | ##FinalDB使用方法: 38 | 关于finalDb的更多介绍,请点击[这里](http://my.oschina.net/yangfuhai/blog/87459) 39 | 40 | ```java 41 | FinalDb db = FinalDb.create(this); 42 | User user = new User(); //这里需要注意的是User对象必须有id属性,或者有通过@ID注解的属性 43 | user.setEmail("mail@tsz.net"); 44 | user.setName("michael yang"); 45 | db.save(user); 46 | ``` 47 | 48 | ---- 49 | ##FinalDB OneToMany懒加载使用方法: 50 | 模型定义: 51 | ```java 52 | public class Parent{ 53 | private int id; 54 | @OneToMany(manyColumn = "parentId") 55 | private OneToManyLazyLoader children; 56 | /*....*/ 57 | } 58 | public class Child{ 59 | private int id; 60 | private String text; 61 | @ManyToOne(column = "parentId") 62 | private Parent parent; 63 | /*....*/ 64 | } 65 | ``` 66 | 使用: 67 | ```java 68 | List all = db.findAll(Parent.class); 69 | for( Parent item : all){ 70 | if(item.getChildren ().getList().size()>0) 71 | Toast.makeText(this,item.getText() + item.getChildren().getList().get(0).getText(),Toast.LENGTH_LONG).show(); 72 | } 73 | ``` 74 | ---- 75 | ##FinalActivity使用方法: 76 | * 完全注解方式就可以进行UI绑定和事件绑定 77 | * 无需findViewById和setClickListener等 78 | 79 | ```java 80 | public class AfinalDemoActivity extends FinalActivity { 81 | 82 | //无需调用findViewById和setOnclickListener等 83 | @ViewInject(id=R.id.button,click="btnClick") Button button; 84 | @ViewInject(id=R.id.textView) TextView textView; 85 | 86 | public void onCreate(Bundle savedInstanceState) { 87 | super.onCreate(savedInstanceState); 88 | setContentView(R.layout.main); 89 | } 90 | 91 | public void btnClick(View v){ 92 | textView.setText("text set form button"); 93 | } 94 | } 95 | ``` 96 | *在其他侵入式框架下使用(如ActionBarShelock) 97 | ```java 98 | protected void onCreate(Bundle savedInstanceState) { 99 | super.onCreate(savedInstanceState); 100 | setContentView(view); 101 | FinalActivity.initInjectedView(this); 102 | } 103 | ``` 104 | *在Fragment中使用 105 | ```java 106 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 107 | Bundle savedInstanceState) { 108 | View viewRoot = inflater.inflate(R.layout.map_frame, container, false); 109 | FinalActivity.initInjectedView(this,viewRoot); 110 | } 111 | ``` 112 | ##FinalHttp使用方法: 113 | ###普通get方法 114 | 115 | ```java 116 | FinalHttp fh = new FinalHttp(); 117 | fh.get("http://www.yangfuhai.com", new AjaxCallBack(){ 118 | 119 | @Override 120 | public void onLoading(long count, long current) { //每1秒钟自动被回调一次 121 | textView.setText(current+"/"+count); 122 | } 123 | 124 | @Override 125 | public void onSuccess(String t) { 126 | textView.setText(t==null?"null":t); 127 | } 128 | 129 | @Override 130 | public void onStart() { 131 | //开始http请求的时候回调 132 | } 133 | 134 | @Override 135 | public void onFailure(Throwable t, String strMsg) { 136 | //加载失败的时候回调 137 | } 138 | }); 139 | ``` 140 | 141 | ### 使用FinalHttp上传文件 或者 提交数据 到服务器(post方法) 142 | 文件上传到服务器,服务器如何接收,请查看[这里](http://www.oschina.net/question/105836_85825) 143 | 144 | ```java 145 | AjaxParams params = new AjaxParams(); 146 | params.put("username", "michael yang"); 147 | params.put("password", "123456"); 148 | params.put("email", "test@tsz.net"); 149 | params.put("profile_picture", new File("/mnt/sdcard/pic.jpg")); // 上传文件 150 | params.put("profile_picture2", inputStream); // 上传数据流 151 | params.put("profile_picture3", new ByteArrayInputStream(bytes)); // 提交字节流 152 | 153 | FinalHttp fh = new FinalHttp(); 154 | fh.post("http://www.yangfuhai.com", params, new AjaxCallBack(){ 155 | @Override 156 | public void onLoading(long count, long current) { 157 | textView.setText(current+"/"+count); 158 | } 159 | 160 | @Override 161 | public void onSuccess(String t) { 162 | textView.setText(t==null?"null":t); 163 | } 164 | }); 165 | ``` 166 | 167 | 168 | ---- 169 | 170 | ###使用FinalHttp下载文件: 171 | * 支持断点续传,随时停止下载任务 或者 开始任务 172 | 173 | ```java 174 | FinalHttp fh = new FinalHttp(); 175 | //调用download方法开始下载 176 | HttpHandler handler = fh.download("http://www.xxx.com/下载路径/xxx.apk", //这里是下载的路径 177 | true,//true:断点续传 false:不断点续传(全新下载) 178 | "/mnt/sdcard/testapk.apk", //这是保存到本地的路径 179 | new AjaxCallBack() { 180 | @Override 181 | public void onLoading(long count, long current) { 182 | textView.setText("下载进度:"+current+"/"+count); 183 | } 184 | 185 | @Override 186 | public void onSuccess(File t) { 187 | textView.setText(t==null?"null":t.getAbsoluteFile().toString()); 188 | } 189 | 190 | }); 191 | 192 | 193 | //调用stop()方法停止下载 194 | handler.stop(); 195 | 196 | 197 | ``` 198 | 199 | 200 | ##FinalBitmap 使用方法 201 | 加载网络图片就一行代码 fb.display(imageView,url) ,更多的display重载请看[帮助文档](https://github.com/yangfuhai/afinal/tree/master/doc) 202 | 203 | ```java 204 | private GridView gridView; 205 | private FinalBitmap fb; 206 | @Override 207 | protected void onCreate(Bundle savedInstanceState) { 208 | super.onCreate(savedInstanceState); 209 | setContentView(R.layout.images); 210 | 211 | gridView = (GridView) findViewById(R.id.gridView); 212 | gridView.setAdapter(mAdapter); 213 | 214 | fb = FinalBitmap.create(this);//初始化FinalBitmap模块 215 | fb.configLoadingImage(R.drawable.downloading); 216 | //这里可以进行其他十几项的配置,也可以不用配置,配置之后必须调用init()函数,才生效 217 | //fb.configBitmapLoadThreadSize(int size) 218 | //fb.configBitmapMaxHeight(bitmapHeight) 219 | } 220 | 221 | 222 | ///////////////////////////adapter getView//////////////////////////////////////////// 223 | 224 | public View getView(int position, View convertView, ViewGroup parent) { 225 | ImageView iv; 226 | if(convertView == null){ 227 | convertView = View.inflate(BitmapCacheActivity.this,R.layout.image_item, null); 228 | iv = (ImageView) convertView.findViewById(R.id.imageView); 229 | iv.setScaleType(ScaleType.CENTER_CROP); 230 | convertView.setTag(iv); 231 | }else{ 232 | iv = (ImageView) convertView.getTag(); 233 | } 234 | //bitmap加载就这一行代码,display还有其他重载,详情查看源码 235 | fb.display(iv,Images.imageUrls[position]); 236 | ``` 237 | 238 | 239 | --- 240 | **>>> Add by fantouch** 241 | 242 | #### 配置成Android Library Project 243 | *解决需求:有多个项目依赖afinal,并且想修改afinal源码* 244 | > 245 | * clone到本地 246 | * 添加AndroidManifest.xml文件: 247 | ```xml 248 | 249 | 251 | 254 | 255 | ``` 256 | > 257 | * 导入到 Eclipse: 258 | `Import => Android => Existing Android Code Into Workspace` 259 | * 工程上按右键 => Properties => Android => √ Is Library 260 | * 完成,你的项目可以引用这个afinal Library了. 261 | 262 | #### 排除不需要Git管理的文件 263 | *解决需求:想修改源码,但不想让Eclipse把工程弄脏* 264 | > 265 | * 忽略已经被Git管理的`./bin`目录: 266 | 导入Eclipse前执行: ` git update-index --assume-unchanged ./bin/* ` 267 | > 268 | * 忽略未被Git管理的文件和目录: 添加`/.gitignore` 文件: 269 | ``` 270 | /gen 271 | /assets 272 | /bin 273 | /res 274 | /.classpath 275 | /.project 276 | /AndroidManifest.xml 277 | /project.properties 278 | /.gitignore 279 | ``` 280 | * 导入到Eclipse,`git status`可见Repository依旧干净. 281 | 282 | **<<< Add by fantouch** 283 | 284 | --- 285 | 286 | #关于作者michael 287 | * 个人博客:[http://www.yangfuhai.com](http://www.yangfuhai.com) 288 | * afinal捐助:[http://me.alipay.com/yangfuhai](http://me.alipay.com/yangfuhai) (为了感谢捐助者,michael将会把捐助者将公布在afinal官方网站上,不让公布的同学说明下) 289 | * afinal交流QQ群 : 192341294 290 | #个人微信 291 | ![mahua](http://7xi3g2.com1.z0.glb.clouddn.com/grwx.png?imageView2/1/w/250/h/250/q/87) 292 | 293 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/http/PreferencesCookieStore.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.http; 17 | 18 | import java.io.ByteArrayInputStream; 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.IOException; 21 | import java.io.ObjectInputStream; 22 | import java.io.ObjectOutputStream; 23 | import java.io.Serializable; 24 | import java.util.ArrayList; 25 | import java.util.Date; 26 | import java.util.List; 27 | import java.util.concurrent.ConcurrentHashMap; 28 | 29 | import org.apache.http.client.CookieStore; 30 | import org.apache.http.cookie.Cookie; 31 | import org.apache.http.impl.cookie.BasicClientCookie; 32 | 33 | import android.content.Context; 34 | import android.content.SharedPreferences; 35 | import android.text.TextUtils; 36 | 37 | /** 38 | * 保存到 Preferences 的cookie 39 | * @author michael yang 40 | * 41 | */ 42 | public class PreferencesCookieStore implements CookieStore { 43 | 44 | private static final String COOKIE_PREFS = "CookiePrefsFile"; 45 | private static final String COOKIE_NAME_STORE = "names"; 46 | private static final String COOKIE_NAME_PREFIX = "cookie_"; 47 | 48 | private final ConcurrentHashMap cookies; 49 | private final SharedPreferences cookiePrefs; 50 | 51 | /** 52 | * Construct a persistent cookie store. 53 | */ 54 | public PreferencesCookieStore(Context context) { 55 | cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0); 56 | cookies = new ConcurrentHashMap(); 57 | 58 | // Load any previously stored cookies into the store 59 | String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null); 60 | if(storedCookieNames != null) { 61 | String[] cookieNames = TextUtils.split(storedCookieNames, ","); 62 | for(String name : cookieNames) { 63 | String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null); 64 | if(encodedCookie != null) { 65 | Cookie decodedCookie = decodeCookie(encodedCookie); 66 | if(decodedCookie != null) { 67 | cookies.put(name, decodedCookie); 68 | } 69 | } 70 | } 71 | 72 | // Clear out expired cookies 73 | clearExpired(new Date()); 74 | } 75 | } 76 | 77 | @Override 78 | public void addCookie(Cookie cookie) { 79 | String name = cookie.getName(); 80 | 81 | // Save cookie into local store, or remove if expired 82 | if(!cookie.isExpired(new Date())) { 83 | cookies.put(name, cookie); 84 | } else { 85 | cookies.remove(name); 86 | } 87 | 88 | // Save cookie into persistent store 89 | SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 90 | prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet())); 91 | prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableCookie(cookie))); 92 | prefsWriter.commit(); 93 | } 94 | 95 | @Override 96 | public void clear() { 97 | // Clear cookies from local store 98 | cookies.clear(); 99 | 100 | // Clear cookies from persistent store 101 | SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 102 | for(String name : cookies.keySet()) { 103 | prefsWriter.remove(COOKIE_NAME_PREFIX + name); 104 | } 105 | prefsWriter.remove(COOKIE_NAME_STORE); 106 | prefsWriter.commit(); 107 | } 108 | 109 | @Override 110 | public boolean clearExpired(Date date) { 111 | boolean clearedAny = false; 112 | SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); 113 | 114 | for(ConcurrentHashMap.Entry entry : cookies.entrySet()) { 115 | String name = entry.getKey(); 116 | Cookie cookie = entry.getValue(); 117 | if(cookie.isExpired(date)) { 118 | // 清除cookies 119 | cookies.remove(name); 120 | 121 | // Clear cookies from persistent store 122 | prefsWriter.remove(COOKIE_NAME_PREFIX + name); 123 | 124 | // We've cleared at least one 125 | clearedAny = true; 126 | } 127 | } 128 | 129 | // Update names in persistent store 130 | if(clearedAny) { 131 | prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet())); 132 | } 133 | prefsWriter.commit(); 134 | 135 | return clearedAny; 136 | } 137 | 138 | @Override 139 | public List getCookies() { 140 | return new ArrayList(cookies.values()); 141 | } 142 | 143 | 144 | 145 | protected String encodeCookie(SerializableCookie cookie) { 146 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 147 | try { 148 | ObjectOutputStream outputStream = new ObjectOutputStream(os); 149 | outputStream.writeObject(cookie); 150 | } catch (Exception e) { 151 | return null; 152 | } 153 | 154 | return byteArrayToHexString(os.toByteArray()); 155 | } 156 | 157 | protected Cookie decodeCookie(String cookieStr) { 158 | byte[] bytes = hexStringToByteArray(cookieStr); 159 | ByteArrayInputStream is = new ByteArrayInputStream(bytes); 160 | Cookie cookie = null; 161 | try { 162 | ObjectInputStream ois = new ObjectInputStream(is); 163 | cookie = ((SerializableCookie)ois.readObject()).getCookie(); 164 | } catch (Exception e) { 165 | e.printStackTrace(); 166 | } 167 | 168 | return cookie; 169 | } 170 | 171 | // Using some super basic byte array <-> hex conversions so we don't have 172 | // to rely on any large Base64 libraries. Can be overridden if you like! 173 | protected String byteArrayToHexString(byte[] b) { 174 | StringBuffer sb = new StringBuffer(b.length * 2); 175 | for (byte element : b) { 176 | int v = element & 0xff; 177 | if(v < 16) { 178 | sb.append('0'); 179 | } 180 | sb.append(Integer.toHexString(v)); 181 | } 182 | return sb.toString().toUpperCase(); 183 | } 184 | 185 | protected byte[] hexStringToByteArray(String s) { 186 | int len = s.length(); 187 | byte[] data = new byte[len / 2]; 188 | for(int i=0; i clazz) { 41 | Table table = clazz.getAnnotation(Table.class); 42 | if(table == null || table.name().trim().length() == 0 ){ 43 | //当没有注解的时候默认用类的名称作为表名,并把点(.)替换为下划线(_) 44 | return clazz.getName().replace('.', '_'); 45 | } 46 | return table.name(); 47 | } 48 | 49 | public static Object getPrimaryKeyValue(Object entity) { 50 | return FieldUtils.getFieldValue(entity,ClassUtils.getPrimaryKeyField(entity.getClass())); 51 | } 52 | 53 | /** 54 | * 根据实体类 获得 实体类对应的表名 55 | * @param entity 56 | * @return 57 | */ 58 | public static String getPrimaryKeyColumn(Class clazz) { 59 | String primaryKey = null ; 60 | Field[] fields = clazz.getDeclaredFields(); 61 | if(fields != null){ 62 | Id idAnnotation = null ; 63 | Field idField = null ; 64 | 65 | for(Field field : fields){ //获取ID注解 66 | idAnnotation = field.getAnnotation(Id.class); 67 | if(idAnnotation != null){ 68 | idField = field; 69 | break; 70 | } 71 | } 72 | 73 | if(idAnnotation != null){ //有ID注解 74 | primaryKey = idAnnotation.column(); 75 | if(primaryKey == null || primaryKey.trim().length() == 0) 76 | primaryKey = idField.getName(); 77 | }else{ //没有ID注解,默认去找 _id 和 id 为主键,优先寻找 _id 78 | for(Field field : fields){ 79 | if("_id".equals(field.getName())) 80 | return "_id"; 81 | } 82 | 83 | for(Field field : fields){ 84 | if("id".equals(field.getName())) 85 | return "id"; 86 | } 87 | } 88 | }else{ 89 | throw new RuntimeException("this model["+clazz+"] has no field"); 90 | } 91 | return primaryKey; 92 | } 93 | 94 | 95 | /** 96 | * 根据实体类 获得 实体类对应的表名 97 | * @param entity 98 | * @return 99 | */ 100 | public static Field getPrimaryKeyField(Class clazz) { 101 | Field primaryKeyField = null ; 102 | Field[] fields = clazz.getDeclaredFields(); 103 | if(fields != null){ 104 | 105 | for(Field field : fields){ //获取ID注解 106 | if(field.getAnnotation(Id.class) != null){ 107 | primaryKeyField = field; 108 | break; 109 | } 110 | } 111 | 112 | if(primaryKeyField == null){ //没有ID注解 113 | for(Field field : fields){ 114 | if("_id".equals(field.getName())){ 115 | primaryKeyField = field; 116 | break; 117 | } 118 | } 119 | } 120 | 121 | if(primaryKeyField == null){ // 如果没有_id的字段 122 | for(Field field : fields){ 123 | if("id".equals(field.getName())){ 124 | primaryKeyField = field; 125 | break; 126 | } 127 | } 128 | } 129 | 130 | }else{ 131 | throw new RuntimeException("this model["+clazz+"] has no field"); 132 | } 133 | return primaryKeyField; 134 | } 135 | 136 | 137 | /** 138 | * 根据实体类 获得 实体类对应的表名 139 | * @param entity 140 | * @return 141 | */ 142 | public static String getPrimaryKeyFieldName(Class clazz) { 143 | Field f = getPrimaryKeyField(clazz); 144 | return f==null ? null:f.getName(); 145 | } 146 | 147 | 148 | 149 | /** 150 | * 将对象转换为ContentValues 151 | * 152 | * @param entity 153 | * @param selective 是否忽略 值为null的字段 154 | * @return 155 | */ 156 | public static List getPropertyList(Class clazz) { 157 | 158 | List plist = new ArrayList(); 159 | try { 160 | Field[] fs = clazz.getDeclaredFields(); 161 | String primaryKeyFieldName = getPrimaryKeyFieldName(clazz); 162 | for (Field f : fs) { 163 | //必须是基本数据类型和没有标瞬时态的字段 164 | if(!FieldUtils.isTransient(f)){ 165 | if (FieldUtils.isBaseDateType(f)) { 166 | 167 | if(f.getName().equals(primaryKeyFieldName)) //过滤主键 168 | continue; 169 | 170 | Property property = new Property(); 171 | 172 | property.setColumn(FieldUtils.getColumnByField(f)); 173 | property.setFieldName(f.getName()); 174 | property.setDataType(f.getType()); 175 | property.setDefaultValue(FieldUtils.getPropertyDefaultValue(f)); 176 | property.setSet(FieldUtils.getFieldSetMethod(clazz, f)); 177 | property.setGet(FieldUtils.getFieldGetMethod(clazz, f)); 178 | property.setField(f); 179 | 180 | plist.add(property); 181 | } 182 | } 183 | } 184 | return plist; 185 | } catch (Exception e) { 186 | throw new RuntimeException(e.getMessage(), e); 187 | } 188 | } 189 | 190 | 191 | /** 192 | * 将对象转换为ContentValues 193 | * 194 | * @param entity 195 | * @param selective 是否忽略 值为null的字段 196 | * @return 197 | */ 198 | public static List getManyToOneList(Class clazz) { 199 | 200 | List mList = new ArrayList(); 201 | try { 202 | Field[] fs = clazz.getDeclaredFields(); 203 | for (Field f : fs) { 204 | if (!FieldUtils.isTransient(f) && FieldUtils.isManyToOne(f)) { 205 | 206 | ManyToOne mto = new ManyToOne(); 207 | //如果类型为ManyToOneLazyLoader则取第二个参数作为manyClass(一方实体) 2013-7-26 208 | if(f.getType()==ManyToOneLazyLoader.class){ 209 | Class pClazz = (Class)((ParameterizedType)f.getGenericType()).getActualTypeArguments()[1]; 210 | if(pClazz!=null) 211 | mto.setManyClass(pClazz); 212 | }else { 213 | mto.setManyClass(f.getType()); 214 | } 215 | mto.setColumn(FieldUtils.getColumnByField(f)); 216 | mto.setFieldName(f.getName()); 217 | mto.setDataType(f.getType()); 218 | mto.setSet(FieldUtils.getFieldSetMethod(clazz, f)); 219 | mto.setGet(FieldUtils.getFieldGetMethod(clazz, f)); 220 | 221 | mList.add(mto); 222 | } 223 | } 224 | return mList; 225 | } catch (Exception e) { 226 | throw new RuntimeException(e.getMessage(), e); 227 | } 228 | } 229 | 230 | 231 | /** 232 | * 将对象转换为ContentValues 233 | * 234 | * @param entity 235 | * @param selective 是否忽略 值为null的字段 236 | * @return 237 | */ 238 | public static List getOneToManyList(Class clazz) { 239 | 240 | List oList = new ArrayList(); 241 | try { 242 | Field[] fs = clazz.getDeclaredFields(); 243 | for (Field f : fs) { 244 | if (!FieldUtils.isTransient(f) && FieldUtils.isOneToMany(f)) { 245 | 246 | OneToMany otm = new OneToMany(); 247 | 248 | otm.setColumn(FieldUtils.getColumnByField(f)); 249 | otm.setFieldName(f.getName()); 250 | 251 | Type type = f.getGenericType(); 252 | 253 | if(type instanceof ParameterizedType){ 254 | ParameterizedType pType = (ParameterizedType) f.getGenericType(); 255 | //如果类型参数为2则认为是LazyLoader 2013-7-25 256 | if(pType.getActualTypeArguments().length==1){ 257 | Class pClazz = (Class)pType.getActualTypeArguments()[0]; 258 | if(pClazz!=null) 259 | otm.setOneClass(pClazz); 260 | }else{ 261 | Class pClazz = (Class)pType.getActualTypeArguments()[1]; 262 | if(pClazz!=null) 263 | otm.setOneClass(pClazz); 264 | } 265 | }else{ 266 | throw new DbException("getOneToManyList Exception:"+f.getName()+"'s type is null"); 267 | } 268 | /*修正类型赋值错误的bug,f.getClass返回的是Filed*/ 269 | otm.setDataType(f.getType()); 270 | otm.setSet(FieldUtils.getFieldSetMethod(clazz, f)); 271 | otm.setGet(FieldUtils.getFieldGetMethod(clazz, f)); 272 | 273 | oList.add(otm); 274 | } 275 | } 276 | return oList; 277 | } catch (Exception e) { 278 | throw new RuntimeException(e.getMessage(), e); 279 | } 280 | } 281 | 282 | 283 | } 284 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/utils/FieldUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.utils; 17 | 18 | import java.lang.reflect.Field; 19 | import java.lang.reflect.InvocationTargetException; 20 | import java.lang.reflect.Method; 21 | import java.text.ParseException; 22 | import java.text.SimpleDateFormat; 23 | import java.util.Date; 24 | 25 | import net.tsz.afinal.annotation.sqlite.Id; 26 | import net.tsz.afinal.annotation.sqlite.ManyToOne; 27 | import net.tsz.afinal.annotation.sqlite.OneToMany; 28 | import net.tsz.afinal.annotation.sqlite.Property; 29 | import net.tsz.afinal.annotation.sqlite.Transient; 30 | 31 | /** 32 | * @title 字段操作工具类 33 | * @description 描述 34 | * @company 探索者网络工作室(www.tsz.net) 35 | * @author michael Young (www.YangFuhai.com) 36 | * @version 1.0 37 | * @created 2012-10-10 38 | */ 39 | public class FieldUtils { 40 | public static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 41 | 42 | public static Method getFieldGetMethod(Class clazz, Field f) { 43 | String fn = f.getName(); 44 | Method m = null; 45 | if(f.getType() == boolean.class){ 46 | m = getBooleanFieldGetMethod(clazz, fn); 47 | } 48 | if(m == null ){ 49 | m = getFieldGetMethod(clazz, fn); 50 | } 51 | return m; 52 | } 53 | 54 | public static Method getBooleanFieldGetMethod(Class clazz, String fieldName) { 55 | String mn = "is" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); 56 | if(isISStart(fieldName)){ 57 | mn = fieldName; 58 | } 59 | try { 60 | return clazz.getDeclaredMethod(mn); 61 | } catch (NoSuchMethodException e) { 62 | e.printStackTrace(); 63 | return null; 64 | } 65 | } 66 | 67 | 68 | public static Method getBooleanFieldSetMethod(Class clazz, Field f) { 69 | String fn = f.getName(); 70 | String mn = "set" + fn.substring(0, 1).toUpperCase() + fn.substring(1); 71 | if(isISStart(f.getName())){ 72 | mn = "set" + fn.substring(2, 3).toUpperCase() + fn.substring(3); 73 | } 74 | try { 75 | return clazz.getDeclaredMethod(mn, f.getType()); 76 | } catch (NoSuchMethodException e) { 77 | e.printStackTrace(); 78 | return null; 79 | } 80 | } 81 | 82 | 83 | private static boolean isISStart(String fieldName){ 84 | if(fieldName==null || fieldName.trim().length()==0) 85 | return false; 86 | //is开头,并且is之后第一个字母是大写 比如 isAdmin 87 | return fieldName.startsWith("is") && !Character.isLowerCase(fieldName.charAt(2)); 88 | } 89 | 90 | 91 | 92 | 93 | public static Method getFieldGetMethod(Class clazz, String fieldName) { 94 | String mn = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); 95 | try { 96 | return clazz.getDeclaredMethod(mn); 97 | } catch (NoSuchMethodException e) { 98 | e.printStackTrace(); 99 | return null; 100 | } 101 | } 102 | 103 | public static Method getFieldSetMethod(Class clazz, Field f) { 104 | String fn = f.getName(); 105 | String mn = "set" + fn.substring(0, 1).toUpperCase() + fn.substring(1); 106 | try { 107 | return clazz.getDeclaredMethod(mn, f.getType()); 108 | } catch (NoSuchMethodException e) { 109 | if(f.getType() == boolean.class){ 110 | return getBooleanFieldSetMethod(clazz, f); 111 | } 112 | } 113 | return null; 114 | } 115 | 116 | public static Method getFieldSetMethod(Class clazz, String fieldName) { 117 | try { 118 | return getFieldSetMethod(clazz, clazz.getDeclaredField(fieldName)); 119 | } catch (SecurityException e) { 120 | e.printStackTrace(); 121 | } catch (NoSuchFieldException e) { 122 | e.printStackTrace(); 123 | } 124 | return null; 125 | } 126 | 127 | /** 128 | * 获取某个字段的值 129 | * @param entity 130 | * @param fieldName 131 | * @return 132 | */ 133 | public static Object getFieldValue(Object entity,Field field){ 134 | Method method = getFieldGetMethod(entity.getClass(), field); 135 | return invoke(entity, method); 136 | } 137 | 138 | /** 139 | * 获取某个字段的值 140 | * @param entity 141 | * @param fieldName 142 | * @return 143 | */ 144 | public static Object getFieldValue(Object entity,String fieldName){ 145 | Method method = getFieldGetMethod(entity.getClass(), fieldName); 146 | return invoke(entity, method); 147 | } 148 | 149 | /** 150 | * 设置某个字段的值 151 | * @param entity 152 | * @param fieldName 153 | * @return 154 | */ 155 | public static void setFieldValue(Object entity,Field field,Object value){ 156 | try { 157 | Method set = getFieldSetMethod(entity.getClass(), field); 158 | if (set != null) { 159 | set.setAccessible(true); 160 | Class type = field.getType(); 161 | if (type == String.class) { 162 | set.invoke(entity, value.toString()); 163 | } else if (type == int.class || type == Integer.class) { 164 | set.invoke(entity, value == null ? (Integer) null : Integer.parseInt(value.toString())); 165 | } else if (type == float.class || type == Float.class) { 166 | set.invoke(entity, value == null ? (Float) null: Float.parseFloat(value.toString())); 167 | } else if (type == long.class || type == Long.class) { 168 | set.invoke(entity, value == null ? (Long) null: Long.parseLong(value.toString())); 169 | } else if (type == Date.class) { 170 | set.invoke(entity, value == null ? (Date) null: stringToDateTime(value.toString())); 171 | } else { 172 | set.invoke(entity, value); 173 | } 174 | } 175 | } catch (Exception e) { 176 | e.printStackTrace(); 177 | } 178 | } 179 | 180 | 181 | /** 182 | * 获取某个字段的值 183 | * @param entity 184 | * @param fieldName 185 | * @return 186 | */ 187 | public static Field getFieldByColumnName(Class clazz,String columnName){ 188 | Field field = null; 189 | if(columnName!=null){ 190 | Field[] fields = clazz.getDeclaredFields(); 191 | if(fields!=null && fields.length>0){ 192 | if(columnName.equals(ClassUtils.getPrimaryKeyColumn(clazz))) 193 | field = ClassUtils.getPrimaryKeyField(clazz); 194 | 195 | if(field == null){ 196 | for(Field f : fields){ 197 | Property property = f.getAnnotation(Property.class); 198 | if(property!=null && columnName.equals(property.column())){ 199 | field = f; 200 | break; 201 | } 202 | 203 | ManyToOne manyToOne = f.getAnnotation(ManyToOne.class); 204 | if(manyToOne!=null && manyToOne.column().trim().length()!=0){ 205 | field = f; 206 | break; 207 | } 208 | } 209 | } 210 | 211 | if(field == null){ 212 | field = getFieldByName(clazz, columnName); 213 | } 214 | } 215 | } 216 | return field; 217 | } 218 | 219 | 220 | /** 221 | * 获取某个字段的值 222 | * @param entity 223 | * @param fieldName 224 | * @return 225 | */ 226 | public static Field getFieldByName(Class clazz,String fieldName){ 227 | Field field = null; 228 | if(fieldName!=null){ 229 | try { 230 | field = clazz.getDeclaredField(fieldName); 231 | } catch (SecurityException e) { 232 | e.printStackTrace(); 233 | } catch (NoSuchFieldException e) { 234 | e.printStackTrace(); 235 | } 236 | } 237 | return field; 238 | } 239 | 240 | 241 | 242 | /** 243 | * 获取某个属性对应的 表的列 244 | * @param entity 245 | * @param fieldName 246 | * @return 247 | */ 248 | public static String getColumnByField(Field field){ 249 | Property property = field.getAnnotation(Property.class); 250 | if(property != null && property.column().trim().length() != 0){ 251 | return property.column(); 252 | } 253 | 254 | ManyToOne manyToOne = field.getAnnotation(ManyToOne.class); 255 | if(manyToOne!=null && manyToOne.column().trim().length()!=0){ 256 | return manyToOne.column(); 257 | } 258 | 259 | OneToMany oneToMany = field.getAnnotation(OneToMany.class); 260 | if(oneToMany!=null && oneToMany.manyColumn()!=null &&oneToMany.manyColumn().trim().length()!=0){ 261 | return oneToMany.manyColumn(); 262 | } 263 | 264 | Id id = field.getAnnotation(Id.class); 265 | if(id!=null && id.column().trim().length()!=0) 266 | return id.column(); 267 | 268 | return field.getName(); 269 | } 270 | 271 | 272 | 273 | public static String getPropertyDefaultValue(Field field){ 274 | Property property = field.getAnnotation(Property.class); 275 | if(property != null && property.defaultValue().trim().length() != 0){ 276 | return property.defaultValue(); 277 | } 278 | return null ; 279 | } 280 | 281 | 282 | 283 | /** 284 | * 检测 字段是否已经被标注为 非数据库字段 285 | * @param f 286 | * @return 287 | */ 288 | public static boolean isTransient(Field f) { 289 | return f.getAnnotation(Transient.class) != null; 290 | } 291 | 292 | /** 293 | * 获取某个实体执行某个方法的结果 294 | * @param obj 295 | * @param method 296 | * @return 297 | */ 298 | private static Object invoke(Object obj , Method method){ 299 | if(obj == null || method == null) return null; 300 | try { 301 | return method.invoke(obj); 302 | } catch (IllegalArgumentException e) { 303 | e.printStackTrace(); 304 | } catch (IllegalAccessException e) { 305 | e.printStackTrace(); 306 | } catch (InvocationTargetException e) { 307 | e.printStackTrace(); 308 | } 309 | return null; 310 | } 311 | 312 | 313 | public static boolean isManyToOne(Field field){ 314 | return field.getAnnotation(ManyToOne.class)!=null; 315 | } 316 | 317 | public static boolean isOneToMany(Field field){ 318 | return field.getAnnotation(OneToMany.class)!=null; 319 | } 320 | 321 | public static boolean isManyToOneOrOneToMany(Field field){ 322 | return isManyToOne(field) || isOneToMany(field); 323 | } 324 | 325 | public static boolean isBaseDateType(Field field){ 326 | Class clazz = field.getType(); 327 | return clazz.equals(String.class) || 328 | clazz.equals(Integer.class)|| 329 | clazz.equals(Byte.class) || 330 | clazz.equals(Long.class) || 331 | clazz.equals(Double.class) || 332 | clazz.equals(Float.class) || 333 | clazz.equals(Character.class) || 334 | clazz.equals(Short.class) || 335 | clazz.equals(Boolean.class) || 336 | clazz.equals(Date.class) || 337 | clazz.equals(java.util.Date.class) || 338 | clazz.equals(java.sql.Date.class) || 339 | clazz.isPrimitive(); 340 | } 341 | 342 | public static Date stringToDateTime(String strDate) { 343 | if (strDate != null) { 344 | try { 345 | return SDF.parse(strDate); 346 | } catch (ParseException e) { 347 | e.printStackTrace(); 348 | } 349 | } 350 | return null; 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/bitmap/core/LruMemoryCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.bitmap.core; 17 | 18 | import java.util.LinkedHashMap; 19 | import java.util.Map; 20 | 21 | public class LruMemoryCache { 22 | private final LinkedHashMap map; 23 | 24 | /** Size of this cache in units. Not necessarily the number of elements. */ 25 | private int size; 26 | private int maxSize; 27 | 28 | private int putCount; 29 | private int createCount; 30 | private int evictionCount; 31 | private int hitCount; 32 | private int missCount; 33 | 34 | /** 35 | * @param maxSize for caches that do not override {@link #sizeOf}, this is 36 | * the maximum number of entries in the cache. For all other caches, 37 | * this is the maximum sum of the sizes of the entries in this cache. 38 | */ 39 | public LruMemoryCache(int maxSize) { 40 | if (maxSize <= 0) { 41 | throw new IllegalArgumentException("maxSize <= 0"); 42 | } 43 | this.maxSize = maxSize; 44 | this.map = new LinkedHashMap(0, 0.75f, true); 45 | } 46 | 47 | /** 48 | * Returns the value for {@code key} if it exists in the cache or can be 49 | * created by {@code #create}. If a value was returned, it is moved to the 50 | * head of the queue. This returns null if a value is not cached and cannot 51 | * be created. 52 | */ 53 | public final V get(K key) { 54 | if (key == null) { 55 | throw new NullPointerException("key == null"); 56 | } 57 | 58 | V mapValue; 59 | synchronized (this) { 60 | mapValue = map.get(key); 61 | if (mapValue != null) { 62 | hitCount++; 63 | return mapValue; 64 | } 65 | missCount++; 66 | } 67 | 68 | /* 69 | * Attempt to create a value. This may take a long time, and the map 70 | * may be different when create() returns. If a conflicting value was 71 | * added to the map while create() was working, we leave that value in 72 | * the map and release the created value. 73 | */ 74 | 75 | V createdValue = create(key); 76 | if (createdValue == null) { 77 | return null; 78 | } 79 | 80 | synchronized (this) { 81 | createCount++; 82 | mapValue = map.put(key, createdValue); 83 | 84 | if (mapValue != null) { 85 | // There was a conflict so undo that last put 86 | map.put(key, mapValue); 87 | } else { 88 | size += safeSizeOf(key, createdValue); 89 | } 90 | } 91 | 92 | if (mapValue != null) { 93 | entryRemoved(false, key, createdValue, mapValue); 94 | return mapValue; 95 | } else { 96 | trimToSize(maxSize); 97 | return createdValue; 98 | } 99 | } 100 | 101 | /** 102 | * Caches {@code value} for {@code key}. The value is moved to the head of 103 | * the queue. 104 | * 105 | * @return the previous value mapped by {@code key}. 106 | */ 107 | public final V put(K key, V value) { 108 | if (key == null || value == null) { 109 | throw new NullPointerException("key == null || value == null"); 110 | } 111 | 112 | V previous; 113 | synchronized (this) { 114 | putCount++; 115 | size += safeSizeOf(key, value); 116 | previous = map.put(key, value); 117 | if (previous != null) { 118 | size -= safeSizeOf(key, previous); 119 | } 120 | } 121 | 122 | if (previous != null) { 123 | entryRemoved(false, key, previous, value); 124 | } 125 | 126 | trimToSize(maxSize); 127 | return previous; 128 | } 129 | 130 | /** 131 | * @param maxSize the maximum size of the cache before returning. May be -1 132 | * to evict even 0-sized elements. 133 | */ 134 | private void trimToSize(int maxSize) { 135 | while (true) { 136 | K key; 137 | V value; 138 | synchronized (this) { 139 | if (size < 0 || (map.isEmpty() && size != 0)) { 140 | throw new IllegalStateException(getClass().getName() 141 | + ".sizeOf() is reporting inconsistent results!"); 142 | } 143 | 144 | if (size <= maxSize || map.isEmpty()) { 145 | break; 146 | } 147 | 148 | Map.Entry toEvict = map.entrySet().iterator().next(); 149 | key = toEvict.getKey(); 150 | value = toEvict.getValue(); 151 | map.remove(key); 152 | size -= safeSizeOf(key, value); 153 | evictionCount++; 154 | } 155 | 156 | entryRemoved(true, key, value, null); 157 | } 158 | } 159 | 160 | /** 161 | * Removes the entry for {@code key} if it exists. 162 | * 163 | * @return the previous value mapped by {@code key}. 164 | */ 165 | public final V remove(K key) { 166 | if (key == null) { 167 | throw new NullPointerException("key == null"); 168 | } 169 | 170 | V previous; 171 | synchronized (this) { 172 | previous = map.remove(key); 173 | if (previous != null) { 174 | size -= safeSizeOf(key, previous); 175 | } 176 | } 177 | 178 | if (previous != null) { 179 | entryRemoved(false, key, previous, null); 180 | } 181 | 182 | return previous; 183 | } 184 | 185 | /** 186 | * Called for entries that have been evicted or removed. This method is 187 | * invoked when a value is evicted to make space, removed by a call to 188 | * {@link #remove}, or replaced by a call to {@link #put}. The default 189 | * implementation does nothing. 190 | * 191 | *

The method is called without synchronization: other threads may 192 | * access the cache while this method is executing. 193 | * 194 | * @param evicted true if the entry is being removed to make space, false 195 | * if the removal was caused by a {@link #put} or {@link #remove}. 196 | * @param newValue the new value for {@code key}, if it exists. If non-null, 197 | * this removal was caused by a {@link #put}. Otherwise it was caused by 198 | * an eviction or a {@link #remove}. 199 | */ 200 | protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} 201 | 202 | /** 203 | * Called after a cache miss to compute a value for the corresponding key. 204 | * Returns the computed value or null if no value can be computed. The 205 | * default implementation returns null. 206 | * 207 | *

The method is called without synchronization: other threads may 208 | * access the cache while this method is executing. 209 | * 210 | *

If a value for {@code key} exists in the cache when this method 211 | * returns, the created value will be released with {@link #entryRemoved} 212 | * and discarded. This can occur when multiple threads request the same key 213 | * at the same time (causing multiple values to be created), or when one 214 | * thread calls {@link #put} while another is creating a value for the same 215 | * key. 216 | */ 217 | protected V create(K key) { 218 | return null; 219 | } 220 | 221 | private int safeSizeOf(K key, V value) { 222 | int result = sizeOf(key, value); 223 | if (result < 0) { 224 | throw new IllegalStateException("Negative size: " + key + "=" + value); 225 | } 226 | return result; 227 | } 228 | 229 | /** 230 | * Returns the size of the entry for {@code key} and {@code value} in 231 | * user-defined units. The default implementation returns 1 so that size 232 | * is the number of entries and max size is the maximum number of entries. 233 | * 234 | *

An entry's size must not change while it is in the cache. 235 | */ 236 | protected int sizeOf(K key, V value) { 237 | return 1; 238 | } 239 | 240 | /** 241 | * Clear the cache, calling {@link #entryRemoved} on each removed entry. 242 | */ 243 | public final void evictAll() { 244 | trimToSize(-1); // -1 will evict 0-sized elements 245 | } 246 | 247 | /** 248 | * For caches that do not override {@link #sizeOf}, this returns the number 249 | * of entries in the cache. For all other caches, this returns the sum of 250 | * the sizes of the entries in this cache. 251 | */ 252 | public synchronized final int size() { 253 | return size; 254 | } 255 | 256 | /** 257 | * For caches that do not override {@link #sizeOf}, this returns the maximum 258 | * number of entries in the cache. For all other caches, this returns the 259 | * maximum sum of the sizes of the entries in this cache. 260 | */ 261 | public synchronized final int maxSize() { 262 | return maxSize; 263 | } 264 | 265 | /** 266 | * Returns the number of times {@link #get} returned a value. 267 | */ 268 | public synchronized final int hitCount() { 269 | return hitCount; 270 | } 271 | 272 | /** 273 | * Returns the number of times {@link #get} returned null or required a new 274 | * value to be created. 275 | */ 276 | public synchronized final int missCount() { 277 | return missCount; 278 | } 279 | 280 | /** 281 | * Returns the number of times {@link #create(Object)} returned a value. 282 | */ 283 | public synchronized final int createCount() { 284 | return createCount; 285 | } 286 | 287 | /** 288 | * Returns the number of times {@link #put} was called. 289 | */ 290 | public synchronized final int putCount() { 291 | return putCount; 292 | } 293 | 294 | /** 295 | * Returns the number of values that have been evicted. 296 | */ 297 | public synchronized final int evictionCount() { 298 | return evictionCount; 299 | } 300 | 301 | /** 302 | * Returns a copy of the current contents of the cache, ordered from least 303 | * recently accessed to most recently accessed. 304 | */ 305 | public synchronized final Map snapshot() { 306 | return new LinkedHashMap(map); 307 | } 308 | 309 | public synchronized final String toString() { 310 | int accesses = hitCount + missCount; 311 | int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0; 312 | return String.format("LruMemoryCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",maxSize, hitCount, missCount, hitPercent); 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/db/sqlite/SqlBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package net.tsz.afinal.db.sqlite; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | import java.util.List; 21 | 22 | import android.text.TextUtils; 23 | 24 | import net.tsz.afinal.db.table.Id; 25 | import net.tsz.afinal.db.table.KeyValue; 26 | import net.tsz.afinal.db.table.ManyToOne; 27 | import net.tsz.afinal.db.table.Property; 28 | import net.tsz.afinal.db.table.TableInfo; 29 | import net.tsz.afinal.exception.DbException; 30 | 31 | public class SqlBuilder { 32 | 33 | /** 34 | * 获取插入的sql语句 35 | * @return 36 | */ 37 | public static SqlInfo buildInsertSql(Object entity){ 38 | 39 | List keyValueList = getSaveKeyValueListByEntity(entity); 40 | 41 | StringBuffer strSQL=new StringBuffer(); 42 | SqlInfo sqlInfo = null; 43 | if(keyValueList!=null && keyValueList.size()>0){ 44 | 45 | sqlInfo = new SqlInfo(); 46 | 47 | strSQL.append("INSERT INTO "); 48 | strSQL.append(TableInfo.get(entity.getClass()).getTableName()); 49 | strSQL.append(" ("); 50 | for(KeyValue kv : keyValueList){ 51 | strSQL.append(kv.getKey()).append(","); 52 | sqlInfo.addValue(kv.getValue()); 53 | } 54 | strSQL.deleteCharAt(strSQL.length() - 1); 55 | strSQL.append(") VALUES ( "); 56 | 57 | int length = keyValueList.size(); 58 | for(int i =0 ; i < length;i++){ 59 | strSQL.append("?,"); 60 | } 61 | strSQL.deleteCharAt(strSQL.length() - 1); 62 | strSQL.append(")"); 63 | 64 | sqlInfo.setSql(strSQL.toString()); 65 | } 66 | 67 | return sqlInfo; 68 | } 69 | 70 | public static List getSaveKeyValueListByEntity(Object entity){ 71 | 72 | List keyValueList = new ArrayList(); 73 | 74 | TableInfo table=TableInfo.get(entity.getClass()); 75 | Object idvalue = table.getId().getValue(entity); 76 | 77 | if(!(idvalue instanceof Integer)){ //用了非自增长,添加id , 采用自增长就不需要添加id了 78 | if(idvalue instanceof String && idvalue != null){ 79 | KeyValue kv = new KeyValue(table.getId().getColumn(),idvalue); 80 | keyValueList.add(kv); 81 | } 82 | } 83 | 84 | //添加属性 85 | Collection propertys = table.propertyMap.values(); 86 | for(Property property : propertys){ 87 | KeyValue kv = property2KeyValue(property,entity) ; 88 | if(kv!=null) 89 | keyValueList.add(kv); 90 | } 91 | 92 | //添加外键(多对一) 93 | Collection manyToOnes = table.manyToOneMap.values(); 94 | for(ManyToOne many:manyToOnes){ 95 | KeyValue kv = manyToOne2KeyValue(many,entity); 96 | if(kv!=null) keyValueList.add(kv); 97 | } 98 | 99 | return keyValueList; 100 | } 101 | 102 | 103 | private static String getDeleteSqlBytableName(String tableName){ 104 | return "DELETE FROM "+ tableName; 105 | } 106 | 107 | 108 | public static SqlInfo buildDeleteSql(Object entity){ 109 | TableInfo table=TableInfo.get(entity.getClass()); 110 | 111 | Id id = table.getId(); 112 | Object idvalue = id.getValue(entity); 113 | 114 | if(idvalue == null ){ 115 | throw new DbException("getDeleteSQL:"+entity.getClass()+" id value is null"); 116 | } 117 | StringBuffer strSQL = new StringBuffer(getDeleteSqlBytableName(table.getTableName())); 118 | strSQL.append(" WHERE ").append(id.getColumn()).append("=?"); 119 | 120 | SqlInfo sqlInfo = new SqlInfo(); 121 | sqlInfo.setSql(strSQL.toString()); 122 | sqlInfo.addValue(idvalue); 123 | 124 | return sqlInfo; 125 | } 126 | 127 | 128 | 129 | public static SqlInfo buildDeleteSql(Class clazz , Object idValue){ 130 | TableInfo table=TableInfo.get(clazz); 131 | Id id=table.getId(); 132 | 133 | if(null == idValue) { 134 | throw new DbException("getDeleteSQL:idValue is null"); 135 | } 136 | 137 | StringBuffer strSQL = new StringBuffer(getDeleteSqlBytableName(table.getTableName())); 138 | strSQL.append(" WHERE ").append(id.getColumn()).append("=?"); 139 | 140 | SqlInfo sqlInfo = new SqlInfo(); 141 | sqlInfo.setSql(strSQL.toString()); 142 | sqlInfo.addValue(idValue); 143 | 144 | return sqlInfo; 145 | } 146 | 147 | /** 148 | * 根据条件删除数据 ,条件为空的时候将会删除所有的数据 149 | * @param clazz 150 | * @param strWhere 151 | * @return 152 | */ 153 | public static String buildDeleteSql(Class clazz , String strWhere){ 154 | TableInfo table=TableInfo.get(clazz); 155 | StringBuffer strSQL = new StringBuffer(getDeleteSqlBytableName(table.getTableName())); 156 | 157 | if(!TextUtils.isEmpty(strWhere)){ 158 | strSQL.append(" WHERE "); 159 | strSQL.append(strWhere); 160 | } 161 | 162 | return strSQL.toString(); 163 | } 164 | 165 | 166 | ////////////////////////////select sql start/////////////////////////////////////// 167 | 168 | 169 | private static String getSelectSqlByTableName(String tableName){ 170 | return new StringBuffer("SELECT * FROM ").append(tableName).toString(); 171 | } 172 | 173 | 174 | public static String getSelectSQL(Class clazz,Object idValue){ 175 | TableInfo table=TableInfo.get(clazz); 176 | 177 | StringBuffer strSQL = new StringBuffer(getSelectSqlByTableName(table.getTableName())); 178 | strSQL.append(" WHERE "); 179 | strSQL.append(getPropertyStrSql(table.getId().getColumn(), idValue)); 180 | 181 | return strSQL.toString(); 182 | } 183 | 184 | public static SqlInfo getSelectSqlAsSqlInfo(Class clazz,Object idValue){ 185 | TableInfo table=TableInfo.get(clazz); 186 | 187 | StringBuffer strSQL = new StringBuffer(getSelectSqlByTableName(table.getTableName())); 188 | strSQL.append(" WHERE ").append(table.getId().getColumn()).append("=?"); 189 | 190 | SqlInfo sqlInfo = new SqlInfo(); 191 | sqlInfo.setSql(strSQL.toString()); 192 | sqlInfo.addValue(idValue); 193 | 194 | return sqlInfo; 195 | } 196 | 197 | 198 | public static String getSelectSQL(Class clazz){ 199 | return getSelectSqlByTableName(TableInfo.get(clazz).getTableName()); 200 | } 201 | 202 | public static String getSelectSQLByWhere(Class clazz,String strWhere){ 203 | TableInfo table=TableInfo.get(clazz); 204 | 205 | StringBuffer strSQL = new StringBuffer(getSelectSqlByTableName(table.getTableName())); 206 | 207 | if(!TextUtils.isEmpty(strWhere)){ 208 | strSQL.append(" WHERE ").append(strWhere); 209 | } 210 | 211 | return strSQL.toString(); 212 | } 213 | 214 | //////////////////////////////update sql start///////////////////////////////////////////// 215 | 216 | public static SqlInfo getUpdateSqlAsSqlInfo(Object entity){ 217 | 218 | TableInfo table=TableInfo.get(entity.getClass()); 219 | Object idvalue=table.getId().getValue(entity); 220 | 221 | if(null == idvalue ) {//主键值不能为null,否则不能更新 222 | throw new DbException("this entity["+entity.getClass()+"]'s id value is null"); 223 | } 224 | 225 | List keyValueList = new ArrayList(); 226 | //添加属性 227 | Collection propertys = table.propertyMap.values(); 228 | for(Property property : propertys){ 229 | KeyValue kv = property2KeyValue(property,entity) ; 230 | if(kv!=null) 231 | keyValueList.add(kv); 232 | } 233 | 234 | //添加外键(多对一) 235 | Collection manyToOnes = table.manyToOneMap.values(); 236 | for(ManyToOne many:manyToOnes){ 237 | KeyValue kv = manyToOne2KeyValue(many,entity); 238 | if(kv!=null) keyValueList.add(kv); 239 | } 240 | 241 | if(keyValueList == null || keyValueList.size()==0) return null ; 242 | 243 | SqlInfo sqlInfo = new SqlInfo(); 244 | StringBuffer strSQL=new StringBuffer("UPDATE "); 245 | strSQL.append(table.getTableName()); 246 | strSQL.append(" SET "); 247 | for(KeyValue kv : keyValueList){ 248 | strSQL.append(kv.getKey()).append("=?,"); 249 | sqlInfo.addValue(kv.getValue()); 250 | } 251 | strSQL.deleteCharAt(strSQL.length() - 1); 252 | strSQL.append(" WHERE ").append(table.getId().getColumn()).append("=?"); 253 | sqlInfo.addValue(idvalue); 254 | sqlInfo.setSql(strSQL.toString()); 255 | return sqlInfo; 256 | } 257 | 258 | 259 | 260 | 261 | public static SqlInfo getUpdateSqlAsSqlInfo(Object entity,String strWhere){ 262 | 263 | TableInfo table=TableInfo.get(entity.getClass()); 264 | 265 | List keyValueList = new ArrayList(); 266 | 267 | //添加属性 268 | Collection propertys = table.propertyMap.values(); 269 | for(Property property : propertys){ 270 | KeyValue kv = property2KeyValue(property,entity) ; 271 | if(kv!=null) keyValueList.add(kv); 272 | } 273 | 274 | //添加外键(多对一) 275 | Collection manyToOnes = table.manyToOneMap.values(); 276 | for(ManyToOne many:manyToOnes){ 277 | KeyValue kv = manyToOne2KeyValue(many,entity); 278 | if(kv!=null) keyValueList.add(kv); 279 | } 280 | 281 | if(keyValueList == null || keyValueList.size()==0) { 282 | throw new DbException("this entity["+entity.getClass()+"] has no property"); 283 | } 284 | 285 | SqlInfo sqlInfo = new SqlInfo(); 286 | StringBuffer strSQL=new StringBuffer("UPDATE "); 287 | strSQL.append(table.getTableName()); 288 | strSQL.append(" SET "); 289 | for(KeyValue kv : keyValueList){ 290 | strSQL.append(kv.getKey()).append("=?,"); 291 | sqlInfo.addValue(kv.getValue()); 292 | } 293 | strSQL.deleteCharAt(strSQL.length() - 1); 294 | if(!TextUtils.isEmpty(strWhere)){ 295 | strSQL.append(" WHERE ").append(strWhere); 296 | } 297 | sqlInfo.setSql(strSQL.toString()); 298 | return sqlInfo; 299 | } 300 | 301 | 302 | 303 | public static String getCreatTableSQL(Class clazz){ 304 | TableInfo table=TableInfo.get(clazz); 305 | 306 | Id id=table.getId(); 307 | StringBuffer strSQL = new StringBuffer(); 308 | strSQL.append("CREATE TABLE IF NOT EXISTS "); 309 | strSQL.append(table.getTableName()); 310 | strSQL.append(" ( "); 311 | 312 | Class primaryClazz = id.getDataType(); 313 | if( primaryClazz == int.class || primaryClazz==Integer.class 314 | || primaryClazz == long.class || primaryClazz == Long.class){ 315 | strSQL.append(id.getColumn()).append(" INTEGER PRIMARY KEY AUTOINCREMENT,"); 316 | }else{ 317 | strSQL.append(id.getColumn()).append(" TEXT PRIMARY KEY,"); 318 | } 319 | 320 | 321 | 322 | Collection propertys = table.propertyMap.values(); 323 | for(Property property : propertys){ 324 | strSQL.append(property.getColumn()); 325 | Class dataType = property.getDataType(); 326 | if( dataType== int.class || dataType == Integer.class 327 | || dataType == long.class || dataType == Long.class){ 328 | strSQL.append(" INTEGER"); 329 | }else if(dataType == float.class ||dataType == Float.class 330 | ||dataType == double.class || dataType == Double.class){ 331 | strSQL.append(" REAL"); 332 | }else if (dataType == boolean.class || dataType == Boolean.class) { 333 | strSQL.append(" NUMERIC"); 334 | } 335 | strSQL.append(","); 336 | } 337 | 338 | Collection manyToOnes = table.manyToOneMap.values(); 339 | for(ManyToOne manyToOne : manyToOnes){ 340 | strSQL.append(manyToOne.getColumn()) 341 | .append(" INTEGER") 342 | .append(","); 343 | } 344 | strSQL.deleteCharAt(strSQL.length() - 1); 345 | strSQL.append(" )"); 346 | return strSQL.toString(); 347 | } 348 | 349 | 350 | /** 351 | * @param key 352 | * @param value 353 | * @return eg1: name='afinal' eg2: id=100 354 | */ 355 | private static String getPropertyStrSql(String key,Object value){ 356 | StringBuffer sbSQL = new StringBuffer(key).append("="); 357 | if(value instanceof String || value instanceof java.util.Date || value instanceof java.sql.Date){ 358 | sbSQL.append("'").append(value).append("'"); 359 | }else{ 360 | sbSQL.append(value); 361 | } 362 | return sbSQL.toString(); 363 | } 364 | 365 | 366 | 367 | private static KeyValue property2KeyValue(Property property , Object entity){ 368 | KeyValue kv = null ; 369 | String pcolumn=property.getColumn(); 370 | Object value = property.getValue(entity); 371 | if(value!=null){ 372 | kv = new KeyValue(pcolumn, value); 373 | }else{ 374 | if(property.getDefaultValue()!=null && property.getDefaultValue().trim().length()!=0) 375 | kv = new KeyValue(pcolumn, property.getDefaultValue()); 376 | } 377 | return kv; 378 | } 379 | 380 | 381 | private static KeyValue manyToOne2KeyValue(ManyToOne many , Object entity){ 382 | KeyValue kv = null ; 383 | String manycolumn=many.getColumn(); 384 | Object manyobject=many.getValue(entity); 385 | if(manyobject!=null){ 386 | Object manyvalue; 387 | if(manyobject.getClass()==ManyToOneLazyLoader.class){ 388 | manyvalue = TableInfo.get(many.getManyClass()).getId().getValue(((ManyToOneLazyLoader)manyobject).get()); 389 | }else{ 390 | manyvalue = TableInfo.get(manyobject.getClass()).getId().getValue(manyobject); 391 | } 392 | if(manycolumn!=null && manyvalue!=null){ 393 | kv = new KeyValue(manycolumn, manyvalue); 394 | } 395 | } 396 | 397 | return kv; 398 | } 399 | 400 | } 401 | -------------------------------------------------------------------------------- /src/net/tsz/afinal/core/AbstractCollection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package net.tsz.afinal.core; 18 | 19 | import java.lang.reflect.Array; 20 | import java.util.Collection; 21 | import java.util.Iterator; 22 | 23 | /** 24 | * Class {@code AbstractCollection} is an abstract implementation of the {@code 25 | * Collection} interface. A subclass must implement the abstract methods {@code 26 | * iterator()} and {@code size()} to create an immutable collection. To create a 27 | * modifiable collection it's necessary to override the {@code add()} method that 28 | * currently throws an {@code UnsupportedOperationException}. 29 | * 30 | * @since 1.2 31 | */ 32 | public abstract class AbstractCollection implements Collection { 33 | 34 | /** 35 | * Constructs a new instance of this AbstractCollection. 36 | */ 37 | protected AbstractCollection() { 38 | } 39 | 40 | public boolean add(E object) { 41 | throw new UnsupportedOperationException(); 42 | } 43 | 44 | /** 45 | * Attempts to add all of the objects contained in {@code collection} 46 | * to the contents of this {@code Collection} (optional). This implementation 47 | * iterates over the given {@code Collection} and calls {@code add} for each 48 | * element. If any of these calls return {@code true}, then {@code true} is 49 | * returned as result of this method call, {@code false} otherwise. If this 50 | * {@code Collection} does not support adding elements, an {@code 51 | * UnsupportedOperationException} is thrown. 52 | *

53 | * If the passed {@code Collection} is changed during the process of adding elements 54 | * to this {@code Collection}, the behavior depends on the behavior of the passed 55 | * {@code Collection}. 56 | * 57 | * @param collection 58 | * the collection of objects. 59 | * @return {@code true} if this {@code Collection} is modified, {@code false} 60 | * otherwise. 61 | * @throws UnsupportedOperationException 62 | * if adding to this {@code Collection} is not supported. 63 | * @throws ClassCastException 64 | * if the class of an object is inappropriate for this 65 | * {@code Collection}. 66 | * @throws IllegalArgumentException 67 | * if an object cannot be added to this {@code Collection}. 68 | * @throws NullPointerException 69 | * if {@code collection} is {@code null}, or if it contains 70 | * {@code null} elements and this {@code Collection} does not support 71 | * such elements. 72 | */ 73 | public boolean addAll(Collection collection) { 74 | boolean result = false; 75 | Iterator it = collection.iterator(); 76 | while (it.hasNext()) { 77 | if (add(it.next())) { 78 | result = true; 79 | } 80 | } 81 | return result; 82 | } 83 | 84 | /** 85 | * Removes all elements from this {@code Collection}, leaving it empty (optional). 86 | * This implementation iterates over this {@code Collection} and calls the {@code 87 | * remove} method on each element. If the iterator does not support removal 88 | * of elements, an {@code UnsupportedOperationException} is thrown. 89 | *

90 | * Concrete implementations usually can clear a {@code Collection} more efficiently 91 | * and should therefore overwrite this method. 92 | * 93 | * @throws UnsupportedOperationException 94 | * it the iterator does not support removing elements from 95 | * this {@code Collection} 96 | * @see #iterator 97 | * @see #isEmpty 98 | * @see #size 99 | */ 100 | public void clear() { 101 | Iterator it = iterator(); 102 | while (it.hasNext()) { 103 | it.next(); 104 | it.remove(); 105 | } 106 | } 107 | 108 | /** 109 | * Tests whether this {@code Collection} contains the specified object. This 110 | * implementation iterates over this {@code Collection} and tests, whether any 111 | * element is equal to the given object. If {@code object != null} then 112 | * {@code object.equals(e)} is called for each element {@code e} returned by 113 | * the iterator until the element is found. If {@code object == null} then 114 | * each element {@code e} returned by the iterator is compared with the test 115 | * {@code e == null}. 116 | * 117 | * @param object 118 | * the object to search for. 119 | * @return {@code true} if object is an element of this {@code Collection}, {@code 120 | * false} otherwise. 121 | * @throws ClassCastException 122 | * if the object to look for isn't of the correct type. 123 | * @throws NullPointerException 124 | * if the object to look for is {@code null} and this 125 | * {@code Collection} doesn't support {@code null} elements. 126 | */ 127 | public boolean contains(Object object) { 128 | Iterator it = iterator(); 129 | if (object != null) { 130 | while (it.hasNext()) { 131 | if (object.equals(it.next())) { 132 | return true; 133 | } 134 | } 135 | } else { 136 | while (it.hasNext()) { 137 | if (it.next() == null) { 138 | return true; 139 | } 140 | } 141 | } 142 | return false; 143 | } 144 | 145 | /** 146 | * Tests whether this {@code Collection} contains all objects contained in the 147 | * specified {@code Collection}. This implementation iterates over the specified 148 | * {@code Collection}. If one element returned by the iterator is not contained in 149 | * this {@code Collection}, then {@code false} is returned; {@code true} otherwise. 150 | * 151 | * @param collection 152 | * the collection of objects. 153 | * @return {@code true} if all objects in the specified {@code Collection} are 154 | * elements of this {@code Collection}, {@code false} otherwise. 155 | * @throws ClassCastException 156 | * if one or more elements of {@code collection} isn't of the 157 | * correct type. 158 | * @throws NullPointerException 159 | * if {@code collection} contains at least one {@code null} 160 | * element and this {@code Collection} doesn't support {@code null} 161 | * elements. 162 | * @throws NullPointerException 163 | * if {@code collection} is {@code null}. 164 | */ 165 | public boolean containsAll(Collection collection) { 166 | Iterator it = collection.iterator(); 167 | while (it.hasNext()) { 168 | if (!contains(it.next())) { 169 | return false; 170 | } 171 | } 172 | return true; 173 | } 174 | 175 | /** 176 | * Returns if this {@code Collection} contains no elements. This implementation 177 | * tests, whether {@code size} returns 0. 178 | * 179 | * @return {@code true} if this {@code Collection} has no elements, {@code false} 180 | * otherwise. 181 | * 182 | * @see #size 183 | */ 184 | public boolean isEmpty() { 185 | return size() == 0; 186 | } 187 | 188 | /** 189 | * Returns an instance of {@link Iterator} that may be used to access the 190 | * objects contained by this {@code Collection}. The order in which the elements are 191 | * returned by the {@link Iterator} is not defined unless the instance of the 192 | * {@code Collection} has a defined order. In that case, the elements are returned in that order. 193 | *

194 | * In this class this method is declared abstract and has to be implemented 195 | * by concrete {@code Collection} implementations. 196 | * 197 | * @return an iterator for accessing the {@code Collection} contents. 198 | */ 199 | public abstract Iterator iterator(); 200 | 201 | /** 202 | * Removes one instance of the specified object from this {@code Collection} if one 203 | * is contained (optional). This implementation iterates over this 204 | * {@code Collection} and tests for each element {@code e} returned by the iterator, 205 | * whether {@code e} is equal to the given object. If {@code object != null} 206 | * then this test is performed using {@code object.equals(e)}, otherwise 207 | * using {@code object == null}. If an element equal to the given object is 208 | * found, then the {@code remove} method is called on the iterator and 209 | * {@code true} is returned, {@code false} otherwise. If the iterator does 210 | * not support removing elements, an {@code UnsupportedOperationException} 211 | * is thrown. 212 | * 213 | * @param object 214 | * the object to remove. 215 | * @return {@code true} if this {@code Collection} is modified, {@code false} 216 | * otherwise. 217 | * @throws UnsupportedOperationException 218 | * if removing from this {@code Collection} is not supported. 219 | * @throws ClassCastException 220 | * if the object passed is not of the correct type. 221 | * @throws NullPointerException 222 | * if {@code object} is {@code null} and this {@code Collection} 223 | * doesn't support {@code null} elements. 224 | */ 225 | public boolean remove(Object object) { 226 | Iterator it = iterator(); 227 | if (object != null) { 228 | while (it.hasNext()) { 229 | if (object.equals(it.next())) { 230 | it.remove(); 231 | return true; 232 | } 233 | } 234 | } else { 235 | while (it.hasNext()) { 236 | if (it.next() == null) { 237 | it.remove(); 238 | return true; 239 | } 240 | } 241 | } 242 | return false; 243 | } 244 | 245 | /** 246 | * Removes all occurrences in this {@code Collection} of each object in the 247 | * specified {@code Collection} (optional). After this method returns none of the 248 | * elements in the passed {@code Collection} can be found in this {@code Collection} 249 | * anymore. 250 | *

251 | * This implementation iterates over this {@code Collection} and tests for each 252 | * element {@code e} returned by the iterator, whether it is contained in 253 | * the specified {@code Collection}. If this test is positive, then the {@code 254 | * remove} method is called on the iterator. If the iterator does not 255 | * support removing elements, an {@code UnsupportedOperationException} is 256 | * thrown. 257 | * 258 | * @param collection 259 | * the collection of objects to remove. 260 | * @return {@code true} if this {@code Collection} is modified, {@code false} 261 | * otherwise. 262 | * @throws UnsupportedOperationException 263 | * if removing from this {@code Collection} is not supported. 264 | * @throws ClassCastException 265 | * if one or more elements of {@code collection} isn't of the 266 | * correct type. 267 | * @throws NullPointerException 268 | * if {@code collection} contains at least one {@code null} 269 | * element and this {@code Collection} doesn't support {@code null} 270 | * elements. 271 | * @throws NullPointerException 272 | * if {@code collection} is {@code null}. 273 | */ 274 | public boolean removeAll(Collection collection) { 275 | boolean result = false; 276 | Iterator it = iterator(); 277 | while (it.hasNext()) { 278 | if (collection.contains(it.next())) { 279 | it.remove(); 280 | result = true; 281 | } 282 | } 283 | return result; 284 | } 285 | 286 | /** 287 | * Removes all objects from this {@code Collection} that are not also found in the 288 | * {@code Collection} passed (optional). After this method returns this {@code Collection} 289 | * will only contain elements that also can be found in the {@code Collection} 290 | * passed to this method. 291 | *

292 | * This implementation iterates over this {@code Collection} and tests for each 293 | * element {@code e} returned by the iterator, whether it is contained in 294 | * the specified {@code Collection}. If this test is negative, then the {@code 295 | * remove} method is called on the iterator. If the iterator does not 296 | * support removing elements, an {@code UnsupportedOperationException} is 297 | * thrown. 298 | * 299 | * @param collection 300 | * the collection of objects to retain. 301 | * @return {@code true} if this {@code Collection} is modified, {@code false} 302 | * otherwise. 303 | * @throws UnsupportedOperationException 304 | * if removing from this {@code Collection} is not supported. 305 | * @throws ClassCastException 306 | * if one or more elements of {@code collection} 307 | * isn't of the correct type. 308 | * @throws NullPointerException 309 | * if {@code collection} contains at least one 310 | * {@code null} element and this {@code Collection} doesn't support 311 | * {@code null} elements. 312 | * @throws NullPointerException 313 | * if {@code collection} is {@code null}. 314 | */ 315 | public boolean retainAll(Collection collection) { 316 | boolean result = false; 317 | Iterator it = iterator(); 318 | while (it.hasNext()) { 319 | if (!collection.contains(it.next())) { 320 | it.remove(); 321 | result = true; 322 | } 323 | } 324 | return result; 325 | } 326 | 327 | /** 328 | * Returns a count of how many objects this {@code Collection} contains. 329 | *

330 | * In this class this method is declared abstract and has to be implemented 331 | * by concrete {@code Collection} implementations. 332 | * 333 | * @return how many objects this {@code Collection} contains, or {@code Integer.MAX_VALUE} 334 | * if there are more than {@code Integer.MAX_VALUE} elements in this 335 | * {@code Collection}. 336 | */ 337 | public abstract int size(); 338 | 339 | public Object[] toArray() { 340 | int size = size(), index = 0; 341 | Iterator it = iterator(); 342 | Object[] array = new Object[size]; 343 | while (index < size) { 344 | array[index++] = it.next(); 345 | } 346 | return array; 347 | } 348 | 349 | @SuppressWarnings("unchecked") 350 | public T[] toArray(T[] contents) { 351 | int size = size(), index = 0; 352 | if (size > contents.length) { 353 | Class ct = contents.getClass().getComponentType(); 354 | contents = (T[]) Array.newInstance(ct, size); 355 | } 356 | for (E entry : this) { 357 | contents[index++] = (T) entry; 358 | } 359 | if (index < contents.length) { 360 | contents[index] = null; 361 | } 362 | return contents; 363 | } 364 | 365 | /** 366 | * Returns the string representation of this {@code Collection}. The presentation 367 | * has a specific format. It is enclosed by square brackets ("[]"). Elements 368 | * are separated by ', ' (comma and space). 369 | * 370 | * @return the string representation of this {@code Collection}. 371 | */ 372 | @Override 373 | public String toString() { 374 | if (isEmpty()) { 375 | return "[]"; 376 | } 377 | 378 | StringBuilder buffer = new StringBuilder(size() * 16); 379 | buffer.append('['); 380 | Iterator it = iterator(); 381 | while (it.hasNext()) { 382 | Object next = it.next(); 383 | if (next != this) { 384 | buffer.append(next); 385 | } else { 386 | buffer.append("(this Collection)"); 387 | } 388 | if (it.hasNext()) { 389 | buffer.append(", "); 390 | } 391 | } 392 | buffer.append(']'); 393 | return buffer.toString(); 394 | } 395 | } 396 | --------------------------------------------------------------------------------