diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..4694134 Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md index 0453824..fb875f5 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,61 @@ -# simple-android-opensource-framework -## 概述 -simple android opensource framework repository +# Android著名开源库的简版实现 +## 简述 +该项目通过分析并实现Android平台知名开源框架的简单版本来提升自我,并达到深入理解各大开源库的核心原理的目的。稳定、强大的开源库一般都较为复杂,比如Universal-ImageLoader,因此简版开源库不需要完全按照原版来实现,只需要把核心架构、原理实现,并且做到可运用到实际项目中即可。在实现开源库简版的同时,作者需要写一系列文章来剖析它的实现原理以及为什么要这么设计,在提升自我的同时将框架的设计与实现、领悟分享给他人,希望大家在提升自我的同时对行业做出一些贡献。 -## 开发规范 +Android平台有很多优秀的开源库,如果你对这些还不是很了解,可以参考Trinea的[android-open-project](https://github.com/Trinea/android-open-project)列举的知名开源库。对一些知名开源库的分析请参考Trinea的[android-open-project-analysis](https://github.com/android-cn/android-open-project-analysis)。 + +我想在你了解了一些开源库,并且学习了Trinea的对开源库分析的文章之后对于开源库的核心技术就有了一定的了解。此时你可以利用这些基础来重复造这些轮子,这些轮子不必很完善、稳定,只需要展示它的核心原理、设计,并且可用即可。这样从实战中学习这些开源库,不仅能够提升技术,也能够学习这些开源库的优秀设计。 + +如果你对面向对象不是很了解,那么在开始之前先学习一下[面向对象的六大原则](https://github.com/simple-android-framework-exchange/android_design_patterns_analysis/blob/master/oop-principles/oop-principles.md)是非常有必要的。 + + +**QQ交流群: 413864859,希望大家踊跃参与进来。** + + + +## 库的所属种类 +| 开源库类型 | 文件夹 | +| ------------- |:-------------:| +| 网络请求 | [network](network) | +| 数据库 | [orm](orm) | +| 图片加载 | [imageloader](imageloader) | +| view | [view](view) | +| 注入框架 | [inject](inject) | +| 兼容库 | [compatibility](compatibility) | +| 事件总线 | [eventbus](eventbus) | +| 其他 | [others](others) | + + + +## 开发规范简述 +[code-style.md](code-style.md) ## 如何参与 +1. 通过git将本库clone到本地; +2. 首先将自己要实现的库、完成时间(包括设计与实现的第一篇概括性文章的完成)等填写到[任务表](#schedule)中; +3. 在对应分类下创建库的目录,例如SimpleVolley,写代码实现开源库的简版,这个简版库需要可用; +4. 创建一个demo到该库的目录下,例如你要完成的库是SimpleVolley,那么你的demo的路径则为SimpleVolley/demo; +5. 将文章的图片统一放到库名/images目录下,例如SimpleVolley/images; +6. 按照[template.md](template.md)完成库的基本介绍,并且在后续的文章中对库进行详细分析。如果没有后续文章那么建议在该介绍文件中对库的核心实现、设计进行详细分析。 +7. 完成之后提交,并且push到该仓库当中。 +**注意,在开发过程中不要修改不属于自己的文件,避免在协作时产生冲突。** + ## 任务表 +### 一期任务 +| 原开源库名称 | 简版开源库名称 | 作者 | 分类 | 预计完成时间 | 进行状态 | +| ------------- | ------------- |:-------------:| ------------- | ------------- | ------------- | +| [Volley](https://github.com/mcxiaoke/android-volley) | [SimpleNet](network/SimpleNet) | [Mr.Simple](https://github.com/bboyfeiyu) | 网络请求 | 2015.3.5 | 文档未完成 | +| [ImageLoader](https://github.com/nostra13/Android-Universal-Image-Loader) | [SimpleImageLoader](https://github.com/bboyfeiyu/simple_imageloader) | [Mr.Simple](https://github.com/bboyfeiyu) | 图片加载 | 2015.3.15 | 代码完成 | +| [AndroidEventBus](https://github.com/bboyfeiyu/AndroidEventBus) | [AndroidEventBus](https://github.com/bboyfeiyu/AndroidEventBus) | [Mr.Simple](https://github.com/bboyfeiyu) | 其他 | 2015.3.25 | 代码完成 | +| [okhttp](https://github.com/square/okhttp) | 这里填写简版库的链接 | [CodeLife](https://github.com/xiaojianchen) | 网络请求 | 2015.4.10 | | +| [Retrofit](https://github.com/square/retrofit) | [SimpleRetrofit]() | [tiny-times](https://github.com/tiny-times) | 网络请求 | 2015.4.10 | | + + diff --git a/code-style.md b/code-style.md new file mode 100644 index 0000000..926ef63 --- /dev/null +++ b/code-style.md @@ -0,0 +1,88 @@ +# 编码规范 + +为了保持大家的代码一致性,进行一些代码格式的规范。 + +* 代码缩进使用4个空格,不是Tab键。 +* 统一使用UTF-8编码,避免乱码问题。 +* 类的命名规范: 如果是Android SDK提供的Android应用组成部分,那么类名应该是类的作用的英文全称或者缩写+ Android SDK基类的名字。 + +例子: +Activity类名字应该是 类似 MainActivity, NaviActivity (Navigation, 导航缩写Navi), TextActivity, BookActivity + +Service类名字缩写应该是类似 DownloadService, +每个类完成后应该有作者姓名和联系方式的注释,对自己的代码负责。如 + +``` +/** + * 类的介绍 + */ +public class DataBack { + // ... +} +``` + +* 变量命名 +变量的命名均要能够代表它的意义,即命名的字解释性。看如下示例: + +public变量的以小写字母开头,例如: +``` +public String userName ; +``` +其他访问权限的变量的格式为 : m+能够代表变量意义的字母, 例如 : +``` +private String mUserName ; +``` + +* 函数命名 +函数的命名均要能够代表它的意义,即命名的字解释性。例如 : + +``` +public void saveUserInfoToDB(User user) { + // code +} +``` +上面的函数一看基本上知道是保存用户信息到数据库中,即命名的字解释性。 + +* 大括号的排列 +在java中两个大括号的正确格式如下 : + +``` +if ( condition ) { + // code +} else if ( condition ) { + // +} + +``` +即两个括号并不对齐排列。 + +* 空格问题 +在条件判断、操作数、操作符之间都要添加空格,使得语句更为清晰。例如 : + +``` +int result = 10 + 23 - 100 / 4 ; + +``` +错误的形式为 : + +``` +int result=10+23-100/4 ; + +``` + +* 空行问题 +在函数之间需要添加一个空行,例如: + +``` + +private void setUserName(String aName) { + // +} + +private void setUserAge(int aAge) { + // +} +``` + +* 注释 +在类、函数、变量前面尽量加上相关的注释,当然如果你觉得你的命名具有足够的自解释性那可以免掉一些注释。但是建议在类的开头、重要的函数之前写一些介绍性、原理性注释。 \ No newline at end of file diff --git a/compatibility/README.md b/compatibility/README.md new file mode 100644 index 0000000..c6eec1a --- /dev/null +++ b/compatibility/README.md @@ -0,0 +1,13 @@ +# 任务表 +| 简版框架名称 | 作者 | 预计完成时间 | +| ------------- |:-------------:| ------------- | +| 这里指向你的框架文件夹 | [用户名](git地址) | 完成时间 | + + + + + + + + + diff --git a/eventbus/README.md b/eventbus/README.md new file mode 100644 index 0000000..c6eec1a --- /dev/null +++ b/eventbus/README.md @@ -0,0 +1,13 @@ +# 任务表 +| 简版框架名称 | 作者 | 预计完成时间 | +| ------------- |:-------------:| ------------- | +| 这里指向你的框架文件夹 | [用户名](git地址) | 完成时间 | + + + + + + + + + diff --git a/imageloader/README.md b/imageloader/README.md new file mode 100644 index 0000000..c6eec1a --- /dev/null +++ b/imageloader/README.md @@ -0,0 +1,13 @@ +# 任务表 +| 简版框架名称 | 作者 | 预计完成时间 | +| ------------- |:-------------:| ------------- | +| 这里指向你的框架文件夹 | [用户名](git地址) | 完成时间 | + + + + + + + + + diff --git a/inject/README.md b/inject/README.md new file mode 100644 index 0000000..c6eec1a --- /dev/null +++ b/inject/README.md @@ -0,0 +1,13 @@ +# 任务表 +| 简版框架名称 | 作者 | 预计完成时间 | +| ------------- |:-------------:| ------------- | +| 这里指向你的框架文件夹 | [用户名](git地址) | 完成时间 | + + + + + + + + + diff --git a/network/.DS_Store b/network/.DS_Store new file mode 100644 index 0000000..d964abb Binary files /dev/null and b/network/.DS_Store differ diff --git a/network/SimpleNet/.DS_Store b/network/SimpleNet/.DS_Store new file mode 100644 index 0000000..18f031f Binary files /dev/null and b/network/SimpleNet/.DS_Store differ diff --git a/network/SimpleNet/.classpath b/network/SimpleNet/.classpath new file mode 100644 index 0000000..ef51b09 --- /dev/null +++ b/network/SimpleNet/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/network/SimpleNet/.gitignore b/network/SimpleNet/.gitignore new file mode 100644 index 0000000..9068cd0 --- /dev/null +++ b/network/SimpleNet/.gitignore @@ -0,0 +1,26 @@ +# Built application files +*.apk +*.ap_ + +# Files for the Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log diff --git a/network/SimpleNet/.project b/network/SimpleNet/.project new file mode 100644 index 0000000..b5b6833 --- /dev/null +++ b/network/SimpleNet/.project @@ -0,0 +1,33 @@ + + + simple_net_framework + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/network/SimpleNet/.settings/org.eclipse.jdt.core.prefs b/network/SimpleNet/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..ef8a789 --- /dev/null +++ b/network/SimpleNet/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/network/SimpleNet/AndroidManifest.xml b/network/SimpleNet/AndroidManifest.xml new file mode 100644 index 0000000..9cb95dc --- /dev/null +++ b/network/SimpleNet/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/network/SimpleNet/LICENSE b/network/SimpleNet/LICENSE new file mode 100644 index 0000000..0ab9361 --- /dev/null +++ b/network/SimpleNet/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Mr.Simple + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/network/SimpleNet/README.md b/network/SimpleNet/README.md new file mode 100644 index 0000000..f965b43 --- /dev/null +++ b/network/SimpleNet/README.md @@ -0,0 +1,64 @@ +SimpleNet 的设计与实现 +==================================== +> 本文为 [Android著名开源库的简版实现](https://github.com/simple-android-framework-exchange/simple-android-opensource-framework) 中的 SimpleNet 的设计与实现 +> 原始开源库: [Volley](https://github.com/mcxiaoke/android-volley) +> 作者:[Mr.Simple](https://github.com/bboyfeiyu),开发状态:完成/未完成,校对者:[Mr.Simple](https://github.com/bboyfeiyu),校对状态:未开始 + + +## 1. 功能介绍 +SimpleNet是按照Volley的基本架构和核心原理来实现,其中省略掉了一些模块,比如CacheDispathcer等。SimpleNet能够执行网络请求,默认支持的请求类型有StringRequest、JsonRequest、MultipartRequest(可传递文件、图片参数),也可以参考上述几个类自定义请求。SimpleNet执行网络请求,并且将结果投递给UI线程。其他的一些核心概念跟Volley都非常的类型,我们在这里只是以重复造轮子的态度去学习轮子构建过程,从而达到能够造轮子的地步。 + +## 2. 总体设计 +![arch](http://img.blog.csdn.net/20150115142804901?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmJveWZlaXl1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) + +SimpleNet框架的基本结构类似于Volley,包括一些命名上也有跟Volley一致。它主要分为四个部分,最上面的部分为Request,即各种请求类型。例如返回的数据类型为json的对应为JsonRequest,返回数据字符串的为StringRequest,如果需要上传文件,那么你需要使用MultipartRequest,该请求只支持小文件的上传,如果上传的文件过大则会产生OOM。 + +第二部分为消息队列,消息队列维护了提交给网络框架的请求列表,并且根据相应的规则进行排序。默认情况下更具优先级和进入队列的顺序来执行,该队列使用的是线程安全的PriorityBlockingQueue,因为我们的队列会被并发的访问,因此需要保证访问的原子性。 + +第三部分是Executor,也就是网络的执行者。该Executor继承自Thread,在run方法中循环访问第二部分的请求队列,请求完成之后将结果投递给UI线程。为了更好的控制请求队列,例如请求排序、取消等操作,这里我们并没有使用线程池来操作,而是自行管理队列和Thread的形式,这样整个结构也变得更为灵活。 + +第四部分则是Response投递类,在第三部分的Executor中执行网络请求,Executor是Thread,但是我们并不能在主线程中更新UI,因此我们使用ResponseDelivery来封装Response的投递,保证Response执行在UI线程。 + +每个部分职责都相对单一,这样便于日后的升级和维护。 + + +## 3. 流程图 +![flow](images/simple_net_flow.jpg) + + +## 4. 详细设计 +### 4.1 核心类详细介绍 + +* SimpleNet : 网络请求队列创建工厂类; +* NetworkExecutor : 执行网络请求的子线程类,不断地从请求队列中读取请求,并且执行网络请求或者从缓存中获取结果,并且将结果回调给UI线程; +* RequestQueue : 网络请求队列; +* ResponseDelivery : 请求结果分发器,将结果投递给UI线程; +* HttpStack : 执行网络请求的接口; +* HttpClientStack : 使用HttpClient执行网络请求的HttpStack子类 ( api 9以下 ); +* HttpUrlConnStack : 使用HttpURLConnection执行网络请求的HttpStack子类 ( api 9及其以上 ); +* Request : 网络请求基类,是一个抽象的泛型类; +* Response : 请求结果类,封装了请求结果的各类信息以及结果实体的字节码数据; +* JsonRequest : 返回的数据类型是JsonObject的请求; +* StringRequest : 返回的数据类型是字符串的请求; +* MultipartRequest : 可传递文件、图片等参数的请求,返回的类型为String; +* HttpConfig : http请求配置的抽象类; + +SimpleNet将各个子模块分布在不同的包中,并且尽量降低与其他类型的耦合,使得整个结构清晰、简单。 + +SimpleNet,Request是一个抽象的泛型类,泛型类型就是返回的Response类型,例如StringRequest就是继承自Request。第二部分的RequestQueue依赖于Request,Request是抽象的,因此任何Request的子类都可以传递到请求队列中来,它依赖的是抽象Request,而不是具体的某个实现,因此保证了可扩展性。你可以自己实现自己所需的Request,例如大文件的上传Request。同理,第三部分的NetworkExecutor也只是依赖于Request抽象,但这里又引入了一个类型HttpStack,这个网络请求的真正执行者,有HttpClientStack和HttpUrlConnStack,两者分别为Apache的HttpClient和java的HttpURLConnection,关于这两者的区别请参考:Android访问网络,使用HttpURLConnection还是HttpClient?。HttpStack也是一个抽象,具体使用HttpClient还是HttpURLConnection则由运行系统版本来定,HttpStackFactory会根据系统版本给框架返回对应的HttpStack。最后的ResponseDelivery比较简单了,只是通过Handler将结果投递给UI线程执行,也就是执行RequestListener的onComplete方法,此时网络执行完成,用户即可在该方法中更新UI或者相关的其他的操作。 + 下面我们再看看SimpleNet的工程结构,如图所示。 + +| ![package](images/package.jpeg) | ![package](images/package-2.png) | +|--------|------| +||| + +这就是SimpleNet框架的基本结构了,如果期待下一篇博客的更新,就请顶个帖吧!谢谢~ + +### 4.2 类关系图 +![uml](images/uml.jpg) + + +##5. 杂谈 +该项目模仿Volley简单实现了一个网络请求框架,该库没有经过严格的测试,适合用于学习,不建议运用到项目中。当然你要是觉得没有什么问题,也可以在你的项目中使用。 +本篇文章,我们对SimpleNet做了一个简介,在后续的文章中我们再进行详细介绍,敬请期待。[SimpleNet的Request、Response类与请求队列](SimpleNet_Detail_1.md)、[SimleNet的Http请求分发与执行](SimpleNet_Detail_2.md)、[SimpleNet的请求配置与Response缓存](SimpleNet_Detail_3.md)。 + diff --git a/network/SimpleNet/SimpleNet_Demo/.classpath b/network/SimpleNet/SimpleNet_Demo/.classpath new file mode 100644 index 0000000..5176974 --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/network/SimpleNet/SimpleNet_Demo/.project b/network/SimpleNet/SimpleNet_Demo/.project new file mode 100644 index 0000000..6968579 --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/.project @@ -0,0 +1,33 @@ + + + SimpleNet_Demo + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/network/SimpleNet/SimpleNet_Demo/.settings/org.eclipse.jdt.core.prefs b/network/SimpleNet/SimpleNet_Demo/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..b080d2d --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/network/SimpleNet/SimpleNet_Demo/AndroidManifest.xml b/network/SimpleNet/SimpleNet_Demo/AndroidManifest.xml new file mode 100644 index 0000000..1de9fe1 --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/network/SimpleNet/SimpleNet_Demo/ic_launcher-web.png b/network/SimpleNet/SimpleNet_Demo/ic_launcher-web.png new file mode 100644 index 0000000..a18cbb4 Binary files /dev/null and b/network/SimpleNet/SimpleNet_Demo/ic_launcher-web.png differ diff --git a/network/SimpleNet/SimpleNet_Demo/proguard-project.txt b/network/SimpleNet/SimpleNet_Demo/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/network/SimpleNet/SimpleNet_Demo/project.properties b/network/SimpleNet/SimpleNet_Demo/project.properties new file mode 100644 index 0000000..b35d80a --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-21 +android.library.reference.1=.. diff --git a/network/SimpleNet/SimpleNet_Demo/res/drawable-hdpi/ic_launcher.png b/network/SimpleNet/SimpleNet_Demo/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..288b665 Binary files /dev/null and b/network/SimpleNet/SimpleNet_Demo/res/drawable-hdpi/ic_launcher.png differ diff --git a/network/SimpleNet/SimpleNet_Demo/res/drawable-mdpi/ic_launcher.png b/network/SimpleNet/SimpleNet_Demo/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..6ae570b Binary files /dev/null and b/network/SimpleNet/SimpleNet_Demo/res/drawable-mdpi/ic_launcher.png differ diff --git a/network/SimpleNet/SimpleNet_Demo/res/drawable-xhdpi/ic_launcher.png b/network/SimpleNet/SimpleNet_Demo/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..d4fb7cd Binary files /dev/null and b/network/SimpleNet/SimpleNet_Demo/res/drawable-xhdpi/ic_launcher.png differ diff --git a/network/SimpleNet/SimpleNet_Demo/res/drawable-xxhdpi/ic_launcher.png b/network/SimpleNet/SimpleNet_Demo/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..85a6081 Binary files /dev/null and b/network/SimpleNet/SimpleNet_Demo/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/network/SimpleNet/SimpleNet_Demo/res/layout/activity_main.xml b/network/SimpleNet/SimpleNet_Demo/res/layout/activity_main.xml new file mode 100644 index 0000000..9a058cf --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/res/layout/activity_main.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/network/SimpleNet/SimpleNet_Demo/res/values/strings.xml b/network/SimpleNet/SimpleNet_Demo/res/values/strings.xml new file mode 100644 index 0000000..2e232b8 --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/res/values/strings.xml @@ -0,0 +1,7 @@ + + + + SimpleNet_Demo + Hello world! + + diff --git a/network/SimpleNet/SimpleNet_Demo/res/values/styles.xml b/network/SimpleNet/SimpleNet_Demo/res/values/styles.xml new file mode 100644 index 0000000..6ce89c7 --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/res/values/styles.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/network/SimpleNet/SimpleNet_Demo/src/com/example/simplenet_demo/MainActivity.java b/network/SimpleNet/SimpleNet_Demo/src/com/example/simplenet_demo/MainActivity.java new file mode 100644 index 0000000..1cd2773 --- /dev/null +++ b/network/SimpleNet/SimpleNet_Demo/src/com/example/simplenet_demo/MainActivity.java @@ -0,0 +1,102 @@ + +package com.example.simplenet_demo; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.text.Html; +import android.widget.TextView; + +import org.simple.net.base.Request.HttpMethod; +import org.simple.net.base.Request.RequestListener; +import org.simple.net.core.RequestQueue; +import org.simple.net.core.SimpleNet; +import org.simple.net.entity.MultipartEntity; +import org.simple.net.requests.MultipartRequest; +import org.simple.net.requests.StringRequest; + +import java.io.ByteArrayOutputStream; +import java.io.File; + +/** + * SimpleNet简单示例 + * + * @author mrsimple + */ +public class MainActivity extends Activity { + + // 1、构建请求队列 + RequestQueue mQueue = SimpleNet.newRequestQueue(); + TextView mResultTv; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + mResultTv = (TextView) findViewById(R.id.result_tv); + sendStringRequest(); + } + + /** + * 发送GET请求,返回的是String类型的数据, 同理还有{@see JsonRequest}、{@see MultipartRequest} + */ + private void sendStringRequest() { + StringRequest request = new StringRequest(HttpMethod.GET, "http://www.baidu.com/", + new RequestListener() { + + @Override + public void onComplete(int stCode, String response, String errMsg) { + mResultTv.setText(Html.fromHtml(response)); + } + }); + + mQueue.addRequest(request); + } + + /** + * 发送MultipartRequest,可以传字符串参数、文件、Bitmap等参数,这种请求为POST类型 + */ + protected void sendMultiRequest() { + // 2、创建请求 + MultipartRequest multipartRequest = new MultipartRequest("你的url", + new RequestListener() { + @Override + public void onComplete(int stCode, String response, String errMsg) { + // 该方法执行在UI线程 + } + }); + + // 3、添加各种参数 + // 添加header + multipartRequest.addHeader("header-name", "value"); + + // 通过MultipartEntity来设置参数 + MultipartEntity multi = multipartRequest.getMultiPartEntity(); + // 文本参数 + multi.addStringPart("location", "模拟的地理位置"); + multi.addStringPart("type", "0"); + + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); + // 直接从上传Bitmap + multi.addBinaryPart("images", bitmapToBytes(bitmap)); + // 上传文件 + multi.addFilePart("imgfile", new File("storage/emulated/0/test.jpg")); + + // 4、将请求添加到队列中 + mQueue.addRequest(multipartRequest); + } + + private byte[] bitmapToBytes(Bitmap bitmap) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); + return stream.toByteArray(); + } + + @Override + protected void onDestroy() { + mQueue.stop(); + super.onDestroy(); + } +} diff --git a/network/SimpleNet/SimpleNet_Detail_1.md b/network/SimpleNet/SimpleNet_Detail_1.md new file mode 100644 index 0000000..1d3ddba --- /dev/null +++ b/network/SimpleNet/SimpleNet_Detail_1.md @@ -0,0 +1,2 @@ +SimpleNet的Request、Response类与请求队列 +--- diff --git a/network/SimpleNet/SimpleNet_Detail_2.md b/network/SimpleNet/SimpleNet_Detail_2.md new file mode 100644 index 0000000..cdb8cdf --- /dev/null +++ b/network/SimpleNet/SimpleNet_Detail_2.md @@ -0,0 +1,2 @@ +SimleNet的Http请求分发与执行 +--- diff --git a/network/SimpleNet/SimpleNet_Detail_3.md b/network/SimpleNet/SimpleNet_Detail_3.md new file mode 100644 index 0000000..7b2683c --- /dev/null +++ b/network/SimpleNet/SimpleNet_Detail_3.md @@ -0,0 +1,2 @@ +SimpleNet的请求配置与Response缓存 +--- diff --git a/network/SimpleNet/images/.DS_Store b/network/SimpleNet/images/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/network/SimpleNet/images/.DS_Store differ diff --git a/network/SimpleNet/images/package-2.png b/network/SimpleNet/images/package-2.png new file mode 100644 index 0000000..7ca3e84 Binary files /dev/null and b/network/SimpleNet/images/package-2.png differ diff --git a/network/SimpleNet/images/package.jpeg b/network/SimpleNet/images/package.jpeg new file mode 100644 index 0000000..71f6606 Binary files /dev/null and b/network/SimpleNet/images/package.jpeg differ diff --git a/network/SimpleNet/images/simple_net_flow.jpg b/network/SimpleNet/images/simple_net_flow.jpg new file mode 100644 index 0000000..b3c797b Binary files /dev/null and b/network/SimpleNet/images/simple_net_flow.jpg differ diff --git a/network/SimpleNet/images/uml.jpg b/network/SimpleNet/images/uml.jpg new file mode 100644 index 0000000..fbc4eb8 Binary files /dev/null and b/network/SimpleNet/images/uml.jpg differ diff --git a/network/SimpleNet/libs/android-support-v4.jar b/network/SimpleNet/libs/android-support-v4.jar new file mode 100644 index 0000000..f48d0da Binary files /dev/null and b/network/SimpleNet/libs/android-support-v4.jar differ diff --git a/network/SimpleNet/proguard-project.txt b/network/SimpleNet/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/network/SimpleNet/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/network/SimpleNet/project.properties b/network/SimpleNet/project.properties new file mode 100644 index 0000000..03d0617 --- /dev/null +++ b/network/SimpleNet/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-10 +android.library=true diff --git a/network/SimpleNet/res/drawable-hdpi/ic_launcher.png b/network/SimpleNet/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..96a442e Binary files /dev/null and b/network/SimpleNet/res/drawable-hdpi/ic_launcher.png differ diff --git a/network/SimpleNet/res/drawable-mdpi/ic_launcher.png b/network/SimpleNet/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..359047d Binary files /dev/null and b/network/SimpleNet/res/drawable-mdpi/ic_launcher.png differ diff --git a/network/SimpleNet/res/drawable-xhdpi/ic_launcher.png b/network/SimpleNet/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..71c6d76 Binary files /dev/null and b/network/SimpleNet/res/drawable-xhdpi/ic_launcher.png differ diff --git a/network/SimpleNet/res/values/strings.xml b/network/SimpleNet/res/values/strings.xml new file mode 100644 index 0000000..cb6953b --- /dev/null +++ b/network/SimpleNet/res/values/strings.xml @@ -0,0 +1,5 @@ + + + network_framework + + diff --git a/network/SimpleNet/simple_net_framework_test/.classpath b/network/SimpleNet/simple_net_framework_test/.classpath new file mode 100644 index 0000000..7698fe6 --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/network/SimpleNet/simple_net_framework_test/.project b/network/SimpleNet/simple_net_framework_test/.project new file mode 100644 index 0000000..aee806e --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/.project @@ -0,0 +1,34 @@ + + + simple_net_framework_test + + + simple_net_framework + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/network/SimpleNet/simple_net_framework_test/.settings/org.eclipse.jdt.core.prefs b/network/SimpleNet/simple_net_framework_test/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..b080d2d --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/network/SimpleNet/simple_net_framework_test/AndroidManifest.xml b/network/SimpleNet/simple_net_framework_test/AndroidManifest.xml new file mode 100644 index 0000000..e82b801 --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/network/SimpleNet/simple_net_framework_test/proguard-project.txt b/network/SimpleNet/simple_net_framework_test/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/network/SimpleNet/simple_net_framework_test/project.properties b/network/SimpleNet/simple_net_framework_test/project.properties new file mode 100644 index 0000000..3aedb2f --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-10 +android.library.reference.1=.. diff --git a/network/SimpleNet/simple_net_framework_test/res/drawable-hdpi/ic_launcher.png b/network/SimpleNet/simple_net_framework_test/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..96a442e Binary files /dev/null and b/network/SimpleNet/simple_net_framework_test/res/drawable-hdpi/ic_launcher.png differ diff --git a/network/SimpleNet/simple_net_framework_test/res/drawable-ldpi/ic_launcher.png b/network/SimpleNet/simple_net_framework_test/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 0000000..9923872 Binary files /dev/null and b/network/SimpleNet/simple_net_framework_test/res/drawable-ldpi/ic_launcher.png differ diff --git a/network/SimpleNet/simple_net_framework_test/res/drawable-mdpi/ic_launcher.png b/network/SimpleNet/simple_net_framework_test/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..359047d Binary files /dev/null and b/network/SimpleNet/simple_net_framework_test/res/drawable-mdpi/ic_launcher.png differ diff --git a/network/SimpleNet/simple_net_framework_test/res/drawable-xhdpi/ic_launcher.png b/network/SimpleNet/simple_net_framework_test/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..71c6d76 Binary files /dev/null and b/network/SimpleNet/simple_net_framework_test/res/drawable-xhdpi/ic_launcher.png differ diff --git a/network/SimpleNet/simple_net_framework_test/res/values/strings.xml b/network/SimpleNet/simple_net_framework_test/res/values/strings.xml new file mode 100644 index 0000000..34f0650 --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + Simple_net_framework_testTest + + diff --git a/network/SimpleNet/simple_net_framework_test/src/com/umeng/network/test/LURCacheTest.java b/network/SimpleNet/simple_net_framework_test/src/com/umeng/network/test/LURCacheTest.java new file mode 100644 index 0000000..1e6c7ee --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/src/com/umeng/network/test/LURCacheTest.java @@ -0,0 +1,103 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 Umeng, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.umeng.network.test; + +import android.support.v4.util.LruCache; +import android.test.AndroidTestCase; + +import org.apache.http.ProtocolVersion; +import org.apache.http.StatusLine; +import org.simple.net.base.Request; +import org.simple.net.base.Response; +import org.simple.net.base.Request.HttpMethod; +import org.simple.net.requests.StringRequest; + +public class LURCacheTest extends AndroidTestCase { + + /** + * Reponse缓存 + */ + private LruCache, Response> mResponseCache; + + protected void setUp() throws Exception { + super.setUp(); + initCache(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + private void initCache() { + mResponseCache = new LruCache, Response>(108 * 1024); + } + + public void testMultiRequestCache() { + + for (int i = 0; i < 20; i++) { + StringRequest request = new StringRequest(HttpMethod.GET, "http://url/" + i, null); + request.getParams().put("key-" + i, "value-1"); + request.getHeaders().put("header-" + i, "header-" + i); + Response response = new Response(mStatusLine); + mResponseCache.put(request, response); + } + + assertEquals(20, mResponseCache.size()); + + } + + public void testMultiRequestWithSame() { + + for (int i = 0; i < 20; i++) { + StringRequest request = new StringRequest(HttpMethod.GET, "http://url/", null); + request.getParams().put("key-1", "value-1"); + request.getHeaders().put("header-1", "header-1"); + Response response = new Response(mStatusLine); + mResponseCache.put(request, response); + } + + assertEquals(1, mResponseCache.size()); + + } + + StatusLine mStatusLine = new StatusLine() { + + @Override + public int getStatusCode() { + return 0; + } + + @Override + public String getReasonPhrase() { + return "msg"; + } + + @Override + public ProtocolVersion getProtocolVersion() { + return new ProtocolVersion("http", 1, 1); + } + }; + +} diff --git a/network/SimpleNet/simple_net_framework_test/src/com/umeng/network/test/RequestQueueTest.java b/network/SimpleNet/simple_net_framework_test/src/com/umeng/network/test/RequestQueueTest.java new file mode 100644 index 0000000..e92fb7d --- /dev/null +++ b/network/SimpleNet/simple_net_framework_test/src/com/umeng/network/test/RequestQueueTest.java @@ -0,0 +1,76 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 Umeng, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.umeng.network.test; + +import android.test.AndroidTestCase; + +import org.simple.net.base.Request.HttpMethod; +import org.simple.net.base.Request.RequestListener; +import org.simple.net.core.RequestQueue; +import org.simple.net.core.SimpleNet; +import org.simple.net.requests.StringRequest; + +public class RequestQueueTest extends AndroidTestCase { + + RequestQueue mQueue = SimpleNet.newRequestQueue(); + + protected void setUp() throws Exception { + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + mQueue.clear(); + } + + public void testMultiRequests() { + + for (int i = 0; i < 10; i++) { + StringRequest request = new StringRequest(HttpMethod.GET, "http://myhost.com/", null); + mQueue.addRequest(request); + } + + assertEquals(1, mQueue.getAllRequests().size()); + + } + + public void testMultiRequestsWithListeners() { + // 添加lisener + for (int i = 0; i < 10; i++) { + StringRequest request = new StringRequest(HttpMethod.GET, "http://myhost.com/", + new RequestListener() { + + @Override + public void onComplete(int stCode, String response, String errMsg) { + + } + }); + mQueue.addRequest(request); + } + + assertEquals(1, mQueue.getAllRequests().size()); + } + +} diff --git a/network/SimpleNet/src/org/simple/net/base/Request.java b/network/SimpleNet/src/org/simple/net/base/Request.java new file mode 100644 index 0000000..5630fbd --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/base/Request.java @@ -0,0 +1,333 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.base; + +import android.util.Log; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; + +/** + * 网络请求类. 注意GET和DELETE不能传递参数,因为其请求的性质所致,用户可以将参数构建到url后传递进来到Request中. + * + * @author mrsimple + * @param T为请求返回的数据类型 + */ +public abstract class Request implements Comparable> { + + /** + * http request method enum. + * + * @author mrsimple + */ + public static enum HttpMethod { + GET("GET"), + POST("POST"), + PUT("PUT"), + DELETE("DELETE"); + + /** http request type */ + private String mHttpMethod = ""; + + private HttpMethod(String method) { + mHttpMethod = method; + } + + @Override + public String toString() { + return mHttpMethod; + } + } + + /** + * 优先级枚举 + * + * @author mrsimple + */ + public static enum Priority { + LOW, + NORMAL, + HIGN, + IMMEDIATE + } + + /** + * Default encoding for POST or PUT parameters. See + * {@link #getParamsEncoding()}. + */ + public static final String DEFAULT_PARAMS_ENCODING = "UTF-8"; + /** + * Default Content-type + */ + public final static String HEADER_CONTENT_TYPE = "Content-Type"; + /** + * 请求序列号 + */ + protected int mSerialNum = 0; + /** + * 优先级默认设置为Normal + */ + protected Priority mPriority = Priority.NORMAL; + /** + * 是否取消该请求 + */ + protected boolean isCancel = false; + + /** 该请求是否应该缓存 */ + private boolean mShouldCache = true; + /** + * 请求Listener + */ + protected RequestListener mRequestListener; + /** + * 请求的url + */ + private String mUrl = ""; + /** + * 请求的方法 + */ + HttpMethod mHttpMethod = HttpMethod.GET; + + /** + * 请求的header + */ + private Map mHeaders = new HashMap(); + /** + * 请求参数 + */ + private Map mBodyParams = new HashMap(); + + /** + * @param method + * @param url + * @param listener + */ + public Request(HttpMethod method, String url, RequestListener listener) { + mHttpMethod = method; + mUrl = url; + mRequestListener = listener; + } + + public void addHeader(String name, String value) { + mHeaders.put(name, value); + } + + /** + * 从原生的网络请求中解析结果 + * + * @param response + * @return + */ + public abstract T parseResponse(Response response); + + /** + * 处理Response,该方法运行在UI线程. + * + * @param response + */ + public final void deliveryResponse(Response response) { + T result = parseResponse(response); + if (mRequestListener != null) { + int stCode = response != null ? response.getStatusCode() : -1; + String msg = response != null ? response.getMessage() : "unkown error"; + Log.e("", "### 执行回调 : stCode = " + stCode + ", result : " + result + ", err : " + msg); + mRequestListener.onComplete(stCode, result, msg); + } + } + + public String getUrl() { + return mUrl; + } + + public RequestListener getRequestListener() { + return mRequestListener; + } + + public int getSerialNumber() { + return mSerialNum; + } + + public void setSerialNumber(int mSerialNum) { + this.mSerialNum = mSerialNum; + } + + public Priority getPriority() { + return mPriority; + } + + public void setPriority(Priority mPriority) { + this.mPriority = mPriority; + } + + protected String getParamsEncoding() { + return DEFAULT_PARAMS_ENCODING; + } + + public String getBodyContentType() { + return "application/x-www-form-urlencoded; charset=" + getParamsEncoding(); + } + + public HttpMethod getHttpMethod() { + return mHttpMethod; + } + + public Map getHeaders() { + return mHeaders; + } + + public Map getParams() { + return mBodyParams; + } + + public boolean isHttps() { + return mUrl.startsWith("https"); + } + + /** + * 该请求是否应该缓存 + * + * @param shouldCache + */ + public void setShouldCache(boolean shouldCache) { + this.mShouldCache = shouldCache; + } + + public boolean shouldCache() { + return mShouldCache; + } + + public void cancel() { + isCancel = true; + } + + public boolean isCanceled() { + return isCancel; + } + + /** + * Returns the raw POST or PUT body to be sent. + * + * @throws AuthFailureError in the event of auth failure + */ + public byte[] getBody() { + Map params = getParams(); + if (params != null && params.size() > 0) { + return encodeParameters(params, getParamsEncoding()); + } + return null; + } + + /** + * Converts params into an application/x-www-form-urlencoded + * encoded string. + */ + private byte[] encodeParameters(Map params, String paramsEncoding) { + StringBuilder encodedParams = new StringBuilder(); + try { + for (Map.Entry entry : params.entrySet()) { + encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding)); + encodedParams.append('='); + encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding)); + encodedParams.append('&'); + } + return encodedParams.toString().getBytes(paramsEncoding); + } catch (UnsupportedEncodingException uee) { + throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee); + } + } + + @Override + public int compareTo(Request another) { + Priority myPriority = this.getPriority(); + Priority anotherPriority = another.getPriority(); + // 如果优先级相等,那么按照添加到队列的序列号顺序来执行 + return myPriority.equals(anotherPriority) ? this.getSerialNumber() + - another.getSerialNumber() + : myPriority.ordinal() - anotherPriority.ordinal(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mHeaders == null) ? 0 : mHeaders.hashCode()); + result = prime * result + ((mHttpMethod == null) ? 0 : mHttpMethod.hashCode()); + result = prime * result + ((mBodyParams == null) ? 0 : mBodyParams.hashCode()); + result = prime * result + ((mPriority == null) ? 0 : mPriority.hashCode()); + result = prime * result + (mShouldCache ? 1231 : 1237); + result = prime * result + ((mUrl == null) ? 0 : mUrl.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Request other = (Request) obj; + if (mHeaders == null) { + if (other.mHeaders != null) + return false; + } else if (!mHeaders.equals(other.mHeaders)) + return false; + if (mHttpMethod != other.mHttpMethod) + return false; + if (mBodyParams == null) { + if (other.mBodyParams != null) + return false; + } else if (!mBodyParams.equals(other.mBodyParams)) + return false; + if (mPriority != other.mPriority) + return false; + if (mShouldCache != other.mShouldCache) + return false; + if (mUrl == null) { + if (other.mUrl != null) + return false; + } else if (!mUrl.equals(other.mUrl)) + return false; + return true; + } + + /** + * 网络请求Listener + * + * @author mrsimple + * @param 请求的response类型 + */ + public static interface RequestListener { + /** + * 请求完成的回调 + * + * @param response + */ + public void onComplete(int stCode, T response, String errMsg); + } +} diff --git a/network/SimpleNet/src/org/simple/net/base/Response.java b/network/SimpleNet/src/org/simple/net/base/Response.java new file mode 100644 index 0000000..a7b6ff6 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/base/Response.java @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.base; + +import org.apache.http.HttpEntity; +import org.apache.http.ProtocolVersion; +import org.apache.http.StatusLine; +import org.apache.http.message.BasicHttpResponse; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +/** + * 请求结果类,继承自BasicHttpResponse,将结果存储在rawData中. + * + * @author mrsimple + */ +public class Response extends BasicHttpResponse { + + public byte[] rawData = new byte[0]; + + public Response(StatusLine statusLine) { + super(statusLine); + } + + public Response(ProtocolVersion ver, int code, String reason) { + super(ver, code, reason); + } + + @Override + public void setEntity(HttpEntity entity) { + super.setEntity(entity); + rawData = entityToBytes(getEntity()); + } + + public byte[] getRawData() { + return rawData; + } + + public int getStatusCode() { + return getStatusLine().getStatusCode(); + } + + public String getMessage() { + return getStatusLine().getReasonPhrase(); + } + + /** Reads the contents of HttpEntity into a byte[]. */ + private byte[] entityToBytes(HttpEntity entity) { + try { + return EntityUtils.toByteArray(entity); + } catch (IOException e) { + e.printStackTrace(); + } + return new byte[0]; + } +} diff --git a/network/SimpleNet/src/org/simple/net/cache/Cache.java b/network/SimpleNet/src/org/simple/net/cache/Cache.java new file mode 100644 index 0000000..2a4870e --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/cache/Cache.java @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.cache; + +/** + * 请求缓存接口 + * + * @author mrsimple + * @param key的类型 + * @param value类型 + */ +public interface Cache { + + public V get(K key); + + public void put(K key, V value); + + public void remove(K key); + +} diff --git a/network/SimpleNet/src/org/simple/net/cache/LruMemCache.java b/network/SimpleNet/src/org/simple/net/cache/LruMemCache.java new file mode 100644 index 0000000..a9e18e6 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/cache/LruMemCache.java @@ -0,0 +1,73 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.cache; + +import android.support.v4.util.LruCache; + +import org.simple.net.base.Response; + +/** + * 将请求结果缓存到内存中 + * + * @author mrsimple + */ +public class LruMemCache implements Cache { + + /** + * Reponse缓存 + */ + private LruCache mResponseCache; + + public LruMemCache() { + // 计算可使用的最大内存 + final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); + + // 取八分之一的可用内存作为缓存 + final int cacheSize = maxMemory / 8; + mResponseCache = new LruCache(cacheSize) { + + @Override + protected int sizeOf(String key, Response response) { + return response.rawData.length / 1024; + } + }; + + } + + @Override + public Response get(String key) { + return mResponseCache.get(key); + } + + @Override + public void put(String key, Response response) { + mResponseCache.put(key, response); + } + + @Override + public void remove(String key) { + mResponseCache.remove(key); + } +} diff --git a/network/SimpleNet/src/org/simple/net/config/HttpClientConfig.java b/network/SimpleNet/src/org/simple/net/config/HttpClientConfig.java new file mode 100644 index 0000000..4ef8707 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/config/HttpClientConfig.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.config; + +import org.apache.http.conn.ssl.SSLSocketFactory; + +/** + * 这是针对于使用HttpClientStack执行请求时为https请求配置的SSLSocketFactory类 + * + * @author mrsimple + */ +public class HttpClientConfig extends HttpConfig { + private static HttpClientConfig sConfig = new HttpClientConfig(); + SSLSocketFactory mSslSocketFactory; + + private HttpClientConfig() { + + } + + public static HttpClientConfig getConfig() { + return sConfig; + } + + /** + * 配置https请求的SSLSocketFactory与HostnameVerifier + * + * @param sslSocketFactory + * @param hostnameVerifier + */ + public void setHttpsConfig(SSLSocketFactory sslSocketFactory) { + mSslSocketFactory = sslSocketFactory; + } + + public SSLSocketFactory getSocketFactory() { + return mSslSocketFactory; + } +} diff --git a/network/SimpleNet/src/org/simple/net/config/HttpConfig.java b/network/SimpleNet/src/org/simple/net/config/HttpConfig.java new file mode 100644 index 0000000..5fb17ff --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/config/HttpConfig.java @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.config; + +/** + * http配置类 + * + * @author mrsimple + */ +public abstract class HttpConfig { + public String userAgent = "default"; + public int soTimeOut = 10000; + public int connTimeOut = 10000; +} diff --git a/network/SimpleNet/src/org/simple/net/config/HttpUrlConnConfig.java b/network/SimpleNet/src/org/simple/net/config/HttpUrlConnConfig.java new file mode 100644 index 0000000..fe37ff5 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/config/HttpUrlConnConfig.java @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.config; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSocketFactory; + +/** + * 这是针对于使用HttpUrlStack执行请求时为https请求设置的SSLSocketFactory和HostnameVerifier的配置类,参考 + * http://blog.csdn.net/xyz_lmn/article/details/8027334,http://www.cnblogs.com/ + * vus520/archive/2012/09/07/2674725.html, + * + * @author mrsimple + */ +public class HttpUrlConnConfig extends HttpConfig { + + private static HttpUrlConnConfig sConfig = new HttpUrlConnConfig(); + + private SSLSocketFactory mSslSocketFactory = null; + private HostnameVerifier mHostnameVerifier = null; + + private HttpUrlConnConfig() { + } + + public static HttpUrlConnConfig getConfig() { + return sConfig; + } + + /** + * 配置https请求的SSLSocketFactory与HostnameVerifier + * + * @param sslSocketFactory + * @param hostnameVerifier + */ + public void setHttpsConfig(SSLSocketFactory sslSocketFactory, + HostnameVerifier hostnameVerifier) { + mSslSocketFactory = sslSocketFactory; + mHostnameVerifier = hostnameVerifier; + } + + public HostnameVerifier getHostnameVerifier() { + return mHostnameVerifier; + } + + public SSLSocketFactory getSslSocketFactory() { + return mSslSocketFactory; + } + +} diff --git a/network/SimpleNet/src/org/simple/net/core/NetworkExecutor.java b/network/SimpleNet/src/org/simple/net/core/NetworkExecutor.java new file mode 100644 index 0000000..16b278e --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/core/NetworkExecutor.java @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.core; + +import android.util.Log; + +import org.simple.net.base.Request; +import org.simple.net.base.Response; +import org.simple.net.cache.Cache; +import org.simple.net.cache.LruMemCache; +import org.simple.net.httpstacks.HttpStack; + +import java.util.concurrent.BlockingQueue; + +/** + * 网络请求Executor,继承自Thread,从网络请求队列中循环读取请求并且执行 + * + * @author mrsimple + */ +final class NetworkExecutor extends Thread { + + /** + * 网络请求队列 + */ + private BlockingQueue> mRequestQueue; + /** + * 网络请求栈 + */ + private HttpStack mHttpStack; + /** + * 结果分发器,将结果投递到主线程 + */ + private static ResponseDelivery mResponseDelivery = new ResponseDelivery(); + /** + * 请求缓存 + */ + private static Cache mReqCache = new LruMemCache(); + /** + * 是否停止 + */ + private boolean isStop = false; + + public NetworkExecutor(BlockingQueue> queue, HttpStack httpStack) { + mRequestQueue = queue; + mHttpStack = httpStack; + } + + @Override + public void run() { + try { + while (!isStop) { + final Request request = mRequestQueue.take(); + if (request.isCanceled()) { + Log.d("### ", "### 取消执行了"); + continue; + } + Response response = null; + if (isUseCache(request)) { + // 从缓存中取 + response = mReqCache.get(request.getUrl()); + } else { + // 从网络上获取数据 + response = mHttpStack.performRequest(request); + // 如果该请求需要缓存,那么请求成功则缓存到mResponseCache中 + if (request.shouldCache() && isSuccess(response)) { + mReqCache.put(request.getUrl(), response); + } + } + + // 分发请求结果 + mResponseDelivery.deliveryResponse(request, response); + } + } catch (InterruptedException e) { + Log.i("", "### 请求分发器退出"); + } + + } + + private boolean isSuccess(Response response) { + return response != null && response.getStatusCode() == 200; + } + + private boolean isUseCache(Request request) { + return request.shouldCache() && mReqCache.get(request.getUrl()) != null; + } + + public void quit() { + isStop = true; + interrupt(); + } +} diff --git a/network/SimpleNet/src/org/simple/net/core/RequestQueue.java b/network/SimpleNet/src/org/simple/net/core/RequestQueue.java new file mode 100644 index 0000000..300044d --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/core/RequestQueue.java @@ -0,0 +1,135 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.core; + +import android.util.Log; + +import org.simple.net.base.Request; +import org.simple.net.httpstacks.HttpStack; +import org.simple.net.httpstacks.HttpStackFactory; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 请求队列, 使用优先队列,使得请求可以按照优先级进行处理. [ Thread Safe ] + * + * @author mrsimple + */ +public final class RequestQueue { + /** + * 请求队列 [ Thread-safe ] + */ + private BlockingQueue> mRequestQueue = new PriorityBlockingQueue>(); + /** + * 请求的序列化生成器 + */ + private AtomicInteger mSerialNumGenerator = new AtomicInteger(0); + + /** + * 默认的核心数 + */ + public static int DEFAULT_CORE_NUMS = Runtime.getRuntime().availableProcessors() + 1; + /** + * CPU核心数 + 1个分发线程数 + */ + private int mDispatcherNums = DEFAULT_CORE_NUMS; + /** + * NetworkExecutor,执行网络请求的线程 + */ + private NetworkExecutor[] mDispatchers = null; + /** + * Http请求的真正执行者 + */ + private HttpStack mHttpStack; + + /** + * @param coreNums 线程核心数 + * @param httpStack http执行器 + */ + protected RequestQueue(int coreNums, HttpStack httpStack) { + mDispatcherNums = coreNums; + mHttpStack = httpStack != null ? httpStack : HttpStackFactory.createHttpStack(); + } + + /** + * 启动NetworkExecutor + */ + private final void startNetworkExecutors() { + mDispatchers = new NetworkExecutor[mDispatcherNums]; + for (int i = 0; i < mDispatcherNums; i++) { + mDispatchers[i] = new NetworkExecutor(mRequestQueue, mHttpStack); + mDispatchers[i].start(); + } + } + + public void start() { + stop(); + startNetworkExecutors(); + } + + /** + * 停止NetworkExecutor + */ + public void stop() { + if (mDispatchers != null && mDispatchers.length > 0) { + for (int i = 0; i < mDispatchers.length; i++) { + mDispatchers[i].quit(); + } + } + } + + /** + * 不能重复添加请求 + * + * @param request + */ + public void addRequest(Request request) { + if (!mRequestQueue.contains(request)) { + request.setSerialNumber(this.generateSerialNumber()); + mRequestQueue.add(request); + } else { + Log.d("", "### 请求队列中已经含有"); + } + } + + public void clear() { + mRequestQueue.clear(); + } + + public BlockingQueue> getAllRequests() { + return mRequestQueue; + } + + /** + * 为每个请求生成一个系列号 + * + * @return 序列号 + */ + private int generateSerialNumber() { + return mSerialNumGenerator.incrementAndGet(); + } +} diff --git a/network/SimpleNet/src/org/simple/net/core/ResponseDelivery.java b/network/SimpleNet/src/org/simple/net/core/ResponseDelivery.java new file mode 100644 index 0000000..3528c9c --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/core/ResponseDelivery.java @@ -0,0 +1,70 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.core; + +import android.os.Handler; +import android.os.Looper; + +import org.simple.net.base.Request; +import org.simple.net.base.Response; + +import java.util.concurrent.Executor; + +/** + * 请求结果投递类,将请求结果投递给UI线程 + * + * @author mrsimple + */ +class ResponseDelivery implements Executor { + + /** + * 主线程的hander + */ + Handler mResponseHandler = new Handler(Looper.getMainLooper()); + + /** + * 处理请求结果,将其执行在UI线程 + * + * @param request + * @param response + */ + public void deliveryResponse(final Request request, final Response response) { + Runnable respRunnable = new Runnable() { + + @Override + public void run() { + request.deliveryResponse(response); + } + }; + + execute(respRunnable); + } + + @Override + public void execute(Runnable command) { + mResponseHandler.post(command); + } + +} diff --git a/network/SimpleNet/src/org/simple/net/core/SimpleNet.java b/network/SimpleNet/src/org/simple/net/core/SimpleNet.java new file mode 100644 index 0000000..5acafa3 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/core/SimpleNet.java @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.core; + +import org.simple.net.httpstacks.HttpStack; + +/** + * SimpleNet入口 + * @author mrsimple + */ +public final class SimpleNet { + /** + * 创建一个请求队列,NetworkExecutor数量为默认的数量 + * + * @return + */ + public static RequestQueue newRequestQueue() { + return newRequestQueue(RequestQueue.DEFAULT_CORE_NUMS); + } + + /** + * 创建一个请求队列,NetworkExecutor数量为coreNums + * + * @param coreNums + * @return + */ + public static RequestQueue newRequestQueue(int coreNums) { + return newRequestQueue(coreNums, null); + } + + /** + * 创建一个请求队列,NetworkExecutor数量为coreNums + * + * @param coreNums 线程数量 + * @param httpStack 网络执行者 + * @return + */ + public static RequestQueue newRequestQueue(int coreNums, HttpStack httpStack) { + RequestQueue queue = new RequestQueue(Math.max(0, coreNums), httpStack); + queue.start(); + return queue; + } +} diff --git a/network/SimpleNet/src/org/simple/net/entity/MultipartEntity.java b/network/SimpleNet/src/org/simple/net/entity/MultipartEntity.java new file mode 100644 index 0000000..56deaeb --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/entity/MultipartEntity.java @@ -0,0 +1,265 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.entity; + +import android.text.TextUtils; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.message.BasicHeader; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Random; + +/** + * POST报文格式请参考博客 : http://blog.csdn.net/bboyfeiyu/article/details/41863951. + *

