├── AndroidDemos
├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values
│ │ │ │ │ ├── dimens.xml
│ │ │ │ │ ├── styles.xml
│ │ │ │ │ └── strings.xml
│ │ │ │ ├── values-w820dp
│ │ │ │ │ └── dimens.xml
│ │ │ │ └── layout
│ │ │ │ │ ├── activity_item_list.xml
│ │ │ │ │ └── activity_log_display.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── zhangtielei
│ │ │ │ │ └── demos
│ │ │ │ │ └── async
│ │ │ │ │ └── programming
│ │ │ │ │ ├── multitask
│ │ │ │ │ ├── pagecaching
│ │ │ │ │ │ ├── model
│ │ │ │ │ │ │ ├── HttpRequest.java
│ │ │ │ │ │ │ └── HttpResponse.java
│ │ │ │ │ │ ├── localcache
│ │ │ │ │ │ │ ├── LocalDataCache.java
│ │ │ │ │ │ │ └── mock
│ │ │ │ │ │ │ │ └── MockLocalDataCache.java
│ │ │ │ │ │ └── PageCachingDemoActivity.java
│ │ │ │ │ ├── simultaneousrequests
│ │ │ │ │ │ └── model
│ │ │ │ │ │ │ ├── HttpRequest1.java
│ │ │ │ │ │ │ ├── HttpRequest2.java
│ │ │ │ │ │ │ ├── HttpResponse1.java
│ │ │ │ │ │ │ └── HttpResponse2.java
│ │ │ │ │ ├── multilevelcaching
│ │ │ │ │ │ ├── memcache
│ │ │ │ │ │ │ ├── ImageMemCache.java
│ │ │ │ │ │ │ └── mock
│ │ │ │ │ │ │ │ └── MockImageMemCache.java
│ │ │ │ │ │ ├── ImageLoader.java
│ │ │ │ │ │ ├── diskcache
│ │ │ │ │ │ │ ├── ImageDiskCache.java
│ │ │ │ │ │ │ └── mock
│ │ │ │ │ │ │ │ └── MockImageDiskCache.java
│ │ │ │ │ │ ├── ImageLoaderListener.java
│ │ │ │ │ │ └── ImageLoaderDemoActivity.java
│ │ │ │ │ ├── http
│ │ │ │ │ │ ├── HttpListener.java
│ │ │ │ │ │ ├── HttpService.java
│ │ │ │ │ │ ├── HttpResult.java
│ │ │ │ │ │ └── mock
│ │ │ │ │ │ │ └── MockHttpService.java
│ │ │ │ │ └── MultiTaskDemoListActivity.java
│ │ │ │ │ ├── common
│ │ │ │ │ ├── AsyncCallback.java
│ │ │ │ │ └── utils
│ │ │ │ │ │ └── TextLogUtil.java
│ │ │ │ │ ├── callback
│ │ │ │ │ ├── emoji
│ │ │ │ │ │ ├── EmojiPackage.java
│ │ │ │ │ │ ├── EmojiDownloadContext.java
│ │ │ │ │ │ ├── EmojiDownloader.java
│ │ │ │ │ │ ├── v4
│ │ │ │ │ │ │ ├── EmojiDownloadDemoActivity.java
│ │ │ │ │ │ │ └── MyEmojiDownloader.java
│ │ │ │ │ │ ├── v1
│ │ │ │ │ │ │ ├── EmojiDownloadDemoActivity.java
│ │ │ │ │ │ │ └── MyEmojiDownloader.java
│ │ │ │ │ │ ├── v2
│ │ │ │ │ │ │ ├── EmojiDownloadDemoActivity.java
│ │ │ │ │ │ │ └── MyEmojiDownloader.java
│ │ │ │ │ │ ├── EmojiDownloadDemoListActivity.java
│ │ │ │ │ │ └── v3
│ │ │ │ │ │ │ ├── EmojiDownloadDemoActivity.java
│ │ │ │ │ │ │ └── MyEmojiDownloader.java
│ │ │ │ │ └── download
│ │ │ │ │ │ ├── v3_simplified
│ │ │ │ │ │ ├── MyDownloader.java
│ │ │ │ │ │ ├── Downloader.java
│ │ │ │ │ │ ├── DownloadListener.java
│ │ │ │ │ │ └── CallbackHellExample.java
│ │ │ │ │ │ ├── v2
│ │ │ │ │ │ ├── Downloader.java
│ │ │ │ │ │ ├── DownloadListener.java
│ │ │ │ │ │ └── MyDownloader.java
│ │ │ │ │ │ ├── v1
│ │ │ │ │ │ ├── Downloader.java
│ │ │ │ │ │ └── DownloadListener.java
│ │ │ │ │ │ └── v3
│ │ │ │ │ │ ├── Downloader.java
│ │ │ │ │ │ ├── DownloadListener.java
│ │ │ │ │ │ └── MyDownloader.java
│ │ │ │ │ ├── queueing
│ │ │ │ │ ├── v1
│ │ │ │ │ │ ├── Task.java
│ │ │ │ │ │ ├── TaskQueue.java
│ │ │ │ │ │ ├── TaskQueueDemoActivity.java
│ │ │ │ │ │ └── TSQBasedTaskQueue.java
│ │ │ │ │ ├── v3
│ │ │ │ │ │ ├── TaskQueue.java
│ │ │ │ │ │ ├── Task.java
│ │ │ │ │ │ ├── mock
│ │ │ │ │ │ │ └── MockAsyncTask.java
│ │ │ │ │ │ ├── TaskQueueDemoActivity.java
│ │ │ │ │ │ └── RxJavaBasedTaskQueue.java
│ │ │ │ │ ├── v2
│ │ │ │ │ │ ├── TaskQueue.java
│ │ │ │ │ │ ├── Task.java
│ │ │ │ │ │ ├── TaskQueueDemoActivity.java
│ │ │ │ │ │ ├── mock
│ │ │ │ │ │ │ └── MockAsyncTask.java
│ │ │ │ │ │ └── CallbackBasedTaskQueue.java
│ │ │ │ │ └── QueueingDemoListActivity.java
│ │ │ │ │ ├── introduction
│ │ │ │ │ └── servicebinding
│ │ │ │ │ │ ├── service
│ │ │ │ │ │ └── SomeService.java
│ │ │ │ │ │ └── ServiceBindingDemoActivity.java
│ │ │ │ │ └── MainActivity.java
│ │ │ └── AndroidManifest.xml
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── zhangtielei
│ │ │ └── demos
│ │ │ └── async
│ │ │ └── programming
│ │ │ └── ApplicationTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
├── settings.gradle
├── .gitignore
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── build.gradle
├── gradle.properties
├── gradlew.bat
└── gradlew
├── iOSDemos
├── iOSDemos.xcodeproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── iOSDemos
│ ├── ViewController.h
│ ├── ServerConnection.h
│ ├── ReachabiityTestViewController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── ViewController.m
│ ├── ReachabiityTestViewController.m
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Reachability.h
│ ├── Info.plist
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── ServerConnection.m
│ ├── AppDelegate.m
│ └── Reachability.m
└── README.md
/AndroidDemos/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/AndroidDemos/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/AndroidDemos/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/*
4 | *.iml
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/AndroidDemos/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tielei/AsyncProgrammingDemos/HEAD/AndroidDemos/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tielei/AsyncProgrammingDemos/HEAD/AndroidDemos/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tielei/AsyncProgrammingDemos/HEAD/AndroidDemos/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tielei/AsyncProgrammingDemos/HEAD/AndroidDemos/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tielei/AsyncProgrammingDemos/HEAD/AndroidDemos/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AndroidDemos/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // iOSDemos
4 | //
5 | // Created by Charles Zhang on 16/8/16.
6 | // Copyright © 2016年 tielei. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/ServerConnection.h:
--------------------------------------------------------------------------------
1 | //
2 | // ServerConnection.h
3 | // MyBlogAsyncTaskSeriesDemos
4 | //
5 | // Created by Charles Zhang on 3/27/16.
6 | // Copyright © 2016 tielei. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ServerConnection : NSObject
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/ReachabiityTestViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ReachabiityTestViewController.h
3 | // MyBlogAsyncTaskSeriesDemos
4 | //
5 | // Created by Charles Zhang on 3/27/16.
6 | // Copyright © 2016 tielei. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ReachabiityTestViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // iOSDemos
4 | //
5 | // Created by Charles Zhang on 16/8/16.
6 | // Copyright © 2016年 tielei. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // iOSDemos
4 | //
5 | // Created by Charles Zhang on 16/8/16.
6 | // Copyright © 2016年 tielei. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/androidTest/java/com/zhangtielei/demos/async/programming/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.zhangtielei.demos.async.programming;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/AndroidDemos/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.0.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // iOSDemos
4 | //
5 | // Created by Charles Zhang on 16/8/16.
6 | // Copyright © 2016年 tielei. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | @interface ViewController ()
12 |
13 | @end
14 |
15 | @implementation ViewController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | // Do any additional setup after loading the view, typically from a nib.
20 | }
21 |
22 | - (void)didReceiveMemoryWarning {
23 | [super didReceiveMemoryWarning];
24 | // Dispose of any resources that can be recreated.
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/ReachabiityTestViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // MyViewController.m
3 | // MyBlogAsyncTaskSeriesDemos
4 | //
5 | // Created by Charles Zhang on 3/27/16.
6 | // Copyright © 2016 tielei. All rights reserved.
7 | //
8 |
9 | #import "ReachabiityTestViewController.h"
10 | #import "ServerConnection.h"
11 |
12 | @interface ReachabiityTestViewController () {
13 | ServerConnection *serverConnection;
14 | }
15 |
16 | @end
17 |
18 | @implementation ReachabiityTestViewController
19 |
20 |
21 | - (void)awakeFromNib {
22 | [super awakeFromNib];
23 |
24 | serverConnection = [[ServerConnection alloc] init];
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/AndroidDemos/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/charleszhang/Documents/sdk/android-sdk-macosx/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AsyncProgrammingDemos
2 | Demo code for Tielei's Blog about async programming in Android & iOS.
3 |
4 | [《Android和iOS开发中的异步处理》](http://zhangtielei.com/posts/blog-series-async-task-1.html)
5 |
6 | License
7 | =======
8 |
9 | Copyright 2016 Tielei Zhang (zhangtielei.com).
10 |
11 | Licensed under the Apache License, Version 2.0 (the "License");
12 | you may not use this file except in compliance with the License.
13 | You may obtain a copy of the License at
14 |
15 | http://www.apache.org/licenses/LICENSE-2.0
16 |
17 | Unless required by applicable law or agreed to in writing, software
18 | distributed under the License is distributed on an "AS IS" BASIS,
19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 | See the License for the specific language governing permissions and
21 | limitations under the License.
--------------------------------------------------------------------------------
/AndroidDemos/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/Reachability.h:
--------------------------------------------------------------------------------
1 | //
2 | // Reachability.h
3 | // MyBlogAsyncTaskSeriesDemos
4 | //
5 | // Created by Charles Zhang on 16/3/24.
6 | // Copyright © 2016年 tielei. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import
12 |
13 | extern NSString *const networkStatusNotificationInfoKey;
14 |
15 | extern NSString *const kReachabilityChangedNotification;
16 |
17 |
18 | typedef NS_ENUM(uint32_t, NetworkStatus) {
19 | NotReachable = 0,
20 | ReachableViaWiFi = 1,
21 | ReachableViaWWAN = 2
22 | };
23 |
24 | @interface Reachability : NSObject {
25 | @private
26 | SCNetworkReachabilityRef reachabilityRef;
27 | }
28 |
29 | /**
30 | * 开始网络状态监听
31 | */
32 | - (BOOL)startNetworkMonitoring;
33 | /**
34 | * 结束网络状态监听
35 | */
36 | - (BOOL)stopNetworkMonitoring;
37 | /**
38 | * 同步获取当前网络状态
39 | */
40 | - (NetworkStatus) currentNetworkStatus;
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 | 16dp
20 | 16dp
21 |
22 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/pagecaching/model/HttpRequest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.pagecaching.model;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/5/17.
21 | */
22 | public class HttpRequest {
23 | }
24 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/pagecaching/model/HttpResponse.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.pagecaching.model;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/5/17.
21 | */
22 | public class HttpResponse {
23 | }
24 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/simultaneousrequests/model/HttpRequest1.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.model;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/17.
20 | */
21 | public class HttpRequest1 {
22 | }
23 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/simultaneousrequests/model/HttpRequest2.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.model;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/5/17.
21 | */
22 | public class HttpRequest2 {
23 | }
24 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/common/AsyncCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.common;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/5/17.
21 | *
22 | * 一个通用的回调接口定义. 用于返回一个参数.
23 | * @param 异步接口返回的参数数据类型.
24 | */
25 | public interface AsyncCallback {
26 | void onResult(D data);
27 | }
28 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
21 | 64dp
22 |
23 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/EmojiPackage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.emoji;
17 |
18 | import java.util.List;
19 |
20 | /**
21 | * Created by Tielei Zhang on 16/5/1.
22 | * 表情包数据结构.
23 | *
24 | */
25 | public class EmojiPackage {
26 | /**
27 | * 表情包ID
28 | */
29 | public long emojiId;
30 | /**
31 | * 表情包图片列表
32 | */
33 | public List emojiUrls;
34 | }
35 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v3_simplified/MyDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v3_simplified;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/11.
20 | * 下载器的实现(stub).
21 | */
22 | public class MyDownloader implements Downloader {
23 | @Override
24 | public void startDownload(String url, String localPath, Object contextData, DownloadListener listener) {
25 | //TODO:
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/multilevelcaching/memcache/ImageMemCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.multilevelcaching.memcache;
18 |
19 | import android.graphics.Bitmap;
20 |
21 | /**
22 | * Created by Tielei Zhang on 16/5/17.
23 | *
24 | * 图片Memory缓存.
25 | * 由于是内存操作, 采用同步接口.
26 | */
27 | public interface ImageMemCache {
28 | Bitmap getImage(String key);
29 | boolean putImage(String key, Bitmap bitmap);
30 | }
31 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/simultaneousrequests/model/HttpResponse1.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.model;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/17.
20 | */
21 | public class HttpResponse1 {
22 | private String text;
23 |
24 | public String getText() {
25 | return text;
26 | }
27 |
28 | public void setText(String text) {
29 | this.text = text;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/simultaneousrequests/model/HttpResponse2.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.model;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/5/17.
21 | */
22 | public class HttpResponse2 {
23 | private String text;
24 |
25 | public String getText() {
26 | return text;
27 | }
28 |
29 | public void setText(String text) {
30 | this.text = text;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/AndroidDemos/app/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | }
5 | dependencies {
6 | classpath 'com.android.tools.build:gradle:2.0.0'
7 | }
8 | }
9 | apply plugin: 'com.android.application'
10 |
11 | repositories {
12 | jcenter()
13 | }
14 |
15 | android {
16 | compileSdkVersion 23
17 | buildToolsVersion "23.0.3"
18 |
19 | defaultConfig {
20 | applicationId "com.zhangtielei.demos.async.programming"
21 | minSdkVersion 9
22 | targetSdkVersion 23
23 | versionCode 1
24 | versionName "1.0"
25 | }
26 |
27 | compileOptions {
28 | sourceCompatibility JavaVersion.VERSION_1_6
29 | targetCompatibility JavaVersion.VERSION_1_6
30 | }
31 | buildTypes {
32 | release {
33 | minifyEnabled false
34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
35 | }
36 | }
37 | }
38 |
39 | dependencies {
40 | compile fileTree(dir: 'libs', include: ['*.jar'])
41 | compile 'com.android.support:appcompat-v7:23.2.1'
42 | compile 'io.reactivex:rxandroid:1.2.0'
43 | compile 'io.reactivex:rxjava:1.1.9'
44 | }
45 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v1/Task.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v1;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/8/31.
21 | *
22 | * 供任务队列执行的同步任务接口定义.
23 | */
24 | public interface Task {
25 | /**
26 | * 唯一标识当前任务的ID
27 | * @return
28 | */
29 | String getTaskId();
30 |
31 | /**
32 | * 同步执行任务.
33 | * 如果执行出错, 可以在处理过程中按异常抛出; 若没抛异常,则认为是执行成功.
34 | *
35 | * 注: run方法在异步线程上执行.
36 | */
37 | void run();
38 | }
39 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v2/Downloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v2;
17 |
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/5/15.
21 | */
22 | public interface Downloader {
23 | /**
24 | * 设置回调监听器.
25 | * @param listener
26 | */
27 | void setListener(DownloadListener listener);
28 | /**
29 | * 启动资源的下载.
30 | * @param url 要下载的资源地址.
31 | * @param localPath 资源下载后要存储的本地位置.
32 | */
33 | void startDownload(String url, String localPath);
34 | }
35 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v1/Downloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v1;
17 |
18 | /**
19 | * Created by Tielei Zhang on 4/17/16.
20 | * 下载器接口定义.
21 | */
22 | public interface Downloader {
23 | /**
24 | * 设置回调监听器.
25 | * @param listener
26 | */
27 | void setListener(DownloadListener listener);
28 | /**
29 | * 启动资源的下载.
30 | * @param url 要下载的资源地址.
31 | * @param localPath 资源下载后要存储的本地位置.
32 | */
33 | void startDownload(String url, String localPath);
34 | }
35 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v3_simplified/Downloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v3_simplified;
17 |
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/5/11.
21 | * 下载器接口定义(可以传递上下文参数).
22 | */
23 | public interface Downloader {
24 | /**
25 | * 启动资源的下载.
26 | * @param url 要下载的资源地址.
27 | * @param localPath 资源下载后要存储的本地位置.
28 | * @param contextData 上下文数据, 在回调接口中会透传回去.可以是任何类型.
29 | * @param listener 回调接口实例.
30 | */
31 | void startDownload(String url, String localPath, Object contextData, DownloadListener listener);
32 | }
33 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/EmojiDownloadContext.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.emoji;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * Created by Tielei Zhang on 16/5/1.
23 | * 表情包下载上下文
24 | */
25 | public class EmojiDownloadContext {
26 | /**
27 | * 当前在下载的表情包
28 | */
29 | public EmojiPackage emojiPackage;
30 | /**
31 | * 已经下载完的表情图片计数
32 | */
33 | public int downloadedEmoji;
34 | /**
35 | * 下载到表情包本地地址
36 | */
37 | public List localPathList = new ArrayList();
38 | }
39 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/http/HttpListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.multitask.http;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/16.
20 | * 监听Http服务的监听器接口.
21 | *
22 | * @param 请求Model类型
23 | * @param 响应Model类型
24 | */
25 | public interface HttpListener {
26 | /**
27 | * 产生请求结果(成功或失败)时的回调接口.
28 | * @param apiUrl 请求URL
29 | * @param request 请求Model
30 | * @param result 请求结果(包括响应或者错误原因)
31 | * @param contextData 透传参数
32 | */
33 | void onResult(String apiUrl, T request, HttpResult result, Object contextData);
34 | }
35 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/http/HttpService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.multitask.http;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/16.
20 | *
21 | * Http服务请求接口.
22 | */
23 | public interface HttpService {
24 | /**
25 | * 发起HTTP请求.
26 | * @param apiUrl 请求URL
27 | * @param request 请求参数(用Java Bean表示)
28 | * @param listener 回调监听器
29 | * @param contextData 透传参数
30 | * @param 请求Model类型
31 | * @param 响应Model类型
32 | */
33 | void doRequest(String apiUrl, T request, HttpListener super T, R> listener, Object contextData);
34 | }
35 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v3/Downloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v3;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/2.
20 | * 下载器接口定义(可以传递上下文参数).
21 | */
22 | public interface Downloader {
23 | /**
24 | * 设置回调监听器.
25 | * @param listener
26 | */
27 | void setListener(DownloadListener listener);
28 | /**
29 | * 启动资源的下载.
30 | * @param url 要下载的资源地址.
31 | * @param localPath 资源下载后要存储的本地位置.
32 | * @param contextData 上下文数据, 在回调接口中会透传回去.可以是任何类型.
33 | */
34 | void startDownload(String url, String localPath, Object contextData);
35 | }
36 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v3/TaskQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v3;
18 |
19 | import rx.Observable;
20 |
21 | /**
22 | * Created by Tielei Zhang on 16/9/1.
23 | *
24 | * 任务队列接口.
25 | *
26 | * 第三版: 对应第三版的Task接口, 并且舍弃TaskQueueListener.
27 | */
28 | public interface TaskQueue {
29 | /**
30 | * 向队列中添加一个任务.
31 | *
32 | * @param task
33 | * @param 异步任务执行完要返回的数据类型.
34 | * @return 一个Observable. 调用者通过这个Observable获取异步任务执行结果.
35 | */
36 | Observable addTask(Task task);
37 |
38 | /**
39 | * 销毁队列.
40 | * 注: 队列在最后不用的时候, 应该主动销毁它.
41 | */
42 | void destroy();
43 | }
44 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v3/Task.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v3;
18 |
19 | import rx.Observable;
20 |
21 | /**
22 | * Created by Tielei Zhang on 16/9/1.
23 | *
24 | * 供任务队列执行的异步任务接口定义.
25 | *
26 | * 第三个版本: 不再使用TaskListener传递回调, 而是使用Observable.
27 | *
28 | * @param 异步任务执行完要返回的数据类型.
29 | */
30 | public interface Task {
31 | /**
32 | * 唯一标识当前任务的ID
33 | * @return
34 | */
35 | String getTaskId();
36 |
37 | /**
38 | *
39 | * 启动任务.
40 | *
41 | * 注: start方法需在主线程上执行.
42 | *
43 | * @return 一个Observable. 调用者通过这个Observable获取异步任务执行结果.
44 | */
45 | Observable start();
46 | }
47 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/multilevelcaching/ImageLoader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.multilevelcaching;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/5/17.
21 | * 一个简单的图片加载器.
22 | * 两级Cache: memory cache, disk cache; 如果都没有命中, 则调用Downloader去下载.
23 | * 注意: 这个实现只是一个Demo, 为了演示多级缓存用.
24 | */
25 | public interface ImageLoader {
26 | /**
27 | * 设置回调监听器.
28 | * @param listener
29 | */
30 | void setListener(ImageLoaderListener listener);
31 | /**
32 | * 根据指定Url启动图片加载.
33 | * @param url 要下载的资源地址.
34 | * @param contextData 上下文数据, 在回调接口中会透传回去.可以是任何类型.
35 | */
36 | void startImageLoad(String url, Object contextData);
37 | }
38 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/multilevelcaching/memcache/mock/MockImageMemCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.multilevelcaching.memcache.mock;
18 |
19 | import android.graphics.Bitmap;
20 | import com.zhangtielei.demos.async.programming.multitask.multilevelcaching.memcache.ImageMemCache;
21 |
22 | /**
23 | * Created by Tielei Zhang on 16/5/17.
24 | */
25 | public class MockImageMemCache implements ImageMemCache {
26 | @Override
27 | public Bitmap getImage(String key) {
28 | //TODO:
29 | //返回null表示没有命中
30 | return null;
31 | }
32 |
33 | @Override
34 | public boolean putImage(String key, Bitmap bitmap) {
35 | //TODO:
36 | return true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v1/DownloadListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v1;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/2.
20 | * 下载器回调接口定义(没有详细的错误码定义).
21 | */
22 | public interface DownloadListener {
23 | /**
24 | * 下载结束回调.
25 | * @param result 下载结果. true表示下载成功, false表示下载失败.
26 | * @param url 资源地址
27 | * @param localPath 下载后的资源存储位置. 只有result=true时才有效.
28 | */
29 | void downloadFinished(boolean result, String url, String localPath);
30 |
31 | /**
32 | * 下载进度回调.
33 | * @param url 资源地址
34 | * @param downloadedSize 已下载大小.
35 | * @param totalSize 资源总大小.
36 | */
37 | void downloadProgress(String url, long downloadedSize, long totalSize);
38 | }
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/multilevelcaching/diskcache/ImageDiskCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.multilevelcaching.diskcache;
18 |
19 | import android.graphics.Bitmap;
20 | import com.zhangtielei.demos.async.programming.common.AsyncCallback;
21 |
22 | /**
23 | * Created by Tielei Zhang on 16/5/17.
24 | *
25 | * 图片的Disk缓存.
26 | * 异步接口形式.
27 | */
28 | public interface ImageDiskCache {
29 | /**
30 | * 异步获取缓存的Bitmap对象.
31 | * @param key
32 | * @param callback 用于返回缓存的Bitmap对象
33 | */
34 | void getImage(String key, AsyncCallback callback);
35 | /**
36 | * 保存Bitmap对象到缓存中.
37 | * @param key
38 | * @param bitmap 要保存的Bitmap对象
39 | * @param callback 用于返回当前保存操作的结果是成功还是失败.
40 | */
41 | void putImage(String key, Bitmap bitmap, AsyncCallback callback);
42 | }
43 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/pagecaching/localcache/LocalDataCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.pagecaching.localcache;
18 |
19 | import com.zhangtielei.demos.async.programming.common.AsyncCallback;
20 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.model.HttpResponse;
21 |
22 | /**
23 | * Created by Tielei Zhang on 16/5/17.
24 | * 本地数据缓存.
25 | */
26 | public interface LocalDataCache {
27 | /**
28 | * 异步获取本地缓存的HttpResponse对象.
29 | * @param key
30 | * @param callback 用于返回缓存对象
31 | */
32 | void getCachingData(String key, AsyncCallback callback);
33 |
34 | /**
35 | * 保存HttpResponse对象到缓存中.
36 | * @param key
37 | * @param data 要保存的HttpResponse对象
38 | * @param callback 用于返回当前保存操作的结果是成功还是失败.
39 | */
40 | void putCachingData(String key, HttpResponse data, AsyncCallback callback);
41 | }
42 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/layout/activity_item_list.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
26 |
27 |
34 |
35 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v1/TaskQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v1;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/8/31.
21 | * 任务队列接口.
22 | *
23 | * 第一版.
24 | */
25 | public interface TaskQueue {
26 | /**
27 | * 向队列中添加一个任务.
28 | * @param task
29 | */
30 | void addTask(Task task);
31 |
32 | /**
33 | * 设置监听器.
34 | * @param listener
35 | */
36 | void setListener(TaskQueueListener listener);
37 |
38 | /**
39 | * 销毁队列.
40 | * 注: 队列在最后不用的时候, 应该主动销毁它.
41 | */
42 | void destroy();
43 |
44 | /**
45 | * 任务队列对外监听接口.
46 | */
47 | interface TaskQueueListener {
48 | /**
49 | * 任务完成的回调.
50 | * @param task
51 | */
52 | void taskComplete(Task task);
53 | /**
54 | * 任务最终失败的回调.
55 | * @param task
56 | * @param cause 失败原因
57 | */
58 | void taskFailed(Task task, Throwable cause);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/common/utils/TextLogUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.common.utils;
18 |
19 | import android.widget.TextView;
20 |
21 | import java.text.SimpleDateFormat;
22 | import java.util.Date;
23 |
24 | /**
25 | * Created by Tielei Zhang on 16/8/16.
26 | * 一个工具类, 用于在页面上打印日志.
27 | */
28 | public class TextLogUtil {
29 | /**
30 | * 在一个TextView上追加一行日志.
31 | * @param logTextView
32 | * @param log
33 | */
34 | public static void println(TextView logTextView, CharSequence log) {
35 | SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
36 | String timestamp = sdf.format(new Date());
37 |
38 | CharSequence newText = timestamp + ": " + log;
39 | CharSequence oldText = logTextView.getText();
40 | if (oldText == null || oldText.length() <= 0) {
41 | logTextView.setText(newText);
42 | }
43 | else {
44 | logTextView.setText(oldText + "\n" + newText);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v2/TaskQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v2;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/9/1.
21 | * 任务队列接口.
22 | *
23 | * 第二版: 对应第二版的Task接口.
24 | */
25 | public interface TaskQueue {
26 | /**
27 | * 向队列中添加一个任务.
28 | *
29 | * @param task
30 | */
31 | void addTask(Task task);
32 |
33 | /**
34 | * 设置监听器.
35 | * @param listener
36 | */
37 | void setListener(TaskQueueListener listener);
38 |
39 | /**
40 | * 销毁队列.
41 | * 注: 队列在最后不用的时候, 应该主动销毁它.
42 | */
43 | void destroy();
44 |
45 | /**
46 | * 任务队列对外监听接口.
47 | */
48 | interface TaskQueueListener {
49 | /**
50 | * 任务完成的回调.
51 | * @param task
52 | */
53 | void taskComplete(Task task);
54 | /**
55 | * 任务最终失败的回调.
56 | * @param task
57 | * @param cause 失败原因
58 | */
59 | void taskFailed(Task task, Throwable cause);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v2/Task.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v2;
18 |
19 | /**
20 | * Created by Tielei Zhang on 16/9/1.
21 | *
22 | * 供任务队列执行的异步任务接口定义.
23 | *
24 | * 第二个版本: 不再是同步任务, 变成异步任务.
25 | *
26 | */
27 | public interface Task {
28 | /**
29 | * 唯一标识当前任务的ID
30 | * @return
31 | */
32 | String getTaskId();
33 |
34 | /**
35 | * 由于任务是异步任务, 那么start方法被调用只是启动任务;
36 | * 任务完成后会回调TaskListener.
37 | *
38 | * 注: start方法需在主线程上执行.
39 | */
40 | void start();
41 |
42 | /**
43 | * 设置回调监听.
44 | * @param listener
45 | */
46 | void setListener(TaskListener listener);
47 |
48 | /**
49 | * 异步任务回调接口.
50 | */
51 | interface TaskListener {
52 | /**
53 | * 当前任务完成的回调.
54 | * @param task
55 | */
56 | void taskComplete(Task task);
57 | /**
58 | * 当前任务执行失败的回调.
59 | * @param task
60 | * @param cause 失败原因
61 | */
62 | void taskFailed(Task task, Throwable cause);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/multilevelcaching/ImageLoaderListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.multilevelcaching;
18 |
19 | import android.graphics.Bitmap;
20 |
21 | /**
22 | * Created by Tielei Zhang on 16/5/17.
23 | */
24 | public interface ImageLoaderListener {
25 | /**
26 | * 错误码定义
27 | */
28 | int SUCCESS = 0;//成功
29 | int BITMAP_DECODE_FAILED = 1;//图片解码失败
30 | int NETWORK_UNAVAILABLE = 2;//网络不可用
31 | int SDCARD_NOT_EXISTS = 3;//SD卡不存在(下载的图片文件没地方存)
32 | int SD_CARD_NO_SPACE_LEFT = 4;//SD卡空间不足(下载的图片文件没地方存)
33 | int DOWNLOAD_FAILED = 5;//图片文件下载过程出错
34 | int UNKNOWN_FAILED = 6;//其它未知错误
35 |
36 | /**
37 | * 图片加载成功回调.
38 | * @param url 图片地址
39 | * @param bitmap 下载到的Bitmap对象.
40 | * @param contextData 上下文数据.
41 | */
42 | void imageLoadSuccess(String url, Bitmap bitmap, Object contextData);
43 | /**
44 | * 图片加载失败回调.
45 | * @param url 图片地址
46 | * @param errorCode 错误码.
47 | * @param errorMessage 错误信息简短描述. 供调用者理解错误原因.
48 | * @param contextData 上下文数据.
49 | */
50 | void imageLoadFailed(String url, int errorCode, String errorMessage, Object contextData);
51 | }
52 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/ServerConnection.m:
--------------------------------------------------------------------------------
1 | //
2 | // ServerConnection.m
3 | // MyBlogAsyncTaskSeriesDemos
4 | //
5 | // Created by Charles Zhang on 3/27/16.
6 | // Copyright © 2016 tielei. All rights reserved.
7 | //
8 |
9 | #import "ServerConnection.h"
10 | #import "Reachability.h"
11 |
12 | @interface ServerConnection() {
13 | //用户执行socket操作的GCD queue
14 | dispatch_queue_t socketQueue;
15 | Reachability *reachability;
16 | }
17 | @end
18 |
19 | @implementation ServerConnection
20 |
21 | - (instancetype)init {
22 | self = [super init];
23 | if (self) {
24 | socketQueue = dispatch_queue_create("SocketQueue", NULL);
25 |
26 | reachability = [[Reachability alloc] init];
27 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkStateChanged:) name:kReachabilityChangedNotification object:reachability];
28 | [reachability startNetworkMonitoring];
29 | NSLog(@"ServerConnection init, start network monitoring...");
30 | }
31 | return self;
32 | }
33 |
34 | - (void)dealloc {
35 | [reachability stopNetworkMonitoring];
36 | [[NSNotificationCenter defaultCenter] removeObserver:self];
37 | NSLog(@"ServerConnection dealloc, stop network monitoring... isMainThread? %d", (dispatch_get_current_queue() == dispatch_get_main_queue()));
38 | }
39 |
40 |
41 | - (void)networkStateChanged:(NSNotification *)notification {
42 | NetworkStatus networkStatus = [notification.userInfo[networkStatusNotificationInfoKey] unsignedIntValue];
43 | if (networkStatus != NotReachable) {
44 | //网络变化,重连
45 | NSLog(@"networkStateChanged detected");
46 | dispatch_async(socketQueue, ^{
47 | [self reconnect];
48 | });
49 | }
50 | }
51 |
52 |
53 | - (void)reconnect {
54 | //TODO:
55 | NSLog(@"reconnecting... isMainThread? %d", (dispatch_get_current_queue() == dispatch_get_main_queue()));
56 | sleep(5);
57 | }
58 |
59 |
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v3_simplified/DownloadListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v3_simplified;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/11.
20 | * 下载器回调接口定义(支持回传上下文参数).
21 | */
22 | public interface DownloadListener {
23 | /**
24 | * 错误码定义
25 | */
26 | public static final int SUCCESS = 0;//成功
27 | public static final int INVALID_PARAMS = 1;//输入参数有误
28 | public static final int NETWORK_UNAVAILABLE = 2;//网络不可用
29 | public static final int UNKNOWN_HOST = 3;//域名解析失败
30 | public static final int CONNECT_TIMEOUT = 4;//连接超时
31 | public static final int HTTP_STATUS_NOT_OK = 5;//下载请求返回非200
32 | public static final int SDCARD_NOT_EXISTS = 6;//SD卡不存在(下载的资源没地方存)
33 | public static final int SD_CARD_NO_SPACE_LEFT = 7;//SD卡空间不足(下载的资源没地方存)
34 | public static final int READ_ONLY_FILE_SYSTEM = 8;//文件系统只读(下载的资源没地方存)
35 | public static final int LOCAL_IO_ERROR = 9;//本地SD存取有关的错误
36 | public static final int UNKNOWN_FAILED = 10;//其它未知错误
37 |
38 | /**
39 | * 下载结束回调.
40 | * @param errorCode 错误码. SUCCESS表示下载成功, 其它错误码表示下载失败.
41 | * @param url 资源地址.
42 | * @param localPath 下载后的资源存储位置.
43 | * @param contextData 上下文数据.
44 | */
45 | void downloadFinished(int errorCode, String url, String localPath, Object contextData);
46 | }
47 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/EmojiDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.emoji;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/1.
20 | * 表情包下载器接口.
21 | */
22 | public interface EmojiDownloader {
23 | /**
24 | * 开始下载指定的表情包
25 | * @param emojiPackage
26 | */
27 | void startDownloadEmoji(EmojiPackage emojiPackage);
28 |
29 | /**
30 | * 设置监听器.
31 | * @param listener
32 | */
33 | void setEmojiDownloadListener(EmojiDownloadListener listener);
34 |
35 | /**
36 | * 这里定义回调相关的接口. 不是我们要讨论的重点.
37 | * 这里的定义用于完整演示.
38 | */
39 |
40 | interface EmojiDownloadListener {
41 | /**
42 | * 表情包下载成功回调.
43 | * @param emojiPackage
44 | */
45 | void emojiDownloadSuccess(EmojiPackage emojiPackage);
46 |
47 | /**
48 | * 表情包下载失败回调.
49 | * @param emojiPackage
50 | * @param errorCode 为简单起见, 这里的值复用{@link com.zhangtielei.demos.async.programming.callback.download.v3.DownloadListener}中的错误码定义.
51 | * @param errorMessage
52 | */
53 | void emojiDownloadFailed(EmojiPackage emojiPackage, int errorCode, String errorMessage);
54 |
55 | /**
56 | * 表情包下载进度回调. 每次下载完一个图片文件后回调一次.
57 | * @param emojiPackage
58 | * @param downloadEmojiUrl 当前刚下载完的图片文件URL
59 | */
60 | void emojiDownloadProgress(EmojiPackage emojiPackage, String downloadEmojiUrl);
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // iOSDemos
4 | //
5 | // Created by Charles Zhang on 16/8/16.
6 | // Copyright © 2016年 tielei. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/layout/activity_log_display.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
26 |
27 |
35 |
36 |
41 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v2/DownloadListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v2;
17 |
18 | /**
19 | * Created by Tielei Zhang on 4/17/16.
20 | * 下载器回调接口定义(带有详细的错误码定义).
21 | */
22 | public interface DownloadListener {
23 | /**
24 | * 错误码定义
25 | */
26 | public static final int SUCCESS = 0;//成功
27 | public static final int INVALID_PARAMS = 1;//输入参数有误
28 | public static final int NETWORK_UNAVAILABLE = 2;//网络不可用
29 | public static final int UNKNOWN_HOST = 3;//域名解析失败
30 | public static final int CONNECT_TIMEOUT = 4;//连接超时
31 | public static final int HTTP_STATUS_NOT_OK = 5;//下载请求返回非200
32 | public static final int SDCARD_NOT_EXISTS = 6;//SD卡不存在(下载的资源没地方存)
33 | public static final int SD_CARD_NO_SPACE_LEFT = 7;//SD卡空间不足(下载的资源没地方存)
34 | public static final int READ_ONLY_FILE_SYSTEM = 8;//文件系统只读(下载的资源没地方存)
35 | public static final int LOCAL_IO_ERROR = 9;//本地SD存取有关的错误
36 | public static final int UNKNOWN_FAILED = 10;//其它未知错误
37 |
38 | /**
39 | * 下载成功回调.
40 | * @param url 资源地址
41 | * @param localPath 下载后的资源存储位置.
42 | */
43 | void downloadSuccess(String url, String localPath);
44 | /**
45 | * 下载失败回调.
46 | * @param url 资源地址
47 | * @param errorCode 错误码.
48 | * @param errorMessage 错误信息简短描述. 供调用者理解错误原因.
49 | */
50 | void downloadFailed(String url, int errorCode, String errorMessage);
51 |
52 | /**
53 | * 下载进度回调.
54 | * @param url 资源地址
55 | * @param downloadedSize 已下载大小.
56 | * @param totalSize 资源总大小.
57 | */
58 | void downloadProgress(String url, long downloadedSize, long totalSize);
59 | }
60 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/introduction/servicebinding/service/SomeService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.introduction.servicebinding.service;
18 |
19 | import android.app.Service;
20 | import android.content.Intent;
21 | import android.os.Binder;
22 | import android.os.IBinder;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 | import java.util.Random;
27 |
28 | /**
29 | * 一个Service例子, 用于演示Service Binding中存在的异步问题.
30 | */
31 | public class SomeService extends Service {
32 | private static final String TAG = "SomeService";
33 |
34 | public SomeService() {
35 | }
36 |
37 | /**
38 | * 用于OnBind返回的Binder实例
39 | */
40 | private ServiceBinder binder = new ServiceBinder();
41 | private List listeners = new ArrayList();
42 |
43 | private Random random = new Random();
44 |
45 | @Override
46 | public IBinder onBind(Intent intent) {
47 | // Return the communication channel to the service.
48 | return binder;
49 | }
50 |
51 | public void addListener(ServiceListener listener) {
52 | if (!listeners.contains(listener)) {
53 | listeners.add(listener);
54 | }
55 | }
56 |
57 | public void removeListener(ServiceListener listener) {
58 | listeners.remove(listener);
59 | }
60 |
61 | /**
62 | * 与此Service通信的Binder类
63 | */
64 | public class ServiceBinder extends Binder {
65 | public SomeService getService() {
66 | return SomeService.this;
67 | }
68 | }
69 |
70 | /**
71 | * 此Service对外界的回调接口定义.
72 | */
73 | public interface ServiceListener {
74 | void callback();
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/http/HttpResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.multitask.http;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/16.
20 | * HttpResult封装Http请求的结果.
21 | *
22 | * 当服务器成功响应的时候, errorCode = SUCCESS, 且服务器的响应转换成response;
23 | * 当服务器未能成功响应的时候, errorCode != SUCCESS, 且response的值无效.
24 | *
25 | * @param 响应Model类型
26 | */
27 | public class HttpResult {
28 | /**
29 | * 错误码定义
30 | */
31 | public static final int SUCCESS = 0;//成功
32 | public static final int REQUEST_ENCODING_ERROR = 1;//对请求进行编码发生错误
33 | public static final int RESPONSE_DECODING_ERROR = 2;//对响应进行解码发生错误
34 | public static final int NETWORK_UNAVAILABLE = 3;//网络不可用
35 | public static final int UNKNOWN_HOST = 4;//域名解析失败
36 | public static final int CONNECT_TIMEOUT = 5;//连接超时
37 | public static final int HTTP_STATUS_NOT_OK = 6;//下载请求返回非200
38 | public static final int UNKNOWN_FAILED = 7;//其它未知错误
39 |
40 | private int errorCode;
41 | private String errorMessage;
42 | /**
43 | * response是服务器返回的响应.
44 | * 只有当errorCode = SUCCESS, response的值才有效.
45 | */
46 | private R response;
47 |
48 | public int getErrorCode() {
49 | return errorCode;
50 | }
51 |
52 | public void setErrorCode(int errorCode) {
53 | this.errorCode = errorCode;
54 | }
55 |
56 | public String getErrorMessage() {
57 | return errorMessage;
58 | }
59 |
60 | public void setErrorMessage(String errorMessage) {
61 | this.errorMessage = errorMessage;
62 | }
63 |
64 | public R getResponse() {
65 | return response;
66 | }
67 |
68 | public void setResponse(R response) {
69 | this.response = response;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/iOSDemos/iOSDemos/Reachability.m:
--------------------------------------------------------------------------------
1 | //
2 | // Reachability.m
3 | // MyBlogAsyncTaskSeriesDemos
4 | //
5 | // Created by Charles Zhang on 16/3/24.
6 | // Copyright © 2016年 tielei. All rights reserved.
7 | //
8 |
9 | #import "Reachability.h"
10 |
11 | #import
12 | #import
13 |
14 | NSString *const networkStatusNotificationInfoKey = @"networkStatus";
15 |
16 | NSString *const kReachabilityChangedNotification = @"NetworkReachabilityChangedNotification";
17 |
18 | @implementation Reachability
19 |
20 |
21 | - (instancetype)init {
22 | self = [super init];
23 | if (self) {
24 | struct sockaddr_in zeroAddress;
25 | // bzero(&zeroAddress, sizeof(zeroAddress));
26 | memset(&zeroAddress, 0, sizeof(zeroAddress));
27 | zeroAddress.sin_len = sizeof(zeroAddress);
28 | zeroAddress.sin_family = AF_INET;
29 |
30 | reachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)&zeroAddress);
31 |
32 | }
33 |
34 | return self;
35 | }
36 |
37 | - (void)dealloc {
38 | if (reachabilityRef) {
39 | CFRelease(reachabilityRef);
40 | }
41 | }
42 |
43 | static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
44 |
45 | Reachability *reachability = (__bridge Reachability *) info;
46 |
47 | @autoreleasepool {
48 | NetworkStatus networkStatus = [reachability currentNetworkStatus];
49 | [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification object:reachability userInfo:@{networkStatusNotificationInfoKey : @(networkStatus)}];
50 | }
51 | }
52 |
53 | - (BOOL)startNetworkMonitoring {
54 | SCNetworkReachabilityContext context = {0, (__bridge void * _Nullable)(self), NULL, NULL, NULL};
55 |
56 | if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) {
57 | if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
58 | return YES;
59 | }
60 |
61 | }
62 |
63 | return NO;
64 | }
65 |
66 | - (BOOL)stopNetworkMonitoring {
67 | return SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
68 | }
69 |
70 | - (NetworkStatus) currentNetworkStatus {
71 | //TODO:
72 | return ReachableViaWiFi;
73 | }
74 |
75 |
76 | @end
77 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v3/DownloadListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v3;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/2.
20 | * 下载器回调接口定义(支持回传上下文参数).
21 | */
22 | public interface DownloadListener {
23 | /**
24 | * 错误码定义
25 | */
26 | public static final int SUCCESS = 0;//成功
27 | public static final int INVALID_PARAMS = 1;//输入参数有误
28 | public static final int NETWORK_UNAVAILABLE = 2;//网络不可用
29 | public static final int UNKNOWN_HOST = 3;//域名解析失败
30 | public static final int CONNECT_TIMEOUT = 4;//连接超时
31 | public static final int HTTP_STATUS_NOT_OK = 5;//下载请求返回非200
32 | public static final int SDCARD_NOT_EXISTS = 6;//SD卡不存在(下载的资源没地方存)
33 | public static final int SD_CARD_NO_SPACE_LEFT = 7;//SD卡空间不足(下载的资源没地方存)
34 | public static final int READ_ONLY_FILE_SYSTEM = 8;//文件系统只读(下载的资源没地方存)
35 | public static final int LOCAL_IO_ERROR = 9;//本地SD存取有关的错误
36 | public static final int UNKNOWN_FAILED = 10;//其它未知错误
37 |
38 | /**
39 | * 下载成功回调.
40 | * @param url 资源地址
41 | * @param localPath 下载后的资源存储位置.
42 | * @param contextData 上下文数据.
43 | */
44 | void downloadSuccess(String url, String localPath, Object contextData);
45 | /**
46 | * 下载失败回调.
47 | * @param url 资源地址
48 | * @param errorCode 错误码.
49 | * @param errorMessage 错误信息简短描述. 供调用者理解错误原因.
50 | * @param contextData 上下文数据.
51 | */
52 | void downloadFailed(String url, int errorCode, String errorMessage, Object contextData);
53 |
54 | /**
55 | * 下载进度回调.
56 | * @param url 资源地址
57 | * @param downloadedSize 已下载大小.
58 | * @param totalSize 资源总大小.
59 | * @param contextData 上下文数据.
60 | */
61 | void downloadProgress(String url, long downloadedSize, long totalSize, Object contextData);
62 | }
63 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v2/MyDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v2;
17 |
18 | import android.os.Handler;
19 | import android.os.Looper;
20 |
21 | import java.util.Random;
22 | import java.util.concurrent.ExecutorService;
23 | import java.util.concurrent.Executors;
24 | import java.util.concurrent.TimeUnit;
25 |
26 | /**
27 | * Created by Tielei Zhang on 16/5/1.
28 | * 下载器的实现(stub).
29 | */
30 | public class MyDownloader implements Downloader {
31 | private DownloadListener listener;
32 |
33 | private ExecutorService executorService = Executors.newCachedThreadPool();
34 | private Handler mainHandler = new Handler(Looper.getMainLooper());
35 | private Random rand = new Random();
36 |
37 | @Override
38 | public void setListener(DownloadListener listener) {
39 | this.listener = listener;
40 | }
41 |
42 | @Override
43 | public void startDownload(final String url, final String localPath) {
44 | executorService.execute(new Runnable() {
45 | @Override
46 | public void run() {
47 | //模拟请求执行, 随机执行0~3秒
48 | try {
49 | TimeUnit.MILLISECONDS.sleep(rand.nextInt(3000));
50 | } catch (InterruptedException e) {
51 | e.printStackTrace();
52 | }
53 |
54 | //模拟一个下载成功回调
55 | mainHandler.post(new Runnable() {
56 | @Override
57 | public void run() {
58 | try {
59 | if (listener != null) {
60 | listener.downloadSuccess(url, localPath);
61 | }
62 | }
63 | catch (Throwable e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | });
68 | }
69 | });
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v3/MyDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v3;
17 |
18 | import android.os.Handler;
19 | import android.os.Looper;
20 |
21 | import java.util.Random;
22 | import java.util.concurrent.ExecutorService;
23 | import java.util.concurrent.Executors;
24 | import java.util.concurrent.TimeUnit;
25 |
26 | /**
27 | * Created by Tielei Zhang on 16/5/2.
28 | * 下载器的实现(stub). 接口支持上下文参数.
29 | */
30 | public class MyDownloader implements Downloader {
31 | private DownloadListener listener;
32 |
33 | private ExecutorService executorService = Executors.newCachedThreadPool();
34 | private Handler mainHandler = new Handler(Looper.getMainLooper());
35 | private Random rand = new Random();
36 |
37 | @Override
38 | public void setListener(DownloadListener listener) {
39 | this.listener = listener;
40 | }
41 |
42 | @Override
43 | public void startDownload(final String url, final String localPath, final Object contextData) {
44 | executorService.execute(new Runnable() {
45 | @Override
46 | public void run() {
47 | //模拟请求执行, 随机执行0~3秒
48 | try {
49 | TimeUnit.MILLISECONDS.sleep(rand.nextInt(3000));
50 | } catch (InterruptedException e) {
51 | e.printStackTrace();
52 | }
53 |
54 | //模拟一个下载成功回调
55 | mainHandler.post(new Runnable() {
56 | @Override
57 | public void run() {
58 | try {
59 | if (listener != null) {
60 | listener.downloadSuccess(url, localPath, contextData);
61 | }
62 | }
63 | catch (Throwable e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | });
68 | }
69 | });
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/AndroidDemos/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v2/TaskQueueDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v2;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.widget.TextView;
22 | import com.zhangtielei.demos.async.programming.R;
23 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
24 | import com.zhangtielei.demos.async.programming.queueing.v2.mock.MockAsyncTask;
25 |
26 | /**
27 | * 演示基于"异步+Callback"的任务队列的运行情况.
28 | */
29 | public class TaskQueueDemoActivity extends AppCompatActivity {
30 | private TextView description;
31 | private TextView logTextView;
32 |
33 | private TaskQueue taskQueue;
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.activity_log_display);
39 |
40 | description = (TextView) findViewById(R.id.description);
41 | logTextView = (TextView) findViewById(R.id.log_display);
42 |
43 | description.setText(R.string.queueing_demo2_description);
44 |
45 | taskQueue = new CallbackBasedTaskQueue();
46 | taskQueue.setListener(new TaskQueue.TaskQueueListener() {
47 | @Override
48 | public void taskComplete(Task task) {
49 | TextLogUtil.println(logTextView, "Task (" + task.getTaskId() + ") complete");
50 | }
51 |
52 | @Override
53 | public void taskFailed(Task task, Throwable cause) {
54 | TextLogUtil.println(logTextView, "Task (" + task.getTaskId() + ") failed, error message: " + cause.getMessage());
55 | }
56 | });
57 |
58 | /**
59 | * 启动5个任务
60 | */
61 | for (int i = 0; i < 5; i++) {
62 | Task task = new MockAsyncTask();
63 | TextLogUtil.println(logTextView, "Add task (" + task.getTaskId() + ") to queue");
64 | taskQueue.addTask(task);
65 | }
66 |
67 | }
68 |
69 | @Override
70 | protected void onDestroy() {
71 | taskQueue.setListener(null);
72 | taskQueue.destroy();
73 |
74 | super.onDestroy();
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/download/v3_simplified/CallbackHellExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.download.v3_simplified;
17 |
18 | /**
19 | * Created by Tielei Zhang on 16/5/11.
20 | * 演示多层嵌套导致的callback hell
21 | */
22 | public class CallbackHellExample {
23 | /**
24 | * 连续下载3个文件
25 | * @param url1
26 | * @param url2
27 | * @param url3
28 | */
29 | public void downloadThreeFiles(final String url1, final String url2, final String url3) {
30 | final Downloader downloader = new MyDownloader();
31 | downloader.startDownload(url1, localPathForUrl(url1), null, new DownloadListener() {
32 | @Override
33 | public void downloadFinished(int errorCode, String url, String localPath, Object contextData) {
34 | if (errorCode != DownloadListener.SUCCESS) {
35 | //...错误处理
36 | }
37 | else {
38 | //下载第二个URL
39 | downloader.startDownload(url2, localPathForUrl(url2), null, new DownloadListener() {
40 | @Override
41 | public void downloadFinished(int errorCode, String url, String localPath, Object contextData) {
42 | if (errorCode != DownloadListener.SUCCESS) {
43 | //...错误处理
44 | }
45 | else {
46 | //下载第三个URL
47 | downloader.startDownload(url3, localPathForUrl(url3), null, new DownloadListener(
48 |
49 | ) {
50 | @Override
51 | public void downloadFinished(int errorCode, String url, String localPath, Object contextData) {
52 | //...最终结果处理
53 | }
54 | });
55 | }
56 | }
57 | });
58 | }
59 | }
60 | });
61 | }
62 |
63 | private String localPathForUrl(String url) {
64 | //TODO:
65 | return null;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/multilevelcaching/diskcache/mock/MockImageDiskCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.multilevelcaching.diskcache.mock;
18 |
19 | import android.graphics.Bitmap;
20 | import android.os.Handler;
21 | import android.os.Looper;
22 | import com.zhangtielei.demos.async.programming.common.AsyncCallback;
23 | import com.zhangtielei.demos.async.programming.multitask.multilevelcaching.diskcache.ImageDiskCache;
24 |
25 | import java.util.Random;
26 | import java.util.concurrent.ExecutorService;
27 | import java.util.concurrent.Executors;
28 | import java.util.concurrent.TimeUnit;
29 |
30 | /**
31 | * Created by Tielei Zhang on 16/5/17.
32 | */
33 | public class MockImageDiskCache implements ImageDiskCache {
34 | private ExecutorService executorService = Executors.newCachedThreadPool();
35 | private Handler mainHandler = new Handler(Looper.getMainLooper());
36 | private Random rand = new Random();
37 |
38 | @Override
39 | public void getImage(String key, final AsyncCallback callback) {
40 | executorService.execute(new Runnable() {
41 | @Override
42 | public void run() {
43 | //模拟请求执行, 随机执行0~1秒
44 | try {
45 | TimeUnit.MILLISECONDS.sleep(rand.nextInt(1000));
46 | } catch (InterruptedException e) {
47 | e.printStackTrace();
48 | }
49 |
50 | //模拟一个下载成功回调
51 | mainHandler.post(new Runnable() {
52 | @Override
53 | public void run() {
54 | try {
55 | if (callback != null) {
56 | //TODO: 这里写死返回null, 模拟Disk缓存没有命中的情形
57 | callback.onResult(null);
58 | }
59 | }
60 | catch (Throwable e) {
61 | e.printStackTrace();
62 | }
63 | }
64 | });
65 | }
66 | });
67 | }
68 |
69 | @Override
70 | public void putImage(String key, Bitmap bitmap, AsyncCallback callback) {
71 | //TODO:
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v3/mock/MockAsyncTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v3.mock;
18 |
19 | import com.zhangtielei.demos.async.programming.queueing.v3.Task;
20 | import rx.Observable;
21 | import rx.Subscriber;
22 | import rx.android.schedulers.AndroidSchedulers;
23 | import rx.schedulers.Schedulers;
24 |
25 | import java.util.Random;
26 | import java.util.concurrent.ExecutorService;
27 | import java.util.concurrent.Executors;
28 | import java.util.concurrent.TimeUnit;
29 |
30 | /**
31 | * Created by Tielei Zhang on 16/9/1.
32 | *
33 | * 异步任务的一个假的实现.
34 | */
35 | public class MockAsyncTask implements Task {
36 | private static long taskIdCounter;
37 |
38 | private String taskId;
39 |
40 | private ExecutorService executorService = Executors.newCachedThreadPool();
41 | private Random rand1 = new Random();
42 | private Random rand2 = new Random();
43 |
44 | public MockAsyncTask() {
45 | taskId = String.valueOf(++taskIdCounter);
46 | }
47 |
48 | @Override
49 | public String getTaskId() {
50 | return taskId;
51 | }
52 |
53 | @Override
54 | public Observable start() {
55 | return Observable.create(new Observable.OnSubscribe() {
56 | @Override
57 | public void call(Subscriber super Void> subscriber) {
58 | //任务随机执行0~3秒
59 | try {
60 | TimeUnit.MILLISECONDS.sleep(rand1.nextInt(3000));
61 | } catch (InterruptedException e) {
62 | e.printStackTrace();
63 | }
64 |
65 | //模拟失败情况: 以80%的概率失败
66 | Exception error = null;
67 | if (rand2.nextInt(10) < 8) {
68 | error = new RuntimeException("runtime error...");
69 | }
70 |
71 | if (error == null) {
72 | //当前异步任务没有返回数据, 不用调用onNext
73 | subscriber.onCompleted();
74 | }
75 | else {
76 | subscriber.onError(error);
77 | }
78 |
79 | }
80 | }).subscribeOn(Schedulers.from(executorService))
81 | .observeOn(AndroidSchedulers.mainThread());
82 | }
83 |
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/multilevelcaching/ImageLoaderDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.multilevelcaching;
18 |
19 | import android.graphics.Bitmap;
20 | import android.os.Bundle;
21 | import android.support.v7.app.AppCompatActivity;
22 | import android.widget.TextView;
23 | import com.zhangtielei.demos.async.programming.R;
24 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
25 | import com.zhangtielei.demos.async.programming.multitask.multilevelcaching.mock.MyDemoImageLoader;
26 |
27 | /**
28 | * 一个演示页面: 调用一个带多级缓存的图片下载器, 演示"多个异步任务先后接续执行".
29 | */
30 | public class ImageLoaderDemoActivity extends AppCompatActivity {
31 | private TextView description;
32 | private TextView logTextView;
33 |
34 | private ImageLoader imageLoader;
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_log_display);
40 |
41 | description = (TextView) findViewById(R.id.description);
42 | logTextView = (TextView) findViewById(R.id.log_display);
43 |
44 | description.setText(R.string.imageloader_demo_description);
45 |
46 | imageLoader = new MyDemoImageLoader();
47 | imageLoader.setListener(new ImageLoaderListener() {
48 | @Override
49 | public void imageLoadSuccess(String url, Bitmap bitmap, Object contextData) {
50 | TextLogUtil.println(logTextView, "Loaded image(" + bitmap + ") from: " + url + ", with context data: " + contextData);
51 | }
52 |
53 | @Override
54 | public void imageLoadFailed(String url, int errorCode, String errorMessage, Object contextData) {
55 | TextLogUtil.println(logTextView, "Load image failed from: " + url + ", with context data: " + contextData + ", errorCode: " + errorCode + ", errorMessage: " + errorMessage);
56 | }
57 | });
58 |
59 | //发起请求: 请求一个静态图片
60 | String imageUrl = "http://zhangtielei.com/demourls/1.png";
61 | Object contextData = "Here ImageLoaderDemoActivity";
62 | TextLogUtil.println(logTextView, "Start to download image from: " + imageUrl + ", with request context data: " + contextData);
63 | imageLoader.startImageLoad(imageUrl, contextData);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/pagecaching/localcache/mock/MockLocalDataCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.pagecaching.localcache.mock;
18 |
19 | import android.os.Handler;
20 | import android.os.Looper;
21 | import com.zhangtielei.demos.async.programming.common.AsyncCallback;
22 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.localcache.LocalDataCache;
23 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.model.HttpResponse;
24 |
25 | import java.util.Random;
26 | import java.util.concurrent.ExecutorService;
27 | import java.util.concurrent.Executors;
28 | import java.util.concurrent.TimeUnit;
29 |
30 | /**
31 | * Created by Tielei Zhang on 16/5/17.
32 | * 本地页面Cache的一个假的实现.
33 | */
34 | public class MockLocalDataCache implements LocalDataCache {
35 | private ExecutorService executorService = Executors.newCachedThreadPool();
36 | private Handler mainHandler = new Handler(Looper.getMainLooper());
37 | private Random rand = new Random();
38 |
39 | @Override
40 | public void getCachingData(String key, final AsyncCallback callback) {
41 | executorService.execute(new Runnable() {
42 | @Override
43 | public void run() {
44 | //模拟请求执行, 随机执行0~1秒
45 | try {
46 | TimeUnit.MILLISECONDS.sleep(rand.nextInt(1000));
47 | } catch (InterruptedException e) {
48 | e.printStackTrace();
49 | }
50 |
51 | //回调
52 | mainHandler.post(new Runnable() {
53 | @Override
54 | public void run() {
55 | if (callback != null) {
56 | try {
57 | //模拟命中还是不命中的两种情况: 以80%概率命中
58 | HttpResponse httpResponse = (rand.nextInt(10) <= 7) ? new HttpResponse() : null;
59 | callback.onResult(httpResponse);
60 | }
61 | catch (Throwable e) {
62 | e.printStackTrace();
63 | }
64 | }
65 | }
66 | });
67 | }
68 | });
69 | }
70 |
71 | @Override
72 | public void putCachingData(String key, HttpResponse data, AsyncCallback callback) {
73 | //TODO:
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v3/TaskQueueDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v3;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.widget.TextView;
22 | import com.zhangtielei.demos.async.programming.R;
23 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
24 | import com.zhangtielei.demos.async.programming.queueing.v3.mock.MockAsyncTask;
25 | import rx.Observable;
26 | import rx.Subscriber;
27 | import rx.Subscription;
28 |
29 | import java.util.ArrayList;
30 | import java.util.List;
31 |
32 | /**
33 | * 演示基于RxJava的任务队列的运行情况.
34 | */
35 | public class TaskQueueDemoActivity extends AppCompatActivity {
36 | private TextView description;
37 | private TextView logTextView;
38 |
39 | private TaskQueue taskQueue;
40 |
41 | private List subscriptionList = new ArrayList();
42 |
43 | @Override
44 | protected void onCreate(Bundle savedInstanceState) {
45 | super.onCreate(savedInstanceState);
46 | setContentView(R.layout.activity_log_display);
47 |
48 | description = (TextView) findViewById(R.id.description);
49 | logTextView = (TextView) findViewById(R.id.log_display);
50 |
51 | description.setText(R.string.queueing_demo3_description);
52 |
53 | taskQueue = new RxJavaBasedTaskQueue();
54 | /**
55 | * 启动5个任务
56 | */
57 | for (int i = 0; i < 5; i++) {
58 | final MockAsyncTask task = new MockAsyncTask();
59 | TextLogUtil.println(logTextView, "Add task (" + task.getTaskId() + ") to queue");
60 | Observable observable = taskQueue.addTask(task);
61 | Subscription subscription = observable.subscribe(new Subscriber() {
62 | @Override
63 | public void onCompleted() {
64 | TextLogUtil.println(logTextView, "Task (" + task.getTaskId() + ") complete");
65 | }
66 |
67 | @Override
68 | public void onError(Throwable e) {
69 | TextLogUtil.println(logTextView, "Task (" + task.getTaskId() + ") failed, error message: " + e.getMessage());
70 | }
71 |
72 | @Override
73 | public void onNext(Void aVoid) {
74 |
75 | }
76 | });
77 |
78 | subscriptionList.add(subscription);
79 | }
80 |
81 | }
82 |
83 | @Override
84 | protected void onDestroy() {
85 | for (Subscription subscription : subscriptionList) {
86 | subscription.unsubscribe();
87 | }
88 | taskQueue.destroy();
89 |
90 | super.onDestroy();
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/QueueingDemoListActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing;
18 |
19 | import android.content.Intent;
20 | import android.content.res.Resources;
21 | import android.os.Bundle;
22 | import android.support.v7.app.AppCompatActivity;
23 | import android.view.View;
24 | import android.widget.AdapterView;
25 | import android.widget.ArrayAdapter;
26 | import android.widget.ListAdapter;
27 | import android.widget.ListView;
28 | import com.zhangtielei.demos.async.programming.R;
29 | import com.zhangtielei.demos.async.programming.queueing.v1.TaskQueueDemoActivity;
30 |
31 | public class QueueingDemoListActivity extends AppCompatActivity {
32 |
33 | @Override
34 | protected void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | setContentView(R.layout.activity_item_list);
37 |
38 | ListView listView = (ListView) findViewById(R.id.item_list);
39 | Resources resources = getResources();
40 | String[] textList = new String[] {
41 | resources.getString(R.string.queueing_demo_1),
42 | resources.getString(R.string.queueing_demo_2),
43 | resources.getString(R.string.queueing_demo_3),
44 | };
45 | ListAdapter listAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, textList);
46 | listView.setAdapter(listAdapter);
47 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
48 | @Override
49 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
50 | switch (position) {
51 | case 0:
52 | {
53 | Intent intent = new Intent(QueueingDemoListActivity.this, TaskQueueDemoActivity.class);
54 | startActivity(intent);
55 | break;
56 | }
57 | case 1:
58 | {
59 | Intent intent = new Intent(QueueingDemoListActivity.this, com.zhangtielei.demos.async.programming.queueing.v2.TaskQueueDemoActivity.class);
60 | startActivity(intent);
61 | break;
62 | }
63 | case 2:
64 | {
65 | Intent intent = new Intent(QueueingDemoListActivity.this, com.zhangtielei.demos.async.programming.queueing.v3.TaskQueueDemoActivity.class);
66 | startActivity(intent);
67 | break;
68 | }
69 | default:
70 | break;
71 | }
72 | }
73 | });
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v2/mock/MockAsyncTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v2.mock;
18 |
19 | import android.os.Handler;
20 | import android.os.Looper;
21 | import com.zhangtielei.demos.async.programming.queueing.v2.Task;
22 |
23 | import java.util.Random;
24 | import java.util.concurrent.ExecutorService;
25 | import java.util.concurrent.Executors;
26 | import java.util.concurrent.TimeUnit;
27 |
28 | /**
29 | * Created by Tielei Zhang on 16/9/1.
30 | *
31 | * 异步任务的一个假的实现.
32 | */
33 | public class MockAsyncTask implements Task {
34 | private static long taskIdCounter;
35 |
36 | private String taskId;
37 | private TaskListener listener;
38 |
39 | private ExecutorService executorService = Executors.newCachedThreadPool();
40 | private Handler mainHandler = new Handler(Looper.getMainLooper());
41 | private Random rand1 = new Random();
42 | private Random rand2 = new Random();
43 |
44 | public MockAsyncTask() {
45 | taskId = String.valueOf(++taskIdCounter);
46 | }
47 |
48 | @Override
49 | public String getTaskId() {
50 | return taskId;
51 | }
52 |
53 | @Override
54 | public void start() {
55 | executorService.execute(new Runnable() {
56 | @Override
57 | public void run() {
58 | //任务随机执行0~3秒
59 | try {
60 | TimeUnit.MILLISECONDS.sleep(rand1.nextInt(3000));
61 | } catch (InterruptedException e) {
62 | e.printStackTrace();
63 | }
64 |
65 | //模拟失败情况: 以80%的概率失败
66 | Exception error = null;
67 | if (rand2.nextInt(10) < 8) {
68 | error = new RuntimeException("runtime error...");
69 | }
70 |
71 | final Exception finalError = error;
72 | mainHandler.post(new Runnable() {
73 | @Override
74 | public void run() {
75 | if (listener != null) {
76 | try {
77 | if (finalError == null) {
78 | listener.taskComplete(MockAsyncTask.this);
79 | }
80 | else {
81 | listener.taskFailed(MockAsyncTask.this, finalError);
82 | }
83 | }
84 | catch (Throwable e) {
85 | e.printStackTrace();
86 | }
87 | }
88 | }
89 | });
90 |
91 | }
92 | });
93 | }
94 |
95 | @Override
96 | public void setListener(TaskListener listener) {
97 | this.listener = listener;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/v4/EmojiDownloadDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.callback.emoji.v4;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.widget.TextView;
22 | import com.zhangtielei.demos.async.programming.R;
23 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloader;
24 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiPackage;
25 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
26 |
27 | import java.util.ArrayList;
28 |
29 | /**
30 | * 利用支持上下文传递的异步接口来实现表情包下载的演示页面.
31 | */
32 | public class EmojiDownloadDemoActivity extends AppCompatActivity {
33 | private TextView description;
34 | private TextView logTextView;
35 |
36 | private EmojiDownloader emojiDownloader;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_log_display);
42 |
43 | description = (TextView) findViewById(R.id.description);
44 | logTextView = (TextView) findViewById(R.id.log_display);
45 |
46 | description.setText(R.string.emoji_download_demo4_description);
47 |
48 | emojiDownloader = new MyEmojiDownloader();
49 | emojiDownloader.setEmojiDownloadListener(new EmojiDownloader.EmojiDownloadListener() {
50 | @Override
51 | public void emojiDownloadSuccess(EmojiPackage emojiPackage) {
52 | TextLogUtil.println(logTextView, "emoji package (emojiId: " + emojiPackage.emojiId + ") downloaded success!");
53 | }
54 |
55 | @Override
56 | public void emojiDownloadFailed(EmojiPackage emojiPackage, int errorCode, String errorMessage) {
57 | TextLogUtil.println(logTextView, "emoji package (emojiId: " + emojiPackage.emojiId + ") downloaded failed! errorCode: " + errorCode + ", errorMessage: " + errorMessage);
58 | }
59 |
60 | @Override
61 | public void emojiDownloadProgress(EmojiPackage emojiPackage, String downloadEmojiUrl) {
62 | TextLogUtil.println(logTextView, "progress: " + downloadEmojiUrl + " downloaded...");
63 | }
64 | });
65 |
66 | //构造要下载的表情包
67 | EmojiPackage emojiPackage = new EmojiPackage();
68 | emojiPackage.emojiId = 1004;
69 | emojiPackage.emojiUrls = new ArrayList();
70 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/1.png");
71 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/2.png");
72 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/3.png");
73 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/4.png");
74 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/5.png");
75 |
76 | TextLogUtil.println(logTextView, "Start downloading emoji package (emojiId: " + emojiPackage.emojiId + ") with " + emojiPackage.emojiUrls.size() + " URLs");
77 | emojiDownloader.startDownloadEmoji(emojiPackage);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/v1/EmojiDownloadDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.callback.emoji.v1;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.widget.TextView;
22 | import com.zhangtielei.demos.async.programming.R;
23 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloader;
24 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiPackage;
25 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
26 |
27 | import java.util.ArrayList;
28 |
29 | /**
30 | * 通过全局保存一份上下文来实现表情包下载的演示页面.
31 | */
32 | public class EmojiDownloadDemoActivity extends AppCompatActivity {
33 | private TextView description;
34 | private TextView logTextView;
35 |
36 | private EmojiDownloader emojiDownloader;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_log_display);
42 |
43 | description = (TextView) findViewById(R.id.description);
44 | logTextView = (TextView) findViewById(R.id.log_display);
45 |
46 | description.setText(R.string.emoji_download_demo1_description);
47 |
48 | emojiDownloader = new MyEmojiDownloader();
49 | emojiDownloader.setEmojiDownloadListener(new EmojiDownloader.EmojiDownloadListener() {
50 | @Override
51 | public void emojiDownloadSuccess(EmojiPackage emojiPackage) {
52 | TextLogUtil.println(logTextView, "emoji package (emojiId: " + emojiPackage.emojiId + ") downloaded success!");
53 | }
54 |
55 | @Override
56 | public void emojiDownloadFailed(EmojiPackage emojiPackage, int errorCode, String errorMessage) {
57 | TextLogUtil.println(logTextView, "emoji package (emojiId: " + emojiPackage.emojiId + ") downloaded failed! errorCode: " + errorCode + ", errorMessage: " + errorMessage);
58 | }
59 |
60 | @Override
61 | public void emojiDownloadProgress(EmojiPackage emojiPackage, String downloadEmojiUrl) {
62 | TextLogUtil.println(logTextView, "progress: " + downloadEmojiUrl + " downloaded...");
63 | }
64 | });
65 |
66 | //构造要下载的表情包
67 | EmojiPackage emojiPackage = new EmojiPackage();
68 | emojiPackage.emojiId = 1001;
69 | emojiPackage.emojiUrls = new ArrayList();
70 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/1.png");
71 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/2.png");
72 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/3.png");
73 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/4.png");
74 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/5.png");
75 |
76 | TextLogUtil.println(logTextView, "Start downloading emoji package (emojiId: " + emojiPackage.emojiId + ") with " + emojiPackage.emojiUrls.size() + " URLs");
77 | emojiDownloader.startDownloadEmoji(emojiPackage);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/v2/EmojiDownloadDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.callback.emoji.v2;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.widget.TextView;
22 | import com.zhangtielei.demos.async.programming.R;
23 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloader;
24 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiPackage;
25 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
26 |
27 | import java.util.ArrayList;
28 |
29 | /**
30 | * 通过用映射关系来保存上下文来实现表情包下载的演示页面.
31 | */
32 | public class EmojiDownloadDemoActivity extends AppCompatActivity {
33 | private TextView description;
34 | private TextView logTextView;
35 |
36 | private EmojiDownloader emojiDownloader;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_log_display);
42 |
43 | description = (TextView) findViewById(R.id.description);
44 | logTextView = (TextView) findViewById(R.id.log_display);
45 |
46 | description.setText(R.string.emoji_download_demo2_description);
47 |
48 | emojiDownloader = new MyEmojiDownloader();
49 | emojiDownloader.setEmojiDownloadListener(new EmojiDownloader.EmojiDownloadListener() {
50 | @Override
51 | public void emojiDownloadSuccess(EmojiPackage emojiPackage) {
52 | TextLogUtil.println(logTextView, "emoji package (emojiId: " + emojiPackage.emojiId + ") downloaded success!");
53 | }
54 |
55 | @Override
56 | public void emojiDownloadFailed(EmojiPackage emojiPackage, int errorCode, String errorMessage) {
57 | TextLogUtil.println(logTextView, "emoji package (emojiId: " + emojiPackage.emojiId + ") downloaded failed! errorCode: " + errorCode + ", errorMessage: " + errorMessage);
58 | }
59 |
60 | @Override
61 | public void emojiDownloadProgress(EmojiPackage emojiPackage, String downloadEmojiUrl) {
62 | TextLogUtil.println(logTextView, "progress: " + downloadEmojiUrl + " downloaded...");
63 | }
64 | });
65 |
66 | //构造要下载的表情包
67 | EmojiPackage emojiPackage = new EmojiPackage();
68 | emojiPackage.emojiId = 1002;
69 | emojiPackage.emojiUrls = new ArrayList();
70 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/1.png");
71 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/2.png");
72 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/3.png");
73 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/4.png");
74 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/5.png");
75 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/6.png");
76 |
77 | TextLogUtil.println(logTextView, "Start downloading emoji package (emojiId: " + emojiPackage.emojiId + ") with " + emojiPackage.emojiUrls.size() + " URLs");
78 | emojiDownloader.startDownloadEmoji(emojiPackage);
79 |
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v1/TaskQueueDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v1;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.widget.TextView;
22 | import com.zhangtielei.demos.async.programming.R;
23 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
24 |
25 | import java.util.Random;
26 | import java.util.concurrent.TimeUnit;
27 |
28 | /**
29 | * 演示基于TSQ的任务队列的运行情况.
30 | */
31 | public class TaskQueueDemoActivity extends AppCompatActivity {
32 | private TextView description;
33 | private TextView logTextView;
34 |
35 | private TaskQueue taskQueue;
36 |
37 | private static long taskIdCounter;
38 | private Random rand1 = new Random();
39 | private Random rand2 = new Random();
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_log_display);
45 |
46 | description = (TextView) findViewById(R.id.description);
47 | logTextView = (TextView) findViewById(R.id.log_display);
48 |
49 | description.setText(R.string.queueing_demo1_description);
50 |
51 | taskQueue = new TSQBasedTaskQueue();
52 | taskQueue.setListener(new TaskQueue.TaskQueueListener() {
53 | @Override
54 | public void taskComplete(Task task) {
55 | TextLogUtil.println(logTextView, "Task (" + task.getTaskId() + ") complete");
56 | }
57 |
58 | @Override
59 | public void taskFailed(Task task, Throwable cause) {
60 | TextLogUtil.println(logTextView, "Task (" + task.getTaskId() + ") failed, error message: " + cause.getMessage());
61 | }
62 | });
63 |
64 | /**
65 | * 启动5个任务
66 | */
67 | for (int i = 0; i < 5; i++) {
68 | Task task = new Task() {
69 | private String taskId = String.valueOf(++taskIdCounter);
70 |
71 | @Override
72 | public void run() {
73 | //任务随机执行0~3秒
74 | try {
75 | TimeUnit.MILLISECONDS.sleep(rand1.nextInt(3000));
76 | } catch (InterruptedException e) {
77 | e.printStackTrace();
78 | }
79 |
80 | //模拟失败情况: 以80%的概率失败
81 | if (rand2.nextInt(10) < 8) {
82 | throw new RuntimeException("runtime error...");
83 | }
84 | }
85 |
86 | @Override
87 | public String getTaskId() {
88 | return taskId;
89 | }
90 | };
91 | TextLogUtil.println(logTextView, "Add task (" + task.getTaskId() + ") to queue");
92 | taskQueue.addTask(task);
93 | }
94 |
95 | }
96 |
97 | @Override
98 | protected void onDestroy() {
99 | taskQueue.setListener(null);
100 | taskQueue.destroy();
101 |
102 | super.onDestroy();
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
26 |
27 |
30 |
31 |
34 |
35 |
36 |
40 |
41 |
42 |
45 |
46 |
49 |
50 |
53 |
54 |
57 |
58 |
61 |
62 |
65 |
66 |
69 |
70 |
73 |
74 |
77 |
78 |
81 |
82 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/EmojiDownloadDemoListActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.callback.emoji;
18 |
19 | import android.content.Intent;
20 | import android.content.res.Resources;
21 | import android.os.Bundle;
22 | import android.support.v7.app.AppCompatActivity;
23 | import android.view.View;
24 | import android.widget.AdapterView;
25 | import android.widget.ArrayAdapter;
26 | import android.widget.ListAdapter;
27 | import android.widget.ListView;
28 | import com.zhangtielei.demos.async.programming.R;
29 | import com.zhangtielei.demos.async.programming.callback.emoji.v1.EmojiDownloadDemoActivity;
30 |
31 | /**
32 | * 表情包下载演示程序入口列表
33 | */
34 | public class EmojiDownloadDemoListActivity extends AppCompatActivity {
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_item_list);
40 |
41 | ListView listView = (ListView) findViewById(R.id.item_list);
42 | Resources resources = getResources();
43 | String[] textList = new String[] {
44 | resources.getString(R.string.emoji_download_demo_1),
45 | resources.getString(R.string.emoji_download_demo_2),
46 | resources.getString(R.string.emoji_download_demo_3),
47 | resources.getString(R.string.emoji_download_demo_4),
48 | };
49 | ListAdapter listAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, textList);
50 | listView.setAdapter(listAdapter);
51 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
52 | @Override
53 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
54 | switch (position) {
55 | case 0:
56 | {
57 | Intent intent = new Intent(EmojiDownloadDemoListActivity.this, EmojiDownloadDemoActivity.class);
58 | startActivity(intent);
59 | break;
60 | }
61 | case 1:
62 | {
63 | Intent intent = new Intent(EmojiDownloadDemoListActivity.this, com.zhangtielei.demos.async.programming.callback.emoji.v2.EmojiDownloadDemoActivity.class);
64 | startActivity(intent);
65 | break;
66 | }
67 | case 2:
68 | {
69 | Intent intent = new Intent(EmojiDownloadDemoListActivity.this, com.zhangtielei.demos.async.programming.callback.emoji.v3.EmojiDownloadDemoActivity.class);
70 | startActivity(intent);
71 | break;
72 | }
73 | case 3:
74 | {
75 | Intent intent = new Intent(EmojiDownloadDemoListActivity.this, com.zhangtielei.demos.async.programming.callback.emoji.v4.EmojiDownloadDemoActivity.class);
76 | startActivity(intent);
77 | break;
78 | }
79 | default:
80 | break;
81 | }
82 | }
83 | });
84 |
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/MultiTaskDemoListActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask;
18 |
19 | import android.content.Intent;
20 | import android.content.res.Resources;
21 | import android.os.Bundle;
22 | import android.support.v7.app.AppCompatActivity;
23 | import android.view.View;
24 | import android.widget.AdapterView;
25 | import android.widget.ArrayAdapter;
26 | import android.widget.ListAdapter;
27 | import android.widget.ListView;
28 | import com.zhangtielei.demos.async.programming.R;
29 | import com.zhangtielei.demos.async.programming.multitask.multilevelcaching.ImageLoaderDemoActivity;
30 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.PageCachingDemoActivity;
31 |
32 | /**
33 | * 多个任务同时执行的演示程序入口列表页面.
34 | */
35 | public class MultiTaskDemoListActivity extends AppCompatActivity {
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.activity_item_list);
41 |
42 | ListView listView = (ListView) findViewById(R.id.item_list);
43 | Resources resources = getResources();
44 | String[] textList = new String[] {
45 | resources.getString(R.string.multitask_demo_1),
46 | resources.getString(R.string.multitask_demo_2),
47 | resources.getString(R.string.multitask_demo_3),
48 | resources.getString(R.string.multitask_demo_4),
49 | };
50 | ListAdapter listAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, textList);
51 | listView.setAdapter(listAdapter);
52 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
53 | @Override
54 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
55 | switch (position) {
56 | case 0:
57 | {
58 | Intent intent = new Intent(MultiTaskDemoListActivity.this, ImageLoaderDemoActivity.class);
59 | startActivity(intent);
60 | break;
61 | }
62 | case 1:
63 | {
64 | Intent intent = new Intent(MultiTaskDemoListActivity.this, com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.MultiRequestsDemoActivity.class);
65 | startActivity(intent);
66 | break;
67 | }
68 | case 2:
69 | {
70 | Intent intent = new Intent(MultiTaskDemoListActivity.this, PageCachingDemoActivity.class);
71 | startActivity(intent);
72 | break;
73 | }
74 | case 3:
75 | {
76 | Intent intent = new Intent(MultiTaskDemoListActivity.this, com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.rxjavasolution.MultiRequestsDemoActivity.class);
77 | startActivity(intent);
78 | break;
79 | }
80 | default:
81 | break;
82 | }
83 | }
84 | });
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/v3/EmojiDownloadDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.callback.emoji.v3;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.widget.TextView;
22 | import com.zhangtielei.demos.async.programming.R;
23 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloader;
24 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiPackage;
25 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
26 |
27 | import java.util.ArrayList;
28 |
29 | /**
30 | * 通过为每一个异步任务创建一个接口实例的方式来传递上下文的表情包下载演示页面.
31 | */
32 | public class EmojiDownloadDemoActivity extends AppCompatActivity {
33 | private TextView description;
34 | private TextView logTextView;
35 |
36 | private EmojiDownloader emojiDownloader;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_log_display);
42 |
43 | description = (TextView) findViewById(R.id.description);
44 | logTextView = (TextView) findViewById(R.id.log_display);
45 |
46 | description.setText(R.string.emoji_download_demo3_description);
47 |
48 | emojiDownloader = new MyEmojiDownloader();
49 | emojiDownloader.setEmojiDownloadListener(new EmojiDownloader.EmojiDownloadListener() {
50 | @Override
51 | public void emojiDownloadSuccess(EmojiPackage emojiPackage) {
52 | TextLogUtil.println(logTextView, "emoji package (emojiId: " + emojiPackage.emojiId + ") downloaded success!");
53 | }
54 |
55 | @Override
56 | public void emojiDownloadFailed(EmojiPackage emojiPackage, int errorCode, String errorMessage) {
57 | TextLogUtil.println(logTextView, "emoji package (emojiId: " + emojiPackage.emojiId + ") downloaded failed! errorCode: " + errorCode + ", errorMessage: " + errorMessage);
58 | }
59 |
60 | @Override
61 | public void emojiDownloadProgress(EmojiPackage emojiPackage, String downloadEmojiUrl) {
62 | TextLogUtil.println(logTextView, "progress: " + downloadEmojiUrl + " downloaded...");
63 | }
64 | });
65 |
66 | //构造要下载的表情包
67 | EmojiPackage emojiPackage = new EmojiPackage();
68 | emojiPackage.emojiId = 1003;
69 | emojiPackage.emojiUrls = new ArrayList();
70 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/1.png");
71 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/2.png");
72 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/3.png");
73 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/4.png");
74 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/5.png");
75 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/6.png");
76 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/7.png");
77 | emojiPackage.emojiUrls.add("http://zhangtielei.com/demourls/8.png");
78 |
79 | TextLogUtil.println(logTextView, "Start downloading emoji package (emojiId: " + emojiPackage.emojiId + ") with " + emojiPackage.emojiUrls.size() + " URLs");
80 | emojiDownloader.startDownloadEmoji(emojiPackage);
81 |
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming;
17 |
18 | import android.content.Intent;
19 | import android.content.res.Resources;
20 | import android.os.Bundle;
21 | import android.support.v7.app.AppCompatActivity;
22 | import android.view.View;
23 | import android.widget.AdapterView;
24 | import android.widget.ArrayAdapter;
25 | import android.widget.ListAdapter;
26 | import android.widget.ListView;
27 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloadDemoListActivity;
28 | import com.zhangtielei.demos.async.programming.introduction.servicebinding.ServiceBindingDemoActivity;
29 | import com.zhangtielei.demos.async.programming.multitask.MultiTaskDemoListActivity;
30 | import com.zhangtielei.demos.async.programming.queueing.QueueingDemoListActivity;
31 |
32 | /**
33 | * 演示程序的入口页面.
34 | */
35 | public class MainActivity extends AppCompatActivity {
36 |
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_item_list);
42 |
43 | ListView listView = (ListView) findViewById(R.id.item_list);
44 | Resources resources = getResources();
45 | String[] textList = new String[] {
46 | resources.getString(R.string.blog_title_1),
47 | resources.getString(R.string.blog_title_2),
48 | resources.getString(R.string.blog_title_3),
49 | resources.getString(R.string.blog_title_4),
50 | resources.getString(R.string.blog_title_5),
51 | resources.getString(R.string.blog_title_6),
52 | resources.getString(R.string.blog_title_7),
53 | };
54 | ListAdapter listAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, textList);
55 | listView.setAdapter(listAdapter);
56 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
57 | @Override
58 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
59 | switch (position) {
60 | case 0:
61 | {
62 | Intent intent = new Intent(MainActivity.this, ServiceBindingDemoActivity.class);
63 | startActivity(intent);
64 | break;
65 | }
66 | case 1:
67 | {
68 | Intent intent = new Intent(MainActivity.this, EmojiDownloadDemoListActivity.class);
69 | startActivity(intent);
70 | break;
71 | }
72 | case 2:
73 | {
74 | Intent intent = new Intent(MainActivity.this, MultiTaskDemoListActivity.class);
75 | startActivity(intent);
76 | break;
77 | }
78 | case 3:
79 | {
80 | Intent intent = new Intent(MainActivity.this, QueueingDemoListActivity.class);
81 | startActivity(intent);
82 | break;
83 | }
84 | case 4:
85 | break;
86 | case 5:
87 | break;
88 | case 6:
89 | break;
90 | default:
91 | break;
92 | }
93 | }
94 | });
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v2/CallbackBasedTaskQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v2;
18 |
19 |
20 | import android.util.Log;
21 |
22 | import java.util.LinkedList;
23 | import java.util.Queue;
24 |
25 | /**
26 | * Created by Tielei Zhang on 16/9/1.
27 | *
28 | * 基于Callback机制的队列实现
29 | */
30 | public class CallbackBasedTaskQueue implements TaskQueue, Task.TaskListener {
31 | private static final String TAG = "TaskQueue";
32 |
33 | /**
34 | * Task排队的队列. 不需要thread-safe
35 | */
36 | private Queue taskQueue = new LinkedList();
37 |
38 | private TaskQueueListener listener;
39 | private boolean stopped;
40 |
41 | /**
42 | * 一个任务最多重试次数.
43 | * 重试次数超过MAX_RETRIES, 任务则最终失败.
44 | */
45 | private static final int MAX_RETRIES = 3;
46 | /**
47 | * 当前任务的执行次数记录(当尝试超过MAX_RETRIES时就最终失败)
48 | */
49 | private int runCount;
50 |
51 | @Override
52 | public void addTask(Task task) {
53 | //新任务加入队列
54 | taskQueue.offer(task);
55 | task.setListener(this);
56 |
57 | if (taskQueue.size() == 1 && !stopped) {
58 | //当前是第一个排队任务, 立即执行它
59 | launchNextTask();
60 | }
61 | }
62 |
63 | @Override
64 | public void setListener(TaskQueueListener listener) {
65 | this.listener = listener;
66 | }
67 |
68 | @Override
69 | public void destroy() {
70 | stopped = true;
71 | }
72 |
73 | private void launchNextTask() {
74 | //取当前队列头的任务, 但不出队列
75 | Task task = taskQueue.peek();
76 | if (task == null) {
77 | //impossible case
78 | Log.e(TAG, "impossible: NO task in queue, unexpected!");
79 | return;
80 | }
81 |
82 | Log.d(TAG, "start task (" + task.getTaskId() + ")");
83 | task.start();
84 | runCount = 1;
85 | }
86 |
87 | @Override
88 | public void taskComplete(Task task) {
89 | Log.d(TAG, "task (" + task.getTaskId() + ") complete");
90 | finishTask(task, null);
91 | }
92 |
93 | @Override
94 | public void taskFailed(Task task, Throwable error) {
95 | if (runCount < MAX_RETRIES && !stopped) {
96 | //可以继续尝试
97 | Log.d(TAG, "task (" + task.getTaskId() + ") failed, try again. runCount: " + runCount);
98 | task.start();
99 | runCount++;
100 | }
101 | else {
102 | //最终失败
103 | Log.d(TAG, "task (" + task.getTaskId() + ") failed, final failed! runCount: " + runCount);
104 | finishTask(task, error);
105 | }
106 | }
107 |
108 | /**
109 | * 一个任务最终结束(成功或最终失败)后的处理
110 | * @param task
111 | * @param error
112 | */
113 | private void finishTask(Task task, Throwable error) {
114 | //回调
115 | if (listener != null && !stopped) {
116 | try {
117 | if (error == null) {
118 | listener.taskComplete(task);
119 | }
120 | else {
121 | listener.taskFailed(task, error);
122 | }
123 | }
124 | catch (Throwable e) {
125 | Log.e(TAG, "", e);
126 | }
127 | }
128 | task.setListener(null);
129 |
130 | //出队列
131 | taskQueue.poll();
132 |
133 | //启动队列下一个任务
134 | if (taskQueue.size() > 0 && !stopped) {
135 | launchNextTask();
136 | }
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | AsyncProgramming
19 |
20 | (一)异步处理概述举例
21 | (二)异步任务的回调
22 | (三)多个异步任务协作
23 | (四)异步任务和队列
24 | (五)异步任务的取消和暂停,以及start ID(未完成)
25 | (六)关于封屏与不封屏(未完成)
26 | (七)Android Service实例分析(未完成)
27 |
28 | (1)演示通过全局保存一份上下文来实现表情包下载
29 | (2)演示通过映射关系保存上下文来实现表情包下载
30 | (3)演示采用为每一个异步任务创建一个接口实例的方式来实现表情包下载
31 | (4)演示利用支持上下文传递的异步接口来实现表情包下载
32 |
33 | (1)通过一个静态图片多级缓存的例子,演示"多个异步任务先后接续执行"
34 | (2)通过一个同时发起多个网络请求的例子,演示"多个异步任务并发执行,结果合并"
35 | (3)通过一个页面缓存的例子,演示"多个异步任务并发执行,一方优先"
36 | (4)演示使用RxJava zip来实现并发网络请求
37 |
38 | (1)演示TSQ实现的任务队列
39 | (2)演示通过普通的"异步+Callback"方式实现的任务队列
40 | (3)演示使用RxJava实现的任务队列
41 |
42 | 本页面用于演示绑定和解绑一个Service的异步过程
43 | 本页面通过实现一个表情包下载器,来演示全局保存一份上下文的技术
44 | 本页面通过实现一个表情包下载器,来演示用映射关系来保存上下文的技术
45 | 本页面通过实现一个表情包下载器,来演示为每一个异步任务创建一个接口实例来传递上下文的技术
46 | 本页面通过实现一个表情包下载器,来演示利用一个支持上下文传递的异步接口的上下文传递方式(推荐方式)
47 | 本页面通过调用一个带有多级缓存的图片下载器,来演示"多个异步任务先后接续执行"的多任务协作关系
48 | 本页面通过同时发起多个网络请求的例子,来演示"多个异步任务并发执行,全部完成"的多任务协作关系(注意: 本实例多次执行会产生不同的执行时序)
49 | 本页面通过一个页面缓存的例子,来演示"多个异步任务并发执行,优先完成"的多任务协作关系(注意: 本实例多次执行会产生不同的执行时序)
50 | 本页面用于演示如何使用RxJava的zip操作来处理并发的两个请求(注意: 本实例多次执行会产生不同的执行时序)
51 |
52 | 本页面演示使用TSQ来实现任务队列(这种方式在客户端编程中很少见)
53 | 本页面演示使用"异步+Callback"方式实现任务队列
54 | 本页面演示使用RxJava实现任务队列
55 |
56 |
57 | MultiRequestsDemoActivity
58 | PageCachingDemoActivity
59 | ServiceBindingDemoActivity
60 | EmojiDownloadDemoListActivity
61 | EmojiDownloadDemoActivity
62 | MultiTaskDemoListActivity
63 | ImageLoaderDemoActivity
64 | TaskQueueDemoActivity
65 |
66 | Hello world!
67 | Settings
68 | QueueingDemoListActivity
69 |
70 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/introduction/servicebinding/ServiceBindingDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.introduction.servicebinding;
18 |
19 | import android.content.ComponentName;
20 | import android.content.Context;
21 | import android.content.Intent;
22 | import android.content.ServiceConnection;
23 | import android.os.Bundle;
24 | import android.os.IBinder;
25 | import android.support.v7.app.AppCompatActivity;
26 | import android.widget.TextView;
27 | import com.zhangtielei.demos.async.programming.R;
28 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
29 | import com.zhangtielei.demos.async.programming.introduction.servicebinding.service.SomeService;
30 |
31 | /**
32 | * 用于演示最普通的Service绑定和解绑.
33 | */
34 | public class ServiceBindingDemoActivity extends AppCompatActivity implements SomeService.ServiceListener {
35 | /**
36 | * 对于Service的引用
37 | */
38 | private SomeService someService;
39 | /**
40 | * 指示本Activity是否处于running状态:执行过onResume就变为running状态。
41 | */
42 | private boolean running;
43 |
44 | private TextView description;
45 | private TextView logTextView;
46 |
47 | private ServiceConnection serviceConnection = new ServiceConnection() {
48 | @Override
49 | public void onServiceDisconnected(ComponentName name) {
50 | //解除Activity与Service的引用和监听关系
51 | //...
52 | if (someService != null) {
53 | someService.removeListener(ServiceBindingDemoActivity.this);
54 | someService = null;
55 | }
56 | TextLogUtil.println(logTextView, "disconnected to SomeService...");
57 | }
58 |
59 | @Override
60 | public void onServiceConnected(ComponentName name, IBinder service) {
61 | if (running) {
62 | //建立Activity与Service的引用和监听关系
63 | //...
64 | SomeService.ServiceBinder binder = (SomeService.ServiceBinder) service;
65 | someService = binder.getService();
66 | someService.addListener(ServiceBindingDemoActivity.this);
67 | TextLogUtil.println(logTextView, "bound to SomeService...");
68 | }
69 | }
70 | };
71 |
72 | @Override
73 | protected void onCreate(Bundle savedInstanceState) {
74 | super.onCreate(savedInstanceState);
75 | setContentView(R.layout.activity_log_display);
76 |
77 | description = (TextView) findViewById(R.id.description);
78 | logTextView = (TextView) findViewById(R.id.log_display);
79 |
80 | description.setText(R.string.service_binding_description);
81 |
82 | }
83 |
84 | @Override
85 | public void onResume() {
86 | super.onResume();
87 | running = true;
88 |
89 | Intent intent = new Intent(this, SomeService.class);
90 | bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
91 | TextLogUtil.println(logTextView, "Requesting bind to SomeService...");
92 | }
93 |
94 | @Override
95 | public void onPause() {
96 | super.onPause();
97 | running = false;
98 |
99 | //解除Activity与Service的引用和监听关系
100 | //...
101 | if (someService != null) {
102 | someService.removeListener(ServiceBindingDemoActivity.this);
103 | someService = null;
104 | }
105 | unbindService(serviceConnection);
106 | TextLogUtil.println(logTextView, "unbind to SomeService...");
107 | }
108 |
109 | @Override
110 | public void callback() {
111 | //TODO:
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/http/mock/MockHttpService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.http.mock;
18 |
19 | import android.os.Handler;
20 | import android.os.Looper;
21 | import com.zhangtielei.demos.async.programming.multitask.http.HttpListener;
22 | import com.zhangtielei.demos.async.programming.multitask.http.HttpResult;
23 | import com.zhangtielei.demos.async.programming.multitask.http.HttpService;
24 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.model.HttpRequest;
25 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.model.HttpResponse;
26 | import com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.model.HttpRequest1;
27 | import com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.model.HttpRequest2;
28 | import com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.model.HttpResponse1;
29 | import com.zhangtielei.demos.async.programming.multitask.simultaneousrequests.model.HttpResponse2;
30 |
31 | import java.util.Date;
32 | import java.util.Random;
33 | import java.util.concurrent.ExecutorService;
34 | import java.util.concurrent.Executors;
35 | import java.util.concurrent.TimeUnit;
36 |
37 | /**
38 | * Created by Tielei Zhang on 16/5/17.
39 | *
40 | * HttpService的一个假的实现.
41 | */
42 | public class MockHttpService implements HttpService {
43 | private ExecutorService executorService = Executors.newCachedThreadPool();
44 | private Handler mainHandler = new Handler(Looper.getMainLooper());
45 | private Random rand = new Random();
46 |
47 | @Override
48 | public void doRequest(final String apiUrl, final T request, final HttpListener super T, R> listener, final Object contextData) {
49 | executorService.execute(new Runnable() {
50 | @Override
51 | public void run() {
52 | //模拟请求执行, 随机执行0~3秒
53 | try {
54 | TimeUnit.MILLISECONDS.sleep(rand.nextInt(3000));
55 | } catch (InterruptedException e) {
56 | e.printStackTrace();
57 | }
58 |
59 | //模拟一个返回结果
60 | Object httpResponse = generateResponse(request);
61 | final HttpResult result = new HttpResult();
62 | result.setErrorCode(HttpResult.SUCCESS);
63 | result.setResponse((R) httpResponse);
64 |
65 | //回调
66 | mainHandler.post(new Runnable() {
67 | @Override
68 | public void run() {
69 | if (listener != null) {
70 | try {
71 | listener.onResult(apiUrl, request, result, contextData);
72 | }
73 | catch (Throwable e) {
74 | e.printStackTrace();
75 | }
76 | }
77 | }
78 | });
79 | }
80 | });
81 | }
82 |
83 | private Object generateResponse(Object httpRequest) {
84 | //hard code
85 | if (httpRequest instanceof HttpRequest1) {
86 | HttpResponse1 response1 = new HttpResponse1();
87 | response1.setText("Data from HttpRequest1. timestamp: " + new Date());
88 | return response1;
89 | }
90 | else if (httpRequest instanceof HttpRequest2) {
91 | HttpResponse2 response2 = new HttpResponse2();
92 | response2.setText("Data from HttpRequest2. timestamp: " + new Date());
93 | return response2;
94 | }
95 | else if (httpRequest instanceof HttpRequest) {
96 | HttpResponse response = new HttpResponse();
97 | return response;
98 | }
99 | return null;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v1/TSQBasedTaskQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v1;
18 |
19 | import android.os.Handler;
20 | import android.os.Looper;
21 | import android.util.Log;
22 |
23 | import java.util.concurrent.BlockingQueue;
24 | import java.util.concurrent.LinkedBlockingQueue;
25 | import java.util.concurrent.atomic.AtomicBoolean;
26 |
27 | /**
28 | * Created by Tielei Zhang on 16/8/31.
29 | *
30 | * 基于TSQ (Thread-Safe Queue)的队列实现
31 | */
32 | public class TSQBasedTaskQueue implements TaskQueue {
33 | private static final String TAG = "TaskQueue";
34 |
35 | private BlockingQueue taskBlockingQueue = new LinkedBlockingQueue();
36 | private Thread consumerThread;
37 | private AtomicBoolean stopped = new AtomicBoolean(false);
38 |
39 | private TaskQueueListener listener;
40 |
41 | private Handler mainHandler = new Handler(Looper.getMainLooper());
42 |
43 | /**
44 | * 一个任务最多重试次数.
45 | * 重试次数超过MAX_RETRIES, 任务则最终失败.
46 | */
47 | private static final int MAX_RETRIES = 3;
48 |
49 | public TSQBasedTaskQueue() {
50 | //创建消费者线程
51 | consumerThread = new Thread() {
52 | @Override
53 | public void run() {
54 | while (!stopped.get() && !Thread.interrupted()) {
55 | try {
56 | Task task = taskBlockingQueue.take();
57 |
58 | int retryCount = 0;
59 | boolean runSuccess = false;
60 | Throwable error = null;
61 | while (!stopped.get() && retryCount < MAX_RETRIES && !runSuccess) {
62 | try {
63 | task.run();
64 | //任务成功执行完了
65 | runSuccess = true;
66 | }
67 | catch (Throwable e) {
68 | error = e;
69 | }
70 | retryCount++;
71 | }
72 |
73 | if (runSuccess) {
74 | callbackSuccess(task);
75 | }
76 | else {
77 | callbackFailed(task, error);
78 | }
79 |
80 | } catch (InterruptedException e) {
81 | //退出了
82 | }
83 | }
84 | Log.i(TAG, "TSQ thread exit...");
85 | }
86 | };
87 | consumerThread.start();
88 | }
89 |
90 | @Override
91 | public void addTask(Task task) {
92 | try {
93 | taskBlockingQueue.put(task);
94 | } catch (InterruptedException e) {
95 | callbackFailed(task, e);
96 | Log.e(TAG, "", e);
97 | }
98 | }
99 |
100 | @Override
101 | public void setListener(TaskQueueListener listener) {
102 | this.listener = listener;
103 | }
104 |
105 | @Override
106 | public void destroy() {
107 | stopped.set(true);
108 | consumerThread.interrupt();
109 | }
110 |
111 | private void callbackSuccess(Task task) {
112 | callbackToListener(task, null);
113 | }
114 |
115 | private void callbackFailed(Task task, Throwable error) {
116 | callbackToListener(task, error);
117 | }
118 |
119 | private void callbackToListener(final Task task, final Throwable error) {
120 | mainHandler.post(new Runnable() {
121 | @Override
122 | public void run() {
123 | try {
124 | if (listener != null) {
125 | if (error == null) {
126 | listener.taskComplete(task);
127 | }
128 | else {
129 | listener.taskFailed(task, error);
130 | }
131 | }
132 | }
133 | catch (Throwable e) {
134 | Log.e(TAG, "", e);
135 | }
136 | }
137 | });
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/multitask/pagecaching/PageCachingDemoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.multitask.pagecaching;
18 |
19 | import android.os.Bundle;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.widget.TextView;
22 | import com.zhangtielei.demos.async.programming.R;
23 | import com.zhangtielei.demos.async.programming.common.AsyncCallback;
24 | import com.zhangtielei.demos.async.programming.common.utils.TextLogUtil;
25 | import com.zhangtielei.demos.async.programming.multitask.http.HttpListener;
26 | import com.zhangtielei.demos.async.programming.multitask.http.HttpResult;
27 | import com.zhangtielei.demos.async.programming.multitask.http.HttpService;
28 | import com.zhangtielei.demos.async.programming.multitask.http.mock.MockHttpService;
29 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.localcache.LocalDataCache;
30 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.localcache.mock.MockLocalDataCache;
31 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.model.HttpRequest;
32 | import com.zhangtielei.demos.async.programming.multitask.pagecaching.model.HttpResponse;
33 |
34 | /**
35 | * 演示Page Caching的异步处理过程.
36 | *
37 | * Page Caching策略: 页面打开后先展示本地缓存数据, 然后API请求返回数据后, 再重新刷新页面.
38 | */
39 | public class PageCachingDemoActivity extends AppCompatActivity {
40 | private TextView description;
41 | private TextView logTextView;
42 |
43 | private HttpService httpService = new MockHttpService();
44 | private LocalDataCache localDataCache = new MockLocalDataCache();
45 | /**
46 | * 从Http请求到的数据是否已经返回
47 | */
48 | private boolean dataFromHttpReady;
49 |
50 | @Override
51 | protected void onCreate(Bundle savedInstanceState) {
52 | super.onCreate(savedInstanceState);
53 | setContentView(R.layout.activity_log_display);
54 |
55 | description = (TextView) findViewById(R.id.description);
56 | logTextView = (TextView) findViewById(R.id.log_display);
57 |
58 | description.setText(R.string.pagecaching_demo_description);
59 |
60 | //同时发起本地数据请求和远程Http请求
61 | final String userId = "xxx";
62 | TextLogUtil.println(logTextView, "Start requesting local data cache...");
63 | localDataCache.getCachingData(userId, new AsyncCallback() {
64 | @Override
65 | public void onResult(HttpResponse data) {
66 | TextLogUtil.println(logTextView, "Data from local data cache: " + data);
67 |
68 | if (data != null && !dataFromHttpReady) {
69 | //缓存有旧数据 & 远程Http请求还没返回,先显示旧数据
70 | processData(data);
71 | }
72 | else if (data != null && dataFromHttpReady) {
73 | //只是打印一行日志
74 | TextLogUtil.println(logTextView, "Data from local data cache is ignored.");
75 | }
76 | }
77 | });
78 | TextLogUtil.println(logTextView, "Start requesting HTTP...");
79 | httpService.doRequest("http://...", new HttpRequest(),
80 | new HttpListener() {
81 | @Override
82 | public void onResult(String apiUrl,
83 | HttpRequest request,
84 | HttpResult result,
85 | Object contextData) {
86 | TextLogUtil.println(logTextView, "Data from HTTP: " + result.getResponse());
87 | if (result.getErrorCode() == HttpResult.SUCCESS) {
88 | dataFromHttpReady = true;
89 | processData(result.getResponse());
90 | //从Http拉到最新数据, 更新本地缓存
91 | localDataCache.putCachingData(userId, result.getResponse(), null);
92 | }
93 | else {
94 | processError(result.getErrorCode());
95 | }
96 | }
97 | },
98 | null);
99 | }
100 |
101 |
102 | private void processData(HttpResponse data) {
103 | TextLogUtil.println(logTextView, "Got data success: " + data);
104 | }
105 |
106 | private void processError(int errorCode) {
107 | TextLogUtil.println(logTextView, "Got data failed. errorCode: " + errorCode);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/v1/MyEmojiDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.emoji.v1;
17 |
18 | import com.zhangtielei.demos.async.programming.callback.download.v2.DownloadListener;
19 | import com.zhangtielei.demos.async.programming.callback.download.v2.Downloader;
20 | import com.zhangtielei.demos.async.programming.callback.download.v2.MyDownloader;
21 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloadContext;
22 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloader;
23 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiPackage;
24 |
25 | import java.util.List;
26 |
27 | /**
28 | * Created by Tielei Zhang on 16/5/1.
29 | * EmojiDownloader的第1个版本的实现: 使用全局一份上下文结构.
30 | */
31 | public class MyEmojiDownloader implements EmojiDownloader, DownloadListener {
32 | /**
33 | * 全局保存一份的表情包下载上下文.
34 | */
35 | private EmojiDownloadContext downloadContext;
36 |
37 | private Downloader downloader;
38 | private EmojiDownloadListener listener;
39 |
40 | public MyEmojiDownloader() {
41 | //实例化有一个下载器.
42 | downloader = new MyDownloader();
43 | downloader.setListener(this);
44 | }
45 |
46 | @Override
47 | public void startDownloadEmoji(EmojiPackage emojiPackage) {
48 | if (downloadContext == null) {
49 | //创建下载上下文数据
50 | downloadContext = new EmojiDownloadContext();
51 | downloadContext.emojiPackage = emojiPackage;
52 | //启动第0个表情图片文件的下载
53 | downloader.startDownload(emojiPackage.emojiUrls.get(0),
54 | getLocalPathForEmoji(emojiPackage, 0));
55 | }
56 | }
57 |
58 | @Override
59 | public void setEmojiDownloadListener(EmojiDownloadListener listener) {
60 | this.listener = listener;
61 | }
62 |
63 | @Override
64 | public void downloadSuccess(String url, String localPath) {
65 | downloadContext.localPathList.add(localPath);
66 | downloadContext.downloadedEmoji++;
67 | EmojiPackage emojiPackage = downloadContext.emojiPackage;
68 | if (downloadContext.downloadedEmoji < emojiPackage.emojiUrls.size()) {
69 | //还没下载完, 产生一个进度回调
70 | try {
71 | if (listener != null) {
72 | listener.emojiDownloadProgress(emojiPackage, url);
73 | }
74 | }
75 | catch (Throwable e) {
76 | e.printStackTrace();
77 | }
78 | //继续下载下一个表情图片
79 | String nextUrl = emojiPackage.emojiUrls.get(downloadContext.downloadedEmoji);
80 | downloader.startDownload(nextUrl,
81 | getLocalPathForEmoji(emojiPackage, downloadContext.downloadedEmoji));
82 | }
83 | else {
84 | //已经下载完
85 | installEmojiPackageLocally(emojiPackage, downloadContext.localPathList);
86 |
87 | downloadContext = null;//这个状态清理操作应该在回调之前
88 |
89 | //成功回调
90 | try {
91 | if (listener != null) {
92 | listener.emojiDownloadProgress(emojiPackage, url);//最后一次进度回调.
93 | listener.emojiDownloadSuccess(emojiPackage);
94 | }
95 | }
96 | catch (Throwable e) {
97 | e.printStackTrace();
98 | }
99 | }
100 | }
101 |
102 | @Override
103 | public void downloadFailed(String url, int errorCode, String errorMessage) {
104 | EmojiPackage emojiPackage = downloadContext.emojiPackage;
105 |
106 | downloadContext = null;//这个状态清理操作应该在回调之前
107 |
108 | //失败回调
109 | try {
110 | if (listener != null) {
111 | listener.emojiDownloadFailed(emojiPackage, errorCode, errorMessage);
112 | }
113 | }
114 | catch (Throwable e) {
115 | e.printStackTrace();
116 | }
117 | }
118 |
119 | @Override
120 | public void downloadProgress(String url, long downloadedSize, long totalSize) {
121 | //TODO:
122 | }
123 |
124 | /**
125 | * 计算表情包中第i个表情图片文件的下载地址.
126 | * @param emojiPackage
127 | * @param i
128 | * @return
129 | */
130 | private String getLocalPathForEmoji(EmojiPackage emojiPackage, int i) {
131 | //TODO:
132 | return null;
133 | }
134 |
135 | /**
136 | * 把表情包安装到本地
137 | * @param emojiPackage
138 | * @param localPathList
139 | */
140 | private void installEmojiPackageLocally(EmojiPackage emojiPackage, List localPathList) {
141 | //TODO:
142 | return;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/v4/MyEmojiDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.emoji.v4;
17 |
18 |
19 | import com.zhangtielei.demos.async.programming.callback.download.v3.DownloadListener;
20 | import com.zhangtielei.demos.async.programming.callback.download.v3.Downloader;
21 | import com.zhangtielei.demos.async.programming.callback.download.v3.MyDownloader;
22 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloadContext;
23 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloader;
24 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiPackage;
25 |
26 | import java.util.List;
27 |
28 | /**
29 | * Created by Tielei Zhang on 16/5/2.
30 | * EmojiDownloader的第4个版本的实现: 利用支持上下文传递的异步接口.
31 | */
32 | public class MyEmojiDownloader implements EmojiDownloader, DownloadListener {
33 | private Downloader downloader;
34 | private EmojiDownloadListener listener;
35 |
36 | public MyEmojiDownloader() {
37 | //实例化有一个下载器.
38 | downloader = new MyDownloader();
39 | downloader.setListener(this);
40 | }
41 |
42 | @Override
43 | public void startDownloadEmoji(EmojiPackage emojiPackage) {
44 | //创建下载上下文数据
45 | EmojiDownloadContext downloadContext = new EmojiDownloadContext();
46 | downloadContext.emojiPackage = emojiPackage;
47 | //启动第0个表情图片文件的下载, 上下文参数传递进去
48 | downloader.startDownload(emojiPackage.emojiUrls.get(0),
49 | getLocalPathForEmoji(emojiPackage, 0),
50 | downloadContext);
51 |
52 | }
53 |
54 | @Override
55 | public void setEmojiDownloadListener(EmojiDownloadListener listener) {
56 | this.listener = listener;
57 | }
58 |
59 | @Override
60 | public void downloadSuccess(String url, String localPath, Object contextData) {
61 | //通过回调接口的contextData参数做Down-casting获得上下文参数
62 | EmojiDownloadContext downloadContext = (EmojiDownloadContext) contextData;
63 |
64 | downloadContext.localPathList.add(localPath);
65 | downloadContext.downloadedEmoji++;
66 | EmojiPackage emojiPackage = downloadContext.emojiPackage;
67 | if (downloadContext.downloadedEmoji < emojiPackage.emojiUrls.size()) {
68 | //还没下载完, 产生一个进度回调
69 | try {
70 | if (listener != null) {
71 | listener.emojiDownloadProgress(emojiPackage, url);
72 | }
73 | }
74 | catch (Throwable e) {
75 | e.printStackTrace();
76 | }
77 | //继续下载下一个表情图片
78 | String nextUrl = emojiPackage.emojiUrls.get(downloadContext.downloadedEmoji);
79 | downloader.startDownload(nextUrl,
80 | getLocalPathForEmoji(emojiPackage, downloadContext.downloadedEmoji),
81 | downloadContext);
82 | }
83 | else {
84 | //已经下载完
85 | installEmojiPackageLocally(emojiPackage, downloadContext.localPathList);
86 |
87 | //成功回调
88 | try {
89 | if (listener != null) {
90 | listener.emojiDownloadProgress(emojiPackage, url);//最后一次进度回调.
91 | listener.emojiDownloadSuccess(emojiPackage);
92 | }
93 | }
94 | catch (Throwable e) {
95 | e.printStackTrace();
96 | }
97 | }
98 | }
99 |
100 | @Override
101 | public void downloadFailed(String url, int errorCode, String errorMessage, Object contextData) {
102 | //通过回调接口的contextData参数做Down-casting获得上下文参数
103 | EmojiDownloadContext downloadContext = (EmojiDownloadContext) contextData;
104 | EmojiPackage emojiPackage = downloadContext.emojiPackage;
105 |
106 | //失败回调
107 | try {
108 | if (listener != null) {
109 | listener.emojiDownloadFailed(emojiPackage, errorCode, errorMessage);
110 | }
111 | }
112 | catch (Throwable e) {
113 | e.printStackTrace();
114 | }
115 | }
116 |
117 | @Override
118 | public void downloadProgress(String url, long downloadedSize, long totalSize, Object contextData) {
119 | //TODO:
120 | }
121 |
122 | /**
123 | * 计算表情包中第i个表情图片文件的下载地址.
124 | * @param emojiPackage
125 | * @param i
126 | * @return
127 | */
128 | private String getLocalPathForEmoji(EmojiPackage emojiPackage, int i) {
129 | //TODO:
130 | return null;
131 | }
132 |
133 | /**
134 | * 把表情包安装到本地
135 | * @param emojiPackage
136 | * @param localPathList
137 | */
138 | private void installEmojiPackageLocally(EmojiPackage emojiPackage, List localPathList) {
139 | //TODO:
140 | return;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/v3/MyEmojiDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.emoji.v3;
17 |
18 | import com.zhangtielei.demos.async.programming.callback.download.v2.DownloadListener;
19 | import com.zhangtielei.demos.async.programming.callback.download.v2.MyDownloader;
20 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloadContext;
21 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloader;
22 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiPackage;
23 |
24 | import java.util.List;
25 |
26 | /**
27 | * Created by Tielei Zhang on 16/5/1.
28 | * EmojiDownloader的第3个版本的实现: 为每一个异步任务创建一个接口实例.
29 | */
30 | public class MyEmojiDownloader implements EmojiDownloader {
31 | private EmojiDownloadListener listener;
32 |
33 | @Override
34 | public void startDownloadEmoji(EmojiPackage emojiPackage) {
35 | //创建下载上下文数据
36 | EmojiDownloadContext downloadContext = new EmojiDownloadContext();
37 | downloadContext.emojiPackage = emojiPackage;
38 | //为每一次下载创建一个新的Downloader
39 | final EmojiUrlDownloader downloader = new EmojiUrlDownloader();
40 | //将上下文数据存到downloader实例中
41 | downloader.downloadContext = downloadContext;
42 |
43 | downloader.setListener(new DownloadListener() {
44 | @Override
45 | public void downloadSuccess(String url, String localPath) {
46 | EmojiDownloadContext downloadContext = downloader.downloadContext;
47 | downloadContext.localPathList.add(localPath);
48 | downloadContext.downloadedEmoji++;
49 | EmojiPackage emojiPackage = downloadContext.emojiPackage;
50 | if (downloadContext.downloadedEmoji < emojiPackage.emojiUrls.size()) {
51 | //还没下载完, 产生一个进度回调
52 | try {
53 | if (listener != null) {
54 | listener.emojiDownloadProgress(emojiPackage, url);
55 | }
56 | }
57 | catch (Throwable e) {
58 | e.printStackTrace();
59 | }
60 | //继续下载下一个表情图片
61 | String nextUrl = emojiPackage.emojiUrls.get(downloadContext.downloadedEmoji);
62 | downloader.startDownload(nextUrl,
63 | getLocalPathForEmoji(emojiPackage, downloadContext.downloadedEmoji));
64 | }
65 | else {
66 | //已经下载完
67 | installEmojiPackageLocally(emojiPackage, downloadContext.localPathList);
68 |
69 | //成功回调
70 | try {
71 | if (listener != null) {
72 | listener.emojiDownloadProgress(emojiPackage, url);//最后一次进度回调.
73 | listener.emojiDownloadSuccess(emojiPackage);
74 | }
75 | }
76 | catch (Throwable e) {
77 | e.printStackTrace();
78 | }
79 | }
80 | }
81 |
82 | @Override
83 | public void downloadFailed(String url, int errorCode, String errorMessage) {
84 | EmojiDownloadContext downloadContext = downloader.downloadContext;
85 | EmojiPackage emojiPackage = downloadContext.emojiPackage;
86 |
87 | //失败回调
88 | try {
89 | if (listener != null) {
90 | listener.emojiDownloadFailed(emojiPackage, errorCode, errorMessage);
91 | }
92 | }
93 | catch (Throwable e) {
94 | e.printStackTrace();
95 | }
96 | }
97 |
98 | @Override
99 | public void downloadProgress(String url, long downloadedSize, long totalSize) {
100 | //TODO:
101 | }
102 | });
103 |
104 | //启动第0个表情图片文件的下载
105 | downloader.startDownload(emojiPackage.emojiUrls.get(0),
106 | getLocalPathForEmoji(emojiPackage, 0));
107 | }
108 |
109 | @Override
110 | public void setEmojiDownloadListener(EmojiDownloadListener listener) {
111 | this.listener = listener;
112 | }
113 |
114 | private static class EmojiUrlDownloader extends MyDownloader {
115 | public EmojiDownloadContext downloadContext;
116 | }
117 |
118 | /**
119 | * 计算表情包中第i个表情图片文件的下载地址.
120 | * @param emojiPackage
121 | * @param i
122 | * @return
123 | */
124 | private String getLocalPathForEmoji(EmojiPackage emojiPackage, int i) {
125 | //TODO:
126 | return null;
127 | }
128 |
129 | /**
130 | * 把表情包安装到本地
131 | * @param emojiPackage
132 | * @param localPathList
133 | */
134 | private void installEmojiPackageLocally(EmojiPackage emojiPackage, List localPathList) {
135 | //TODO:
136 | return;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/AndroidDemos/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/callback/emoji/v2/MyEmojiDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.zhangtielei.demos.async.programming.callback.emoji.v2;
17 |
18 | import com.zhangtielei.demos.async.programming.callback.download.v2.DownloadListener;
19 | import com.zhangtielei.demos.async.programming.callback.download.v2.Downloader;
20 | import com.zhangtielei.demos.async.programming.callback.download.v2.MyDownloader;
21 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloadContext;
22 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiDownloader;
23 | import com.zhangtielei.demos.async.programming.callback.emoji.EmojiPackage;
24 |
25 | import java.util.HashMap;
26 | import java.util.List;
27 | import java.util.Map;
28 |
29 | /**
30 | * Created by Tielei Zhang on 16/5/1.
31 | * EmojiDownloader的第2个版本的实现: 用映射关系来保存上下文.
32 | */
33 | public class MyEmojiDownloader implements EmojiDownloader, DownloadListener {
34 | /**
35 | * 保存上下文的映射关系.
36 | * URL -> EmojiDownloadContext
37 | */
38 | private Map downloadContextMap;
39 |
40 | private Downloader downloader;
41 | private EmojiDownloadListener listener;
42 |
43 | public MyEmojiDownloader() {
44 | downloadContextMap = new HashMap();
45 | //实例化有一个下载器.
46 | downloader = new MyDownloader();
47 | downloader.setListener(this);
48 | }
49 |
50 | @Override
51 | public void startDownloadEmoji(EmojiPackage emojiPackage) {
52 | //创建下载上下文数据
53 | EmojiDownloadContext downloadContext = new EmojiDownloadContext();
54 | downloadContext.emojiPackage = emojiPackage;
55 | //为每一个URL创建映射关系
56 | for (String emojiUrl : emojiPackage.emojiUrls) {
57 | downloadContextMap.put(emojiUrl, downloadContext);
58 | }
59 | //启动第0个表情图片文件的下载
60 | downloader.startDownload(emojiPackage.emojiUrls.get(0),
61 | getLocalPathForEmoji(emojiPackage, 0));
62 | }
63 |
64 | @Override
65 | public void setEmojiDownloadListener(EmojiDownloadListener listener) {
66 | this.listener = listener;
67 | }
68 |
69 | @Override
70 | public void downloadSuccess(String url, String localPath) {
71 | EmojiDownloadContext downloadContext = downloadContextMap.get(url);
72 | downloadContext.localPathList.add(localPath);
73 | downloadContext.downloadedEmoji++;
74 | EmojiPackage emojiPackage = downloadContext.emojiPackage;
75 | if (downloadContext.downloadedEmoji < emojiPackage.emojiUrls.size()) {
76 | //还没下载完, 产生一个进度回调
77 | try {
78 | if (listener != null) {
79 | listener.emojiDownloadProgress(emojiPackage, url);
80 | }
81 | }
82 | catch (Throwable e) {
83 | e.printStackTrace();
84 | }
85 | //继续下载下一个表情图片
86 | String nextUrl = emojiPackage.emojiUrls.get(downloadContext.downloadedEmoji);
87 | downloader.startDownload(nextUrl,
88 | getLocalPathForEmoji(emojiPackage, downloadContext.downloadedEmoji));
89 | }
90 | else {
91 | //已经下载完
92 | installEmojiPackageLocally(emojiPackage, downloadContext.localPathList);
93 |
94 | //为每一个URL删除映射关系
95 | //这个状态清理操作应该在回调之前
96 | for (String emojiUrl : emojiPackage.emojiUrls) {
97 | downloadContextMap.remove(emojiUrl);
98 | }
99 |
100 | //成功回调
101 | try {
102 | if (listener != null) {
103 | listener.emojiDownloadProgress(emojiPackage, url);//最后一次进度回调.
104 | listener.emojiDownloadSuccess(emojiPackage);
105 | }
106 | }
107 | catch (Throwable e) {
108 | e.printStackTrace();
109 | }
110 | }
111 | }
112 |
113 | @Override
114 | public void downloadFailed(String url, int errorCode, String errorMessage) {
115 | EmojiDownloadContext downloadContext = downloadContextMap.get(url);
116 | EmojiPackage emojiPackage = downloadContext.emojiPackage;
117 |
118 | //为每一个URL删除映射关系
119 | //这个状态清理操作应该在回调之前
120 | for (String emojiUrl : emojiPackage.emojiUrls) {
121 | downloadContextMap.remove(emojiUrl);
122 | }
123 |
124 | //失败回调
125 | try {
126 | if (listener != null) {
127 | listener.emojiDownloadFailed(emojiPackage, errorCode, errorMessage);
128 | }
129 | }
130 | catch (Throwable e) {
131 | e.printStackTrace();
132 | }
133 | }
134 |
135 | @Override
136 | public void downloadProgress(String url, long downloadedSize, long totalSize) {
137 | //TODO:
138 | }
139 |
140 | /**
141 | * 计算表情包中第i个表情图片文件的下载地址.
142 | * @param emojiPackage
143 | * @param i
144 | * @return
145 | */
146 | private String getLocalPathForEmoji(EmojiPackage emojiPackage, int i) {
147 | //TODO:
148 | return null;
149 | }
150 |
151 | /**
152 | * 把表情包安装到本地
153 | * @param emojiPackage
154 | * @param localPathList
155 | */
156 | private void installEmojiPackageLocally(EmojiPackage emojiPackage, List localPathList) {
157 | //TODO:
158 | return;
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/AndroidDemos/app/src/main/java/com/zhangtielei/demos/async/programming/queueing/v3/RxJavaBasedTaskQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Tielei Zhang (zhangtielei.com).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.zhangtielei.demos.async.programming.queueing.v3;
18 |
19 | import android.util.Log;
20 | import rx.Observable;
21 | import rx.Observer;
22 | import rx.Subscriber;
23 | import rx.observables.AsyncOnSubscribe;
24 |
25 | import java.util.LinkedList;
26 | import java.util.Queue;
27 |
28 | /**
29 | * Created by Tielei Zhang on 16/9/1.
30 | *
31 | * 基于RxJava机制的队列实现
32 | */
33 | public class RxJavaBasedTaskQueue implements TaskQueue {
34 | private static final String TAG = "TaskQueue";
35 |
36 | /**
37 | * Task排队的队列. 不需要thread-safe
38 | */
39 | private Queue> taskQueue = new LinkedList>();
40 | private boolean stopped;
41 |
42 | /**
43 | * 一个任务最多重试次数.
44 | * 重试次数超过MAX_RETRIES, 任务则最终失败.
45 | */
46 | private static final int MAX_RETRIES = 3;
47 |
48 | @Override
49 | public Observable addTask(Task task) {
50 | //新任务加入队列
51 | final QueueElement element = new QueueElement();
52 | element.task = task;
53 | //subscriber后面会赋值
54 | taskQueue.offer(element);
55 |
56 | //把异步任务task转成一个Observable, 用于当前addTask的返回
57 | Observable taskObservable = Observable.create(new AsyncOnSubscribe() {
58 | @Override
59 | protected Integer generateState() {
60 | return 0;
61 | }
62 |
63 | @Override
64 | protected Integer next(Integer state, long requested, Observer> observer) {
65 | Observable asyncObservable = Observable.create(new Observable.OnSubscribe() {
66 | @Override
67 | public void call(Subscriber super R> subscriber) {
68 | //得到subscriber了,存入队列元素
69 | element.subscriber = subscriber;
70 | //这里能启动排队任务了
71 | if (taskQueue.size() == 1 && !stopped) {
72 | //当前是第一个排队任务, 立即执行它
73 | QueueElement element = taskQueue.peek();
74 | launchNextTask(element);
75 | }
76 | }
77 | });
78 | observer.onNext(asyncObservable);
79 | observer.onCompleted();
80 | return 1;
81 | }
82 | });
83 |
84 | return taskObservable;
85 | }
86 |
87 | @Override
88 | public void destroy() {
89 | stopped = true;
90 | }
91 |
92 | private void launchNextTask(final QueueElement element) {
93 | //取当前队列头的任务, 但不出队列
94 | if (element == null || element.task == null || element.subscriber == null) {
95 | //impossible case
96 | Log.e(TAG, "impossible: NO task element in queue, unexpected!");
97 | return;
98 | }
99 |
100 | Task> task = element.task;
101 |
102 | Log.d(TAG, "start task (" + task.getTaskId() + ")");
103 | task.start().subscribe(new Subscriber