+ * Android中的多参数类型的Entity实体类,用户可以使用该类来上传文件、文本参数、二进制参数, + * 不需要依赖于httpmime.jar来实现上传文件的功能. + *

+ * + * @author mrsimple + */ +public class MultipartEntity implements HttpEntity { + + private final static char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + .toCharArray(); + /** + * 换行符 + */ + private final String NEW_LINE_STR = "\r\n"; + private final String CONTENT_TYPE = "Content-Type: "; + private final String CONTENT_DISPOSITION = "Content-Disposition: "; + /** + * 文本参数和字符集 + */ + private final String TYPE_TEXT_CHARSET = "text/plain; charset=UTF-8"; + + /** + * 字节流参数 + */ + private final String TYPE_OCTET_STREAM = "application/octet-stream"; + /** + * 二进制参数 + */ + private final byte[] BINARY_ENCODING = "Content-Transfer-Encoding: binary\r\n\r\n".getBytes(); + /** + * 文本参数 + */ + private final byte[] BIT_ENCODING = "Content-Transfer-Encoding: 8bit\r\n\r\n".getBytes(); + + /** + * 分隔符 + */ + private String mBoundary = null; + /** + * 输出流 + */ + ByteArrayOutputStream mOutputStream = new ByteArrayOutputStream(); + + public MultipartEntity() { + this.mBoundary = generateBoundary(); + } + + /** + * 生成分隔符 + * + * @return + */ + private final String generateBoundary() { + final StringBuffer buf = new StringBuffer(); + final Random rand = new Random(); + for (int i = 0; i < 30; i++) { + buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]); + } + return buf.toString(); + } + + /** + * 参数开头的分隔符 + * + * @throws IOException + */ + private void writeFirstBoundary() throws IOException { + mOutputStream.write(("--" + mBoundary + "\r\n").getBytes()); + } + + /** + * 添加文本参数 + * + * @param key + * @param value + */ + public void addStringPart(final String paramName, final String value) { + writeToOutputStream(paramName, value.getBytes(), TYPE_TEXT_CHARSET, BIT_ENCODING, ""); + } + + /** + * 将数据写入到输出流中 + * + * @param key + * @param rawData + * @param type + * @param encodingBytes + * @param fileName + */ + private void writeToOutputStream(String paramName, byte[] rawData, String type, + byte[] encodingBytes, + String fileName) { + try { + writeFirstBoundary(); + mOutputStream.write((CONTENT_TYPE + type + NEW_LINE_STR).getBytes()); + mOutputStream + .write(getContentDispositionBytes(paramName, fileName)); + mOutputStream.write(encodingBytes); + mOutputStream.write(rawData); + mOutputStream.write(NEW_LINE_STR.getBytes()); + } catch (final IOException e) { + e.printStackTrace(); + } + } + + /** + * 添加二进制参数, 例如Bitmap的字节流参数 + * + * @param key + * @param rawData + */ + public void addBinaryPart(String paramName, final byte[] rawData) { + writeToOutputStream(paramName, rawData, TYPE_OCTET_STREAM, BINARY_ENCODING, "no-file"); + } + + /** + * 添加文件参数,可以实现文件上传功能 + * + * @param key + * @param file + */ + public void addFilePart(final String key, final File file) { + InputStream fin = null; + try { + fin = new FileInputStream(file); + writeFirstBoundary(); + final String type = CONTENT_TYPE + TYPE_OCTET_STREAM + NEW_LINE_STR; + mOutputStream.write(getContentDispositionBytes(key, file.getName())); + mOutputStream.write(type.getBytes()); + mOutputStream.write(BINARY_ENCODING); + + final byte[] tmp = new byte[4096]; + int len = 0; + while ((len = fin.read(tmp)) != -1) { + mOutputStream.write(tmp, 0, len); + } + mOutputStream.flush(); + } catch (final IOException e) { + e.printStackTrace(); + } finally { + closeSilently(fin); + } + } + + private void closeSilently(Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (final IOException e) { + e.printStackTrace(); + } + } + + private byte[] getContentDispositionBytes(String paramName, String fileName) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(CONTENT_DISPOSITION + "form-data; name=\"" + paramName + "\""); + // 文本参数没有filename参数,设置为空即可 + if (!TextUtils.isEmpty(fileName)) { + stringBuilder.append("; filename=\"" + + fileName + "\""); + } + + return stringBuilder.append(NEW_LINE_STR).toString().getBytes(); + } + + @Override + public long getContentLength() { + return mOutputStream.toByteArray().length; + } + + @Override + public Header getContentType() { + return new BasicHeader("Content-Type", "multipart/form-data; boundary=" + mBoundary); + } + + @Override + public boolean isChunked() { + return false; + } + + @Override + public boolean isRepeatable() { + return false; + } + + @Override + public boolean isStreaming() { + return false; + } + + @Override + public void writeTo(final OutputStream outstream) throws IOException { + // 参数最末尾的结束符 + final String endString = "--" + mBoundary + "--\r\n"; + // 写入结束符 + mOutputStream.write(endString.getBytes()); + // + outstream.write(mOutputStream.toByteArray()); + } + + @Override + public Header getContentEncoding() { + return null; + } + + @Override + public void consumeContent() throws IOException, + UnsupportedOperationException { + if (isStreaming()) { + throw new UnsupportedOperationException( + "Streaming entity does not implement #consumeContent()"); + } + } + + @Override + public InputStream getContent() { + return new ByteArrayInputStream(mOutputStream.toByteArray()); + } +} diff --git a/network/SimpleNet/src/org/simple/net/httpstacks/HttpClientStack.java b/network/SimpleNet/src/org/simple/net/httpstacks/HttpClientStack.java new file mode 100644 index 0000000..7073ecb --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/httpstacks/HttpClientStack.java @@ -0,0 +1,166 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.httpstacks; + +import android.net.http.AndroidHttpClient; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; +import org.simple.net.base.Request; +import org.simple.net.base.Response; +import org.simple.net.config.HttpClientConfig; + +import java.util.Map; + +/** + * api 9以下使用HttpClient执行网络请求, https配置参考http://jackyrong.iteye.com/blog/1606444 + * + * @author mrsimple + */ +public class HttpClientStack implements HttpStack { + + /** + * 使用HttpClient执行网络请求时的Https配置 + */ + HttpClientConfig mConfig = HttpClientConfig.getConfig(); + /** + * HttpClient + */ + HttpClient mHttpClient = AndroidHttpClient.newInstance(mConfig.userAgent); + + @Override + public Response performRequest(Request request) { + try { + HttpUriRequest httpRequest = createHttpRequest(request); + // 添加连接参数 + setConnectionParams(httpRequest); + // 添加header + addHeaders(httpRequest, request.getHeaders()); + // https配置 + configHttps(request); + // 执行请求 + HttpResponse response = mHttpClient.execute(httpRequest); + // 构建Response + Response rawResponse = new Response(response.getStatusLine()); + // 设置Entity + rawResponse.setEntity(response.getEntity()); + return rawResponse; + } catch (Exception e) { + } + + return null; + } + + /** + * 如果是https请求,则使用用户配置的SSLSocketFactory进行配置. + * + * @param request + */ + private void configHttps(Request request) { + SSLSocketFactory sslSocketFactory = mConfig.getSocketFactory(); + if (request.isHttps() && sslSocketFactory != null) { + Scheme sch = new Scheme("https", sslSocketFactory, 443); + mHttpClient.getConnectionManager().getSchemeRegistry().register(sch); + } + } + + /** + * 设置连接参数,这里比较简单啊.一些优化设置就没有写了. + * + * @param httpUriRequest + */ + private void setConnectionParams(HttpUriRequest httpUriRequest) { + HttpParams httpParams = httpUriRequest.getParams(); + HttpConnectionParams.setConnectionTimeout(httpParams, mConfig.connTimeOut); + HttpConnectionParams.setSoTimeout(httpParams, mConfig.soTimeOut); + } + + /** + * 根据请求类型创建不同的Http请求 + * + * @param request + * @return + */ + static HttpUriRequest createHttpRequest(Request request) { + HttpUriRequest httpUriRequest = null; + switch (request.getHttpMethod()) { + case GET: + httpUriRequest = new HttpGet(request.getUrl()); + break; + case DELETE: + httpUriRequest = new HttpDelete(request.getUrl()); + break; + case POST: { + httpUriRequest = new HttpPost(request.getUrl()); + httpUriRequest.addHeader(Request.HEADER_CONTENT_TYPE, request.getBodyContentType()); + setEntityIfNonEmptyBody((HttpPost) httpUriRequest, request); + } + break; + case PUT: { + httpUriRequest = new HttpPut(request.getUrl()); + httpUriRequest.addHeader(Request.HEADER_CONTENT_TYPE, request.getBodyContentType()); + setEntityIfNonEmptyBody((HttpPut) httpUriRequest, request); + } + break; + default: + throw new IllegalStateException("Unknown request method."); + } + + return httpUriRequest; + } + + private static void addHeaders(HttpUriRequest httpRequest, Map headers) { + for (String key : headers.keySet()) { + httpRequest.setHeader(key, headers.get(key)); + } + } + + /** + * 将请求参数设置到HttpEntity中 + * + * @param httpRequest + * @param request + */ + private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest, + Request request) { + byte[] body = request.getBody(); + if (body != null) { + HttpEntity entity = new ByteArrayEntity(body); + httpRequest.setEntity(entity); + } + } +} diff --git a/network/SimpleNet/src/org/simple/net/httpstacks/HttpStack.java b/network/SimpleNet/src/org/simple/net/httpstacks/HttpStack.java new file mode 100644 index 0000000..b7c3e6a --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/httpstacks/HttpStack.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.httpstacks; + +import org.simple.net.base.Request; +import org.simple.net.base.Response; + +/** + * 执行网络请求的接口 + * + * @author mrsimple + */ +public interface HttpStack { + /** + * 执行Http请求 + * + * @param request 待执行的请求 + * @return + */ + public Response performRequest(Request request); +} diff --git a/network/SimpleNet/src/org/simple/net/httpstacks/HttpStackFactory.java b/network/SimpleNet/src/org/simple/net/httpstacks/HttpStackFactory.java new file mode 100644 index 0000000..062ecb5 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/httpstacks/HttpStackFactory.java @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.httpstacks; + +import android.os.Build; + +/** + * 根据api版本选择HttpClient或者HttpURLConnection + * + * @author mrsimple + */ +public final class HttpStackFactory { + + private static final int GINGERBREAD_SDK_NUM = 9; + + /** + * 根据SDK版本号来创建不同的Http执行器,即SDK 9之前使用HttpClient,之后则使用HttlUrlConnection, + * 两者之间的差别请参考 : + * http://android-developers.blogspot.com/2011/09/androids-http-clients.html + * + * @return + */ + public static HttpStack createHttpStack() { + int runtimeSDKApi = Build.VERSION.SDK_INT; + if (runtimeSDKApi >= GINGERBREAD_SDK_NUM) { + return new HttpUrlConnStack(); + } + + return new HttpClientStack(); + } +} diff --git a/network/SimpleNet/src/org/simple/net/httpstacks/HttpUrlConnStack.java b/network/SimpleNet/src/org/simple/net/httpstacks/HttpUrlConnStack.java new file mode 100644 index 0000000..3386141 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/httpstacks/HttpUrlConnStack.java @@ -0,0 +1,190 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.httpstacks; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.ProtocolVersion; +import org.apache.http.StatusLine; +import org.apache.http.entity.BasicHttpEntity; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicHttpResponse; +import org.apache.http.message.BasicStatusLine; +import org.simple.net.base.Request; +import org.simple.net.base.Request.HttpMethod; +import org.simple.net.base.Response; +import org.simple.net.config.HttpUrlConnConfig; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.ProtocolException; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; + +/** + * 使用HttpURLConnection执行网络请求的HttpStack + * + * @author mrsimple + */ +public class HttpUrlConnStack implements HttpStack { + + /** + * 配置Https + */ + HttpUrlConnConfig mConfig = HttpUrlConnConfig.getConfig(); + + @Override + public Response performRequest(Request request) { + HttpURLConnection urlConnection = null; + try { + // 构建HttpURLConnection + urlConnection = createUrlConnection(request.getUrl()); + // 设置headers + setRequestHeaders(urlConnection, request); + // 设置Body参数 + setRequestParams(urlConnection, request); + // https 配置 + configHttps(request); + return fetchResponse(urlConnection); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (urlConnection != null) { + urlConnection.disconnect(); + } + } + return null; + } + + private HttpURLConnection createUrlConnection(String url) throws IOException { + URL newURL = new URL(url); + URLConnection urlConnection = newURL.openConnection(); + urlConnection.setConnectTimeout(mConfig.connTimeOut); + urlConnection.setReadTimeout(mConfig.soTimeOut); + urlConnection.setDoInput(true); + urlConnection.setUseCaches(false); + return (HttpURLConnection) urlConnection; + } + + private void configHttps(Request request) { + if (request.isHttps()) { + SSLSocketFactory sslFactory = mConfig.getSslSocketFactory(); + // 配置https + if (sslFactory != null) { + HttpsURLConnection.setDefaultSSLSocketFactory(sslFactory); + HttpsURLConnection.setDefaultHostnameVerifier(mConfig.getHostnameVerifier()); + } + + } + } + + private void setRequestHeaders(HttpURLConnection connection, Request request) { + Set headersKeys = request.getHeaders().keySet(); + for (String headerName : headersKeys) { + connection.addRequestProperty(headerName, request.getHeaders().get(headerName)); + } + } + + protected void setRequestParams(HttpURLConnection connection, Request request) + throws ProtocolException, IOException { + HttpMethod method = request.getHttpMethod(); + connection.setRequestMethod(method.toString()); + // add params + byte[] body = request.getBody(); + if (body != null) { + // enable output + connection.setDoOutput(true); + // set content type + connection + .addRequestProperty(Request.HEADER_CONTENT_TYPE, request.getBodyContentType()); + // write params data to connection + DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream()); + dataOutputStream.write(body); + dataOutputStream.close(); + } + } + + private Response fetchResponse(HttpURLConnection connection) throws IOException { + + // Initialize HttpResponse with data from the HttpURLConnection. + ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); + int responseCode = connection.getResponseCode(); + if (responseCode == -1) { + throw new IOException("Could not retrieve response code from HttpUrlConnection."); + } + // 状态行数据 + StatusLine responseStatus = new BasicStatusLine(protocolVersion, + connection.getResponseCode(), connection.getResponseMessage()); + // 构建response + Response response = new Response(responseStatus); + // 设置response数据 + response.setEntity(entityFromURLConnwction(connection)); + addHeadersToResponse(response, connection); + return response; + } + + /** + * 执行HTTP请求之后获取到其数据流,即返回请求结果的流 + * + * @param connection + * @return + */ + private HttpEntity entityFromURLConnwction(HttpURLConnection connection) { + BasicHttpEntity entity = new BasicHttpEntity(); + InputStream inputStream = null; + try { + inputStream = connection.getInputStream(); + } catch (IOException e) { + e.printStackTrace(); + inputStream = connection.getErrorStream(); + } + + // TODO : GZIP + entity.setContent(inputStream); + entity.setContentLength(connection.getContentLength()); + entity.setContentEncoding(connection.getContentEncoding()); + entity.setContentType(connection.getContentType()); + + return entity; + } + + private void addHeadersToResponse(BasicHttpResponse response, HttpURLConnection connection) { + for (Entry> header : connection.getHeaderFields().entrySet()) { + if (header.getKey() != null) { + Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); + response.addHeader(h); + } + } + } + +} diff --git a/network/SimpleNet/src/org/simple/net/requests/JsonRequest.java b/network/SimpleNet/src/org/simple/net/requests/JsonRequest.java new file mode 100644 index 0000000..5ef9cad --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/requests/JsonRequest.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.requests; + +import org.json.JSONException; +import org.json.JSONObject; +import org.simple.net.base.Request; +import org.simple.net.base.Response; + +/** + * 返回的数据类型为Json的请求, Json对应的对象类型为JSONObject + * + * @author mrsimple + */ +public class JsonRequest extends Request { + + public JsonRequest(HttpMethod method, String url, RequestListener listener) { + super(method, url, listener); + } + + + /** + * 将Response的结果转换为JSONObject + */ + @Override + public JSONObject parseResponse(Response response) { + String jsonString = new String(response.getRawData()); + try { + return new JSONObject(jsonString); + } catch (JSONException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/network/SimpleNet/src/org/simple/net/requests/MultipartRequest.java b/network/SimpleNet/src/org/simple/net/requests/MultipartRequest.java new file mode 100644 index 0000000..35edce7 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/requests/MultipartRequest.java @@ -0,0 +1,82 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.requests; + +import android.util.Log; + +import org.simple.net.base.Request; +import org.simple.net.base.Response; +import org.simple.net.entity.MultipartEntity; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Multipart请求 ( 只能为POST请求 ),该请求可以搭载多种类型参数,比如文本、文件等,但是文件仅限于小文件,否则会出现OOM异常. + * + * @author mrsimple + */ +public class MultipartRequest extends Request { + + MultipartEntity mMultiPartEntity = new MultipartEntity(); + + public MultipartRequest(String url, RequestListener listener) { + super(HttpMethod.POST, url, listener); + } + + /** + * @return + */ + public MultipartEntity getMultiPartEntity() { + return mMultiPartEntity; + } + + @Override + public String getBodyContentType() { + return mMultiPartEntity.getContentType().getValue(); + } + + @Override + public byte[] getBody() { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try { + // 将MultipartEntity中的参数写入到bos中 + mMultiPartEntity.writeTo(bos); + } catch (IOException e) { + Log.e("", "IOException writing to ByteArrayOutputStream"); + } + return bos.toByteArray(); + } + + @Override + public String parseResponse(Response response) { + if (response != null && response.getRawData() != null) { + return new String(response.getRawData()); + } + + return ""; + } + +} diff --git a/network/SimpleNet/src/org/simple/net/requests/StringRequest.java b/network/SimpleNet/src/org/simple/net/requests/StringRequest.java new file mode 100644 index 0000000..28f2765 --- /dev/null +++ b/network/SimpleNet/src/org/simple/net/requests/StringRequest.java @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2015 bboyfeiyu@gmail.com, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.simple.net.requests; + +import org.simple.net.base.Request; +import org.simple.net.base.Response; + +public class StringRequest extends Request { + + public StringRequest(HttpMethod method, String url, RequestListener listener) { + super(method, url, listener); + } + + @Override + public String parseResponse(Response response) { + return new String(response.getRawData()); + } + +} diff --git a/orm/README.md b/orm/README.md new file mode 100644 index 0000000..648ebb5 --- /dev/null +++ b/orm/README.md @@ -0,0 +1,13 @@ +# 任务表 +| 开源框架名称 | 作者 | 预计完成时间 | +| ------------- |:-------------:| ------------- | +| | [用户名](git地址) | 完成时间 | + + + + + + + + + diff --git a/others/README.md b/others/README.md new file mode 100644 index 0000000..c6eec1a --- /dev/null +++ b/others/README.md @@ -0,0 +1,13 @@ +# 任务表 +| 简版框架名称 | 作者 | 预计完成时间 | +| ------------- |:-------------:| ------------- | +| 这里指向你的框架文件夹 | [用户名](git地址) | 完成时间 | + + + + + + + + + diff --git a/template.md b/template.md new file mode 100644 index 0000000..ca140d4 --- /dev/null +++ b/template.md @@ -0,0 +1,52 @@ +${简版开源库} 的设计与实现 +==================================== +> 本文为 [Android著名开源库的简版实现](https://github.com/simple-android-framework-exchange/simple-android-opensource-framework) 中的 ${简版开源库} 的设计与实现 +> 原始开源库: [${原始开源库名称}](链接) +> 作者:[作者用户名](作者github链接),开发状态:完成/未完成,校对者:[等待管理员填写](),校对状态:未开始 + + +建议大家看下 [SimpleNet](network/SimpleNet/README.md),了解应该写到什么程度,以及类似流程图和总体设计该怎么做。当然,如果你只想写README.md一篇介绍,那么该文档中必须包含详细的设计与源码实现介绍,阐述其核心原理。如果你的README.md只是一篇介绍性文档,那么后续必须增加其他阐述核心原理的其他文档。 + +`复制一份到自己的项目文件夹下,然后根据自己项目替换掉 ${} 内容,删掉本行及上面两行。` + +## 1. 功能介绍 +功能介绍,包括功能或优点等 + + +## 2. 总体设计 +整个库分为哪些模块及模块之间的调用关系。 +- 如大多数图片缓存会分为 Loader 和 Processer 等模块。 +- 可使用 [Google Drawing](https://docs.google.com/drawings)、[Visio](http://products.office.com/en-us/visio/flowchart-software)、[StarUML](http://staruml.io/) 等工具完成,其他工具推荐?? +- 非所有项目必须,不需要的请先在群里反馈。 + + +## 3. 流程图 +主要功能流程图 + +- 如 Retrofit、Volley 的请求处理流程,Android-Universal-Image-Loader 的图片处理流程图 +- 可使用 [Google Drawing](https://docs.google.com/drawings)、[Visio](http://products.office.com/en-us/visio/flowchart-software)、[StarUML](http://staruml.io/) 等工具完成,其他工具推荐?? +- 非所有项目必须,不需要的请先在群里反馈 + + + + +## 4. 详细设计 +### 4.1 核心类详细介绍 + +类及其主要函数功能介绍、核心功能流程图,流程图可使用 [Google Drawing](https://docs.google.com/drawings)、[Visio](http://products.office.com/en-us/visio/flowchart-software)、[StarUML](http://staruml.io/)。 + + +### 4.2 类关系图 +类关系图,类的继承、组合关系图,可是用 [StarUML](http://staruml.io/) 工具。 + + + + +##5. 杂谈 +该项目存在的问题、可优化点及类似功能项目对比等,非所有项目必须。 + + + + +`写完相关内容之后到开发群告知管理员,管理员安排相关人员进行审核,审核通过之后即可。` + diff --git a/view/README.md b/view/README.md new file mode 100644 index 0000000..c6eec1a --- /dev/null +++ b/view/README.md @@ -0,0 +1,13 @@ +# 任务表 +| 简版框架名称 | 作者 | 预计完成时间 | +| ------------- |:-------------:| ------------- | +| 这里指向你的框架文件夹 | [用户名](git地址) | 完成时间 | + + + + + + + + +