├── tinytask
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── androidwind
│ │ │ └── task
│ │ │ ├── Priority.java
│ │ │ ├── SimpleTask.java
│ │ │ ├── Task.java
│ │ │ ├── TaskThreadPoolExecutor.java
│ │ │ └── TinyTaskExecutor.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── androidwind
│ │ │ └── task
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── androidwind
│ │ └── task
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── tinytask-sample
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_test.xml
│ │ │ │ ├── include_description.xml
│ │ │ │ ├── activity_fragment_executor.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_fragment_old.xml
│ │ │ │ ├── activity_fragment_synchronized.xml
│ │ │ │ └── activity_fragment_new.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── androidwind
│ │ │ │ └── task
│ │ │ │ └── sample
│ │ │ │ ├── onebyone
│ │ │ │ ├── SyncTask.java
│ │ │ │ ├── BaseSyncTask.java
│ │ │ │ └── TinySyncExecutor.java
│ │ │ │ ├── TestActivity.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── ExecutorFragment.java
│ │ │ │ ├── OldFragment.java
│ │ │ │ ├── NewFragment.java
│ │ │ │ └── SynchronizedFragment.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── androidwind
│ │ │ └── task
│ │ │ └── sample
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── androidwind
│ │ └── task
│ │ └── sample
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── .gitignore
├── README.md
├── gradlew.bat
└── gradlew
/tinytask/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/tinytask-sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':tinytask-sample', ':tinytask'
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/tinytask/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | My Library
3 |
4 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | android-tiny-task
3 |
4 |
--------------------------------------------------------------------------------
/tinytask/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddnosh/android-tiny-task/HEAD/tinytask-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/tinytask/src/main/java/com/androidwind/task/Priority.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task;
2 |
3 | /**
4 | * task priority
5 | *
6 | * @author ddnosh
7 | * @website http://blog.csdn.net/ddnosh
8 | */
9 | public enum Priority {
10 | HIGH, NORMAL, LOW
11 | }
12 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/onebyone/SyncTask.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample.onebyone;
2 |
3 | /**
4 | * @author ddnosh
5 | * @website http://blog.csdn.net/ddnosh
6 | */
7 | public interface SyncTask {
8 |
9 | void doTask();
10 | }
11 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/onebyone/BaseSyncTask.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample.onebyone;
2 |
3 | /**
4 | * @author ddnosh
5 | * @website http://blog.csdn.net/ddnosh
6 | */
7 | public abstract class BaseSyncTask implements SyncTask {
8 |
9 | private int id;
10 |
11 | public int getId() {
12 | return id;
13 | }
14 |
15 | public void setId(int id) {
16 | this.id = id;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/tinytask/src/test/java/com/androidwind/task/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/tinytask-sample/src/test/java/com/androidwind/task/sample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/tinytask/src/main/java/com/androidwind/task/SimpleTask.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task;
2 |
3 | /**
4 | * @author ddnosh
5 | * @website http://blog.csdn.net/ddnosh
6 | */
7 | public abstract class SimpleTask implements Runnable {
8 | long SEQ; // the identity for task
9 |
10 | public String taskName;
11 |
12 | public Priority priority;
13 |
14 | public SimpleTask() {
15 | priority = Priority.NORMAL;
16 | }
17 |
18 | public SimpleTask(Priority priority) {
19 | this.priority = priority == null ? Priority.NORMAL : priority;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/layout/include_description.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tinytask/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/tinytask-sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/tinytask/src/androidTest/java/com/androidwind/task/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.androidwind.task.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tinytask-sample/src/androidTest/java/com/androidwind/task/sample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.androidwind.task.sample", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/layout/activity_fragment_executor.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
23 |
24 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 |
33 | # Android Studio captures folder
34 | captures/
35 |
36 | # IntelliJ
37 | *.iml
38 | .idea
39 |
40 | # Keystore files
41 | # Uncomment the following lines if you do not want to check your keystore files in.
42 | #*.jks
43 | #*.keystore
44 |
45 | # External native build folder generated in Android Studio 2.2 and later
46 | .externalNativeBuild
47 |
48 | # Google Services (e.g. APIs or Firebase)
49 | google-services.json
50 |
51 | # Freeline
52 | freeline.py
53 | freeline/
54 | freeline_project_description.json
55 |
56 | # fastlane
57 | fastlane/report.xml
58 | fastlane/Preview.html
59 | fastlane/screenshots
60 | fastlane/test_output
61 | fastlane/readme.md
62 |
63 | * OSX files
64 | .DS_Store
65 |
66 | # Windows thumbnail db
67 | Thumbs.db
68 |
69 | #NDK
70 | obj/
--------------------------------------------------------------------------------
/tinytask-sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.androidwind.task.sample"
7 | minSdkVersion 19
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 |
20 | lintOptions{
21 | abortOnError false
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | implementation 'com.android.support:appcompat-v7:28.0.0'
28 | testImplementation 'junit:junit:4.12'
29 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
30 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
31 |
32 | compile project(':tinytask')
33 |
34 | // compile files('libs/tinylog.jar')
35 | compile 'com.androidwind:tinylog:1.0.1'
36 | compile 'com.airbnb.android:lottie:2.5.4'
37 | }
38 |
39 | repositories {
40 | flatDir {
41 | dirs 'libs'
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tinytask/src/main/java/com/androidwind/task/Task.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * run in background and then callback in main
7 | *
8 | * @author ddnosh
9 | * @website http://blog.csdn.net/ddnosh
10 | */
11 | public abstract class Task extends SimpleTask {
12 | public Task() {
13 | super();
14 | }
15 |
16 | public Task(Priority priority) {
17 | super(priority);
18 | }
19 |
20 | public abstract T doInBackground();
21 |
22 | public abstract void onSuccess(T t);
23 |
24 | public abstract void onFail(Throwable throwable);
25 |
26 | @Override
27 | public void run() {
28 | if (BuildConfig.DEBUG) {
29 | Log.i("TinyTask", "[Task] compare: priority = " + priority + ", taskName = " + Thread.currentThread().getName());
30 | }
31 | try {
32 | final T t = doInBackground();
33 | TinyTaskExecutor.getMainThreadHandler().post(new Runnable() {
34 | @Override
35 | public void run() {
36 | onSuccess(t);
37 | }
38 | });
39 | } catch (final Throwable throwable) {
40 | TinyTaskExecutor.getMainThreadHandler().post(new Runnable() {
41 | @Override
42 | public void run() {
43 | onFail(throwable);
44 | }
45 | });
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/TestActivity.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.widget.TextView;
7 | import android.widget.Toast;
8 |
9 | import com.androidwind.task.Task;
10 | import com.androidwind.task.TinyTaskExecutor;
11 |
12 | /**
13 | * @author ddnosh
14 | * @website http://blog.csdn.net/ddnosh
15 | */
16 | public class TestActivity extends Activity {
17 |
18 | private TextView mTextView;
19 | @Override
20 | protected void onCreate(@Nullable Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_test);
23 |
24 | mTextView = findViewById(R.id.textView);
25 |
26 | TinyTaskExecutor.execute(delayTask);
27 | }
28 |
29 | @Override
30 | public void onBackPressed() {
31 | super.onBackPressed();
32 | finish();
33 | }
34 |
35 | @Override
36 | protected void onDestroy() {
37 | super.onDestroy();
38 | }
39 |
40 |
41 | private Task delayTask = new Task() {
42 | @Override
43 | public String doInBackground() {
44 | System.out.println("[new] thread id in tinytask: " + Thread.currentThread().getId());
45 | try {
46 | Thread.sleep(5000);
47 | } catch (InterruptedException e) {
48 | e.printStackTrace();
49 | }
50 | System.out.println("[new] with callback after 5 sec");
51 | return "task with sleep 5 sec";
52 | }
53 |
54 | @Override
55 | public void onSuccess(String s) {
56 | Toast.makeText(TestActivity.this, "delay tinytask toast", Toast.LENGTH_SHORT).show();
57 | mTextView.setText("delayed!");
58 | }
59 |
60 | @Override
61 | public void onFail(Throwable throwable) {
62 |
63 | }
64 | };
65 | }
66 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
27 |
28 |
34 |
35 |
41 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # android-tiny-task
2 | [ ](https://bintray.com/ddnosh/maven/tinytask/_latestVersion)
3 | A tiny asynchronized task library for android.
4 |
5 | 
6 |
7 | # Solution
8 | 1. we should avoid to use thread, runnable, handler, and AsyncTask;
9 | 2. we should use thread pool executors to handle threads;
10 | 3. we will handle background thread and UI thread, and their interactions, even frequently;
11 | 4. simple and easy to use, focus lifecycle and avoid OOM.
12 |
13 | # Function
14 | 1. handle asynchronized task in background;
15 | 2. handle asynchronized task first in background and then to front;
16 | 3. handle asynchronized task with delay;
17 | 4. cancel handle asynchronized task.
18 | 5. set task priority.
19 |
20 | # Technology
21 | 1. Desing Pattern
22 | 1. Singleton Pattern
23 | 2. static
24 | 2. Skill Point
25 | 1. ExecutorService
26 | 2. synchronized
27 | 3. Callable
28 | 4. FutureTask
29 | 5. Handler
30 | 6. Runnable
31 |
32 | # Usage
33 | 1. only run in background
34 | TinyTaskExecutor.execute(new SimpleTask() { ... });
35 | 2. run in background and then go back to main ui;
36 | TinyTaskExecutor.execute(new AdvancedTask() { ... });
37 | 3. run with delay
38 | TinyTaskExecutor.execute(task, 5000);
39 | 4. remove delay task
40 | TinyTaskExecutor.removeTask(task);
41 | 5. check a task(not recommend)
42 | TinyTaskExecutor.check();
43 | 6. post to main thread
44 | TinyTaskExecutor.postToMainThread(runnable, 2000);
45 | 7. remove post to main thread
46 | TinyTaskExecutor.removeMainThreadRunnable(delayRunnable);
47 | 8. set task priority
48 | new TestTask(TinyTaskExecutor.PRIORITY_LOWEST);
49 | TinyTaskExecutor.execute(s1);
50 |
51 | # TODO
52 | 1. to cancel when overtime has come;
53 | 2. schedule task;
54 | 3. ~~(done in 20190105) task priority~~;
55 | 4. ~~(done in 20190119) BlockQueue~~;
56 | 5. ~~(done in 20190119) customized thread pool and queue~~;
57 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/layout/activity_fragment_old.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
28 |
29 |
35 |
36 |
42 |
43 |
49 |
50 |
55 |
56 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/tinytask/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.novoda.bintray-release'
3 |
4 | android {
5 | compileSdkVersion 28
6 |
7 | defaultConfig {
8 | minSdkVersion 19
9 | targetSdkVersion 28
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | lintOptions {
25 | abortOnError false
26 | }
27 |
28 | }
29 |
30 | dependencies {
31 | implementation fileTree(dir: 'libs', include: ['*.jar'])
32 |
33 | implementation 'com.android.support:appcompat-v7:28.0.0'
34 | testImplementation 'junit:junit:4.12'
35 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
36 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
37 | }
38 |
39 | publish {
40 | userOrg = 'ddnosh'
41 | groupId = 'com.androidwind'
42 | artifactId = 'tinytask'
43 | publishVersion = '2.0.0'
44 | desc = 'A tiny task library for android.'
45 | website = "https://github.com/ddnosh/android-tiny-task"
46 | }
47 |
48 | tasks.withType(Javadoc) {//防止编码问题
49 | options.addStringOption('Xdoclint:none', '-quiet')
50 | options.addStringOption('encoding', 'UTF-8')
51 | options.addStringOption('charSet', 'UTF-8')
52 | }
53 |
54 | task sourcesJar(type: Jar) {
55 | from android.sourceSets.main.java.srcDirs
56 | classifier = 'sources'
57 | }
58 |
59 | task javadoc(type: Javadoc) {
60 | source = android.sourceSets.main.java.srcDirs
61 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
62 | }
63 |
64 | task javadocJar(type: Jar, dependsOn: javadoc) {
65 | classifier = 'javadoc'
66 | from javadoc.destinationDir
67 | }
68 |
69 | artifacts {
70 | archives javadocJar
71 | archives sourcesJar
72 | }
73 |
74 | //打包任务
75 | task makeJar(type: Copy) {
76 | //删除旧的jar包
77 | delete 'build/libs/tinytask.jar'
78 | //从哪里打包class文件
79 | from('build/intermediates/packaged-classes/debug/')
80 | //打包到jar后的目录结构
81 | into('build/libs/')
82 | //包含的jar包
83 | include('classes.jar')
84 | //去掉不需要打包的目录和文件
85 | exclude('BuildConfig.class', 'R.class')
86 | //去掉R$开头的文件
87 | exclude { it.name.startsWith('R$'); }
88 | //重命名jar包为tinytask
89 | rename ('classes.jar', 'tinytask.jar')
90 | }
91 |
92 | makeJar.dependsOn(build)
93 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/onebyone/TinySyncExecutor.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample.onebyone;
2 |
3 | import com.androidwind.task.Task;
4 | import com.androidwind.task.TinyTaskExecutor;
5 |
6 | import java.util.ArrayDeque;
7 | import java.util.concurrent.atomic.AtomicInteger;
8 |
9 | /**
10 | * @author ddnosh
11 | * @website http://blog.csdn.net/ddnosh
12 | */
13 | public class TinySyncExecutor {
14 |
15 | private volatile static TinySyncExecutor sTinySyncExecutor;
16 |
17 | //store incoming task, waiting to put into ArrayBlockingQueue;
18 | private ArrayDeque pendingQueue = new ArrayDeque<>();
19 | private BaseSyncTask currentTask;
20 |
21 | private final AtomicInteger count = new AtomicInteger(1);
22 |
23 | public static TinySyncExecutor getInstance() {
24 | if (sTinySyncExecutor == null) {
25 | synchronized (TinySyncExecutor.class) {
26 | sTinySyncExecutor = new TinySyncExecutor();
27 | }
28 | }
29 | return sTinySyncExecutor;
30 | }
31 |
32 | private void coreExecute() {
33 | currentTask = pendingQueue.poll();
34 | if (currentTask != null) {
35 | System.out.println("[OneByOne]executing currentTask id = :" + currentTask.getId());
36 | TinyTaskExecutor.execute(new Task() {
37 | @Override
38 | public Object doInBackground() {
39 | System.out.println("[OneByOne]doInBackground, " + "the current thread id = " + Thread.currentThread().getId());
40 | return null;
41 | }
42 |
43 | @Override
44 | public void onSuccess(Object o) {
45 | currentTask.doTask();
46 | }
47 |
48 | @Override
49 | public void onFail(Throwable throwable) {
50 |
51 | }
52 | });
53 | }
54 | }
55 |
56 | public void enqueue(final BaseSyncTask task) {
57 | task.setId(count.getAndIncrement());
58 | System.out.println("[OneByOne]The task id = :" + task.getId());
59 | pendingQueue.offer(task);//the ArrayDeque should not be blocked when operate offer
60 | System.out.println("[OneByOne]The pendingQueue size = :" + pendingQueue.size());
61 | if (currentTask == null) {
62 | coreExecute();
63 | }
64 | }
65 |
66 | public void finish() {
67 | System.out.println("[OneByOne]finish task, task id = " + currentTask.getId() + "; pendingQueue size = " + pendingQueue.size());
68 | coreExecute();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentTransaction;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.View;
8 | import android.widget.Button;
9 |
10 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
11 |
12 | private Fragment mOldFragment, mNewFragment, mExecutorFragment, mSynchronizedFragment;
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 |
18 | Button btn1 = findViewById(R.id.btn_fragment1);
19 | btn1.setOnClickListener(this);
20 |
21 | Button btn2 = findViewById(R.id.btn_fragment2);
22 | btn2.setOnClickListener(this);
23 |
24 | Button btn3 = findViewById(R.id.btn_fragment3);
25 | btn3.setOnClickListener(this);
26 |
27 | Button btn4 = findViewById(R.id.btn_fragment4);
28 | btn4.setOnClickListener(this);
29 | }
30 |
31 | @Override
32 | public void onClick(View v) {
33 | switch (v.getId()) {
34 | case R.id.btn_fragment1:
35 | updateOldFragment();
36 | break;
37 | case R.id.btn_fragment2:
38 | updateNewFragment();
39 | break;
40 | case R.id.btn_fragment3:
41 | updateExecutorFragment();
42 | break;
43 | case R.id.btn_fragment4:
44 | updateSynchronizedFragment();
45 | break;
46 | }
47 | }
48 |
49 | private void updateOldFragment() {
50 | FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
51 | if (mOldFragment == null) {
52 | mOldFragment = OldFragment.newInstance();
53 | }
54 | ft.replace(R.id.fragment_container, mOldFragment);
55 | ft.commit();
56 | }
57 |
58 | private void updateNewFragment() {
59 | FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
60 | if (mNewFragment == null) {
61 | mNewFragment = NewFragment.newInstance();
62 | }
63 | ft.replace(R.id.fragment_container, mNewFragment);
64 | ft.commit();
65 | }
66 |
67 | private void updateExecutorFragment() {
68 | FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
69 | if (mExecutorFragment == null) {
70 | mExecutorFragment = ExecutorFragment.newInstance();
71 | }
72 | ft.replace(R.id.fragment_container, mExecutorFragment);
73 | ft.commit();
74 | }
75 |
76 | private void updateSynchronizedFragment() {
77 | FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
78 | if (mSynchronizedFragment == null) {
79 | mSynchronizedFragment = SynchronizedFragment.newInstance();
80 | }
81 | ft.replace(R.id.fragment_container, mSynchronizedFragment);
82 | ft.commit();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/layout/activity_fragment_synchronized.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
21 |
22 |
28 |
29 |
35 |
36 |
39 |
40 |
46 |
47 |
53 |
54 |
55 |
62 |
63 |
69 |
70 |
76 |
77 |
83 |
84 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/layout/activity_fragment_new.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
19 |
20 |
26 |
27 |
33 |
34 |
40 |
41 |
47 |
48 |
54 |
55 |
61 |
62 |
68 |
69 |
75 |
76 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/tinytask/src/main/java/com/androidwind/task/TaskThreadPoolExecutor.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task;
2 |
3 | import java.util.Comparator;
4 | import java.util.concurrent.BlockingQueue;
5 | import java.util.concurrent.PriorityBlockingQueue;
6 | import java.util.concurrent.ThreadFactory;
7 | import java.util.concurrent.ThreadPoolExecutor;
8 | import java.util.concurrent.TimeUnit;
9 | import java.util.concurrent.atomic.AtomicInteger;
10 | import java.util.concurrent.atomic.AtomicLong;
11 |
12 | /**
13 | * @author ddnosh
14 | * @website http://blog.csdn.net/ddnosh
15 | */
16 | public class TaskThreadPoolExecutor extends ThreadPoolExecutor {
17 |
18 | private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();
19 | private static final int MAXIMUM_POOL_SIZE = 128;
20 | private static final int KEEP_ALIVE = 60;
21 | private static final AtomicLong SEQ_SEED = new AtomicLong(0);
22 |
23 | private static final ThreadFactory sThreadFactory = new ThreadFactory() {
24 | private final AtomicInteger mCount = new AtomicInteger(1);
25 |
26 | @Override
27 | public Thread newThread(Runnable runnable) {
28 | return new Thread(runnable, "TaskThreadPoolExecutor#" + mCount.getAndIncrement());
29 | }
30 | };
31 |
32 | /**
33 | * FIFO
34 | */
35 | private static final Comparator FIFO = new Comparator() {
36 | @Override
37 | public int compare(Runnable lhs, Runnable rhs) {
38 | if (lhs instanceof SimpleTask && rhs instanceof SimpleTask) {
39 | SimpleTask lpr = ((SimpleTask) lhs);
40 | SimpleTask rpr = ((SimpleTask) rhs);
41 | int result = lpr.priority.ordinal() - rpr.priority.ordinal();
42 | return result == 0 ? (int) (lpr.SEQ - rpr.SEQ) : result;
43 | } else {
44 | return 0;
45 | }
46 | }
47 | };
48 |
49 | /**
50 | * LIFO
51 | */
52 | private static final Comparator LIFO = new Comparator() {
53 | @Override
54 | public int compare(Runnable lhs, Runnable rhs) {
55 | if (lhs instanceof SimpleTask && rhs instanceof SimpleTask) {
56 | SimpleTask lpr = ((SimpleTask) lhs);
57 | SimpleTask rpr = ((SimpleTask) rhs);
58 | int result = lpr.priority.ordinal() - rpr.priority.ordinal();
59 | return result == 0 ? (int) (rpr.SEQ - lpr.SEQ) : result;
60 | } else {
61 | return 0;
62 | }
63 | }
64 | };
65 |
66 | public TaskThreadPoolExecutor(boolean fifo) {
67 | this(CORE_POOL_SIZE, fifo);
68 | }
69 |
70 | public TaskThreadPoolExecutor(int poolSize, boolean fifo) {
71 | this(poolSize, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, new PriorityBlockingQueue(MAXIMUM_POOL_SIZE, fifo ? FIFO : LIFO), sThreadFactory);
72 | }
73 |
74 | public TaskThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) {
75 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
76 | }
77 |
78 | public boolean isBusy() {
79 | return getActiveCount() >= getCorePoolSize();
80 | }
81 |
82 | @Override
83 | public void execute(Runnable runnable) {
84 | if (runnable instanceof SimpleTask) {
85 | ((SimpleTask) runnable).SEQ = SEQ_SEED.getAndIncrement();
86 | }
87 | super.execute(runnable);
88 | }
89 | }
--------------------------------------------------------------------------------
/tinytask/src/main/java/com/androidwind/task/TinyTaskExecutor.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | import java.util.HashMap;
7 | import java.util.concurrent.ExecutorService;
8 |
9 | /**
10 | * @author ddnosh
11 | * @website http://blog.csdn.net/ddnosh
12 | */
13 | public class TinyTaskExecutor {
14 |
15 | private volatile static TinyTaskExecutor sTinyTaskExecutor;
16 |
17 | private ExecutorService mExecutor;
18 | private volatile Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
19 | private static HashMap sDelayTasks = new HashMap<>();
20 |
21 | public static TinyTaskExecutor getInstance() {
22 | if (sTinyTaskExecutor == null) {
23 | synchronized (TinyTaskExecutor.class) {
24 | sTinyTaskExecutor = new TinyTaskExecutor();
25 | }
26 | }
27 | return sTinyTaskExecutor;
28 | }
29 |
30 | public TinyTaskExecutor() {
31 | mExecutor = new TaskThreadPoolExecutor(true);
32 | }
33 |
34 | private static ExecutorService getExecutor() {
35 | return getInstance().mExecutor;
36 | }
37 |
38 | public static Handler getMainThreadHandler() {
39 | return getInstance().mMainThreadHandler;
40 | }
41 |
42 | public static void execute(Runnable runnable) {
43 | execute(runnable, 0);
44 | }
45 |
46 | public static void execute(final Runnable runnable, long delayMillisecond) {
47 | if (runnable == null) {
48 | return;
49 | }
50 | if (delayMillisecond < 0) {
51 | return;
52 | }
53 |
54 | if (!getExecutor().isShutdown()) {
55 | if (delayMillisecond > 0) {
56 | Runnable delayRunnable = new Runnable() {
57 | @Override
58 | public void run() {
59 | synchronized (sDelayTasks) {
60 | sDelayTasks.remove(runnable);
61 | }
62 | realExecute(runnable);
63 | }
64 | };
65 |
66 | synchronized (sDelayTasks) {
67 | sDelayTasks.put(runnable, delayRunnable);
68 | }
69 |
70 | getMainThreadHandler().postDelayed(delayRunnable, delayMillisecond);
71 | } else {
72 | realExecute(runnable);
73 | }
74 | }
75 | }
76 |
77 | /**
78 | * real executor
79 | *
80 | * @param runnable
81 | */
82 | private static void realExecute(Runnable runnable) {
83 | getExecutor().execute(runnable);
84 | }
85 |
86 | /**
87 | * remove task
88 | *
89 | * @param runnable
90 | */
91 | public static void removeTask(final Runnable runnable) {
92 | if (runnable == null) {
93 | return;
94 | }
95 |
96 | Runnable delayRunnable;
97 | synchronized (sDelayTasks) {
98 | delayRunnable = sDelayTasks.remove(runnable);
99 | }
100 |
101 | if (delayRunnable != null) {
102 | getMainThreadHandler().removeCallbacks(delayRunnable);
103 | }
104 |
105 | }
106 |
107 | /**
108 | * post to main thread, do not handle time-consuming job
109 | *
110 | * @param task
111 | */
112 | public static void postToMainThread(final Runnable task) {
113 | postToMainThread(task, 0);
114 | }
115 |
116 | /**
117 | * post to main thread, do not handle time-consuming job
118 | *
119 | * @param task
120 | * @param delayMillis
121 | */
122 | public static void postToMainThread(final Runnable task, long delayMillis) {
123 | if (task == null) {
124 | return;
125 | }
126 |
127 | getMainThreadHandler().postDelayed(task, delayMillis);
128 | }
129 |
130 | /**
131 | * remove delay task from main thread
132 | *
133 | * @param task
134 | */
135 | public static void removeMainThreadRunnable(Runnable task) {
136 | if (task == null) {
137 | return;
138 | }
139 |
140 | getMainThreadHandler().removeCallbacks(task);
141 | }
142 |
143 | /**
144 | * check current thread is main thread or not
145 | *
146 | * @return
147 | */
148 | public static boolean isMainThread() {
149 | return Thread.currentThread() == getInstance().mMainThreadHandler.getLooper().getThread();
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/ExecutorFragment.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.Button;
9 |
10 | import java.util.concurrent.ArrayBlockingQueue;
11 | import java.util.concurrent.BlockingQueue;
12 | import java.util.concurrent.LinkedBlockingQueue;
13 | import java.util.concurrent.ThreadPoolExecutor;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | /**
17 | * @author ddnosh
18 | * @website http://blog.csdn.net/ddnosh
19 | */
20 | public class ExecutorFragment extends Fragment implements View.OnClickListener {
21 |
22 | public static ExecutorFragment newInstance() {
23 | ExecutorFragment fragment = new ExecutorFragment();
24 | return fragment;
25 | }
26 |
27 | @Override
28 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
29 | Bundle savedInstanceState) {
30 | View view = inflater.inflate(R.layout.activity_fragment_executor, container, false);
31 | Button btn1 = view.findViewById(R.id.btn_1);
32 | btn1.setOnClickListener(this);
33 | Button btn2 = view.findViewById(R.id.btn_2);
34 | btn2.setOnClickListener(this);
35 | return view;
36 | }
37 |
38 | private class ThreadPoolRunnable implements Runnable {
39 |
40 | private String name;
41 |
42 | public ThreadPoolRunnable(String name) {
43 | this.name = name;
44 | }
45 |
46 | @Override
47 | public void run() {
48 | synchronized(this) {
49 | try{
50 | System.out.println("[Test-Thread]" + Thread.currentThread().getName() + ", " + name);
51 | Thread.sleep(3000);
52 | }catch (InterruptedException e){
53 | e.printStackTrace();
54 | }
55 | }
56 | }
57 | }
58 |
59 | @Override
60 | public void onClick(View v) {
61 | switch (v.getId()) {
62 | case R.id.btn_1:
63 | test1();
64 | break;
65 | case R.id.btn_2:
66 | test2();
67 | break;
68 | }
69 | }
70 |
71 | private void test1() {
72 | BlockingQueue queue = new LinkedBlockingQueue();
73 | //if use LinkedBlockingQueue, the maximumPoolSize is unavailable,
74 | //if use ArrayBlockingQueue, the maximumPoolSize is available.
75 | ThreadPoolExecutor executor2 = new ThreadPoolExecutor(2, 6, 1, TimeUnit.DAYS, queue);
76 | for (int i = 0; i < 10; i++) {
77 | // executor.execute(new Thread(new ThreadPoolRunnable(), "Test".concat(""+i)));
78 | executor2.execute(new ThreadPoolRunnable("[Test-Runnable]".concat(""+i)));
79 | int threadSize = queue.size();
80 | System.out.println("[Test-Thread]线程队列大小为-->"+threadSize);
81 | }
82 | executor2.shutdown();
83 | }
84 |
85 | private void test2() {
86 | final ArrayBlockingQueue valve = new ArrayBlockingQueue<>(10);
87 | Thread breadProductor = new Thread(new Runnable() {//productor
88 | @Override
89 | public void run() {
90 | while (true) {
91 | String s = "[Test]one bread";
92 | try {
93 | valve.put(s);//blocking
94 | } catch (InterruptedException e1) {
95 | e1.printStackTrace();
96 | }// when the queue is full, the thread will be blocked util the queue isn't full
97 | System.out.println("[Test]produced" + s);
98 | try {
99 | Thread.sleep(2000);
100 | } catch (InterruptedException e) {
101 | e.printStackTrace();
102 | }
103 |
104 | }
105 | }
106 | }, "[Test]Bread Producer");
107 |
108 | Thread breadConsumer = new Thread(new Runnable() {//consumer
109 | @Override
110 | public void run() {
111 | while (true) {
112 | String s = null;
113 | try {
114 | s = valve.take();//when the queue is empty, the thread will be blocked util the blank queue comes a task
115 | } catch (InterruptedException e) {
116 | e.printStackTrace();
117 | }
118 | System.out.println("[Test]consumed" + s);
119 | try {
120 | Thread.sleep(5000);
121 | } catch (InterruptedException e) {
122 | e.printStackTrace();
123 | }
124 | }
125 | }
126 | });
127 |
128 | breadProductor.start();
129 | breadConsumer.start();
130 |
131 | Thread monitor = new Thread(new Runnable() {
132 |
133 | @Override
134 | public void run() {
135 | while (true) {
136 | System.out.println("[Test]the left breads:" + valve.size());//monitor the breads
137 | try {
138 | Thread.sleep(1000);
139 | } catch (InterruptedException e) {
140 | e.printStackTrace();
141 | }
142 | }
143 | }
144 | });
145 | monitor.start();
146 | }
147 | }
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
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 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/OldFragment.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample;
2 |
3 | import android.os.Bundle;
4 | import android.os.Handler;
5 | import android.os.HandlerThread;
6 | import android.os.Looper;
7 | import android.os.Message;
8 | import android.support.v4.app.Fragment;
9 | import android.util.Log;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.Button;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | /**
18 | * @author ddnosh
19 | * @website http://blog.csdn.net/ddnosh
20 | */
21 | public class OldFragment extends Fragment implements View.OnClickListener {
22 |
23 | private TextView tvResult;
24 | private int result;
25 |
26 | public static OldFragment newInstance() {
27 | OldFragment fragment = new OldFragment();
28 | return fragment;
29 | }
30 |
31 | @Override
32 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
33 | Bundle savedInstanceState) {
34 | View view = inflater.inflate(R.layout.activity_fragment_old, container, false);
35 | TextView tv = view.findViewById(R.id.tv);
36 | tv.setText("OldFragment");
37 |
38 | Button btn1 = view.findViewById(R.id.btn_1);
39 | btn1.setOnClickListener(this);
40 |
41 | Button btn2 = view.findViewById(R.id.btn_2);
42 | btn2.setOnClickListener(this);
43 |
44 | Button btn3 = view.findViewById(R.id.btn_3);
45 | btn3.setOnClickListener(this);
46 |
47 | Button btn4 = view.findViewById(R.id.btn_4);
48 | btn4.setOnClickListener(this);
49 |
50 | Button btn5 = view.findViewById(R.id.btn_5);
51 | btn5.setOnClickListener(this);
52 |
53 | tvResult = view.findViewById(R.id.tv_result);
54 |
55 | return view;
56 | }
57 |
58 | private Handler mHandler = new Handler(Looper.getMainLooper()) {
59 | @Override
60 | public void handleMessage(Message msg) {
61 | super.handleMessage(msg);
62 | if (msg.what == 0) {
63 | Toast.makeText(getContext(), "old toast: " + msg.obj, Toast.LENGTH_SHORT).show();
64 | } else if (msg.what == 1) {
65 | Toast.makeText(getContext(), "old toast: " + msg.obj, Toast.LENGTH_SHORT).show();
66 | }
67 | }
68 | };
69 |
70 | // init1---------------------------------------------------------------------------------------
71 | private void init1() {
72 | System.out.println("[old] thread id in main: " + Thread.currentThread().getId());
73 | new Thread(mRunnable1).start();
74 | new Thread(mRunnable1).start();
75 | }
76 |
77 | private Runnable mRunnable1 = new Runnable() {
78 | @Override
79 | public void run() {
80 | synchronized (this) {
81 | //运行于子线程中, 处理耗时任务
82 | System.out.println("[old] thread id in run: " + Thread.currentThread().getId());
83 | int result = 0;
84 | int i = 0;
85 | for (; i < 500; i++) {
86 | result += i;
87 | try {
88 | Thread.sleep(10);
89 | } catch (InterruptedException e) {
90 | e.printStackTrace();
91 | }
92 | }
93 | System.out.println("[old] result = " + result);
94 | Message message = mHandler.obtainMessage();
95 | message.what = 0;
96 | message.obj = result;
97 | mHandler.sendMessage(message);
98 | }
99 | }
100 | };
101 |
102 | // init2---------------------------------------------------------------------------------------
103 | private void init2() {
104 | System.out.println("[old] thread id in main: " + Thread.currentThread().getId());
105 | new Thread() {
106 | @Override
107 | public void run() {
108 | //运行于子线程中, 处理耗时任务
109 | System.out.println("[old] thread id in run: " + Thread.currentThread().getId());
110 | try {
111 | Thread.sleep(5000);// simulate time-consuming task;
112 | result = 222;
113 | } catch (InterruptedException e) {
114 | e.printStackTrace();
115 | }
116 | mHandler.post(mRunnable2);
117 | }
118 | }.start();
119 |
120 | }
121 |
122 | //运行于主线程中, 因此不能处理耗时任务
123 | Runnable mRunnable2 = new Runnable() {
124 | @Override
125 | public void run() {
126 | System.out.println("[old] thread id in runnable: " + Thread.currentThread().getId());
127 | tvResult.setText("view updated, and the result is " + result);
128 | }
129 | };
130 |
131 | // init3---------------------------------------------------------------------------------------
132 | private void init3() {
133 | HandlerThread myHandlerThread = new HandlerThread("handler-thread");
134 | myHandlerThread.start();
135 | Handler handler = new Handler(myHandlerThread.getLooper()) {
136 | @Override
137 | public void handleMessage(Message msg) {
138 | super.handleMessage(msg);
139 | //运行于子线程handler-thread中, 处理耗时任务
140 | Log.d("handler ", "消息: " + msg.what + " 线程: " + Thread.currentThread().getName());
141 | try {
142 | Thread.sleep(3000);
143 | } catch (InterruptedException e) {
144 | e.printStackTrace();
145 | }
146 | Message message = mHandler.obtainMessage();
147 | message.what = 1;
148 | message.obj = 333;
149 | mHandler.sendMessage(message);
150 | }
151 | };
152 |
153 | //给工作线程发送消息
154 | handler.sendEmptyMessage(1);
155 | }
156 |
157 | // init4---------------------------------------------------------------------------------------
158 | private void init4() {
159 | HandlerThread myHandlerThread = new HandlerThread("handler-thread");
160 | myHandlerThread.start();
161 | Handler handler = new Handler(myHandlerThread.getLooper());
162 | handler.postDelayed(mRunnable4, 5000);
163 | }
164 |
165 | private Runnable mRunnable4 = new Runnable() {
166 | @Override
167 | public void run() {
168 | //运行于子线程handler-thread中, 处理耗时任务
169 | try {
170 | Thread.sleep(3000);
171 | } catch (InterruptedException e) {
172 | e.printStackTrace();
173 | }
174 |
175 | Message message = mHandler.obtainMessage();
176 | message.what = 1;
177 | message.obj = 444;
178 | mHandler.sendMessage(message);
179 | }
180 | };
181 |
182 | @Override
183 | public void onClick(View v) {
184 | tvResult.setText("");
185 | switch (v.getId()) {
186 | case R.id.btn_1:
187 | init1();
188 | break;
189 | case R.id.btn_2:
190 | init2();
191 | break;
192 | case R.id.btn_3:
193 | init3();
194 | break;
195 | case R.id.btn_4:
196 | init4();
197 | break;
198 | case R.id.btn_5:
199 | Toast.makeText(getActivity(), "this is a toast, you know.", Toast.LENGTH_SHORT).show();
200 | break;
201 | }
202 | }
203 |
204 | @Override
205 | public void onDestroy() {
206 | super.onDestroy();
207 | mHandler.removeCallbacks(mRunnable4);
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/NewFragment.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.Button;
10 | import android.widget.Toast;
11 |
12 | import com.androidwind.task.SimpleTask;
13 | import com.androidwind.task.Priority;
14 | import com.androidwind.task.Task;
15 | import com.androidwind.task.TinyTaskExecutor;
16 |
17 | /**
18 | * v2.x
19 | *
20 | * @author ddnosh
21 | * @website http://blog.csdn.net/ddnosh
22 | */
23 | public class NewFragment extends Fragment implements View.OnClickListener {
24 |
25 | public static NewFragment newInstance() {
26 | NewFragment fragment = new NewFragment();
27 | return fragment;
28 | }
29 |
30 | @Override
31 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
32 | Bundle savedInstanceState) {
33 | View view = inflater.inflate(R.layout.activity_fragment_new, container, false);
34 |
35 | Button btn1 = view.findViewById(R.id.btn_1);
36 | btn1.setOnClickListener(this);
37 |
38 | Button btn2 = view.findViewById(R.id.btn_2);
39 | btn2.setOnClickListener(this);
40 |
41 | Button btn3 = view.findViewById(R.id.btn_3);
42 | btn3.setOnClickListener(this);
43 |
44 | Button btn4 = view.findViewById(R.id.btn_4);
45 | btn4.setOnClickListener(this);
46 |
47 | Button btn5 = view.findViewById(R.id.btn_5);
48 | btn5.setOnClickListener(this);
49 |
50 | Button btn6 = view.findViewById(R.id.btn_6);
51 | btn6.setOnClickListener(this);
52 |
53 | Button btn7 = view.findViewById(R.id.btn_7);
54 | btn7.setOnClickListener(this);
55 |
56 | Button btn8 = view.findViewById(R.id.btn_8);
57 | btn8.setOnClickListener(this);
58 |
59 | Button btn9 = view.findViewById(R.id.btn_9);
60 | btn9.setOnClickListener(this);
61 |
62 | System.out.println("[new] thread id in main: " + Thread.currentThread().getId());
63 |
64 | return view;
65 | }
66 |
67 | @Override
68 | public void onClick(View v) {
69 | switch (v.getId()) {
70 | case R.id.btn_1:
71 | Toast.makeText(getActivity(), "this is a toast, you know.", Toast.LENGTH_SHORT).show();
72 | startActivity(new Intent(getActivity(), TestActivity.class));
73 | break;
74 | case R.id.btn_2:
75 | TinyTaskExecutor.execute(new Runnable() {
76 | @Override
77 | public void run() {
78 | System.out.println("[new] thread id in tinytask: " + Thread.currentThread().getId() +
79 | ", is main thread:" + TinyTaskExecutor.isMainThread());
80 | try {
81 | Thread.sleep(5000);
82 | } catch (InterruptedException e) {
83 | e.printStackTrace();
84 | }
85 | System.out.println("[new] no callback after 5 sec");
86 | }
87 | });
88 | break;
89 | case R.id.btn_3:
90 | TinyTaskExecutor.execute(new Task() { //default priority is Priority.NORMAL
91 | @Override
92 | public String doInBackground() {
93 | System.out.println("[new] thread id in tinytask: " + Thread.currentThread().getId());
94 | try {
95 | Thread.sleep(5000);
96 | } catch (InterruptedException e) {
97 | e.printStackTrace();
98 | }
99 | System.out.println("[new] with callback after 5 sec");
100 | return "task with sleep 5 sec";
101 | }
102 |
103 | @Override
104 | public void onSuccess(String s) {
105 | Toast.makeText(getActivity(), s, Toast.LENGTH_SHORT).show();
106 | }
107 |
108 | @Override
109 | public void onFail(Throwable throwable) {
110 |
111 | }
112 | });
113 | break;
114 | case R.id.btn_4:
115 | TinyTaskExecutor.execute(new Task(Priority.NORMAL) {
116 | @Override
117 | public String doInBackground() {
118 | System.out.println("[new] thread id in tinytask: " + Thread.currentThread().getId());
119 | try {
120 | Thread.sleep(5000);
121 | } catch (InterruptedException e) {
122 | e.printStackTrace();
123 | }
124 | System.out.println("[new] with callback after 5 sec");
125 | return "task with sleep 5 sec";
126 | }
127 |
128 | @Override
129 | public void onSuccess(String s) {
130 | Toast.makeText(getActivity(), s, Toast.LENGTH_SHORT).show();
131 | }
132 |
133 | @Override
134 | public void onFail(Throwable throwable) {
135 |
136 | }
137 | });
138 | break;
139 | case R.id.btn_5:
140 | System.out.println("[new] with task delay");
141 | TinyTaskExecutor.execute(delayTask, 5000);
142 | break;
143 | case R.id.btn_6:
144 | System.out.println("[new] with remove delay task");
145 | TinyTaskExecutor.removeTask(delayTask);
146 | break;
147 | case R.id.btn_7:
148 | System.out.println("[new] post to main thread");
149 | TinyTaskExecutor.postToMainThread(delayRunnable, 2000);
150 | break;
151 | case R.id.btn_8:
152 | System.out.println("[new] remove post to main thread");
153 | TinyTaskExecutor.removeMainThreadRunnable(delayRunnable);
154 | break;
155 | case R.id.btn_9:
156 | System.out.println("[new] priority test");
157 | for (int i = 0; i < 50; i++) {
158 | SimpleTask priorityRunnable;
159 | if (i % 3 == 1) {
160 | priorityRunnable = new SimpleTask(Priority.HIGH) {
161 |
162 | @Override
163 | public void run() {
164 | System.out.println("[new] " + Thread.currentThread().getName() + "Priority.HIGH");
165 | }
166 | };
167 | } else if (i % 5 == 0) {
168 | priorityRunnable = new SimpleTask(Priority.LOW) {
169 |
170 | @Override
171 | public void run() {
172 | System.out.println("[new] " + Thread.currentThread().getName() + "Priority.LOW");
173 | }
174 | };
175 | } else {
176 | priorityRunnable = new SimpleTask(Priority.NORMAL) {
177 |
178 | @Override
179 | public void run() {
180 | System.out.println("[new] " + Thread.currentThread().getName() + "Priority.NORMAL");
181 | }
182 | };
183 | }
184 | TinyTaskExecutor.execute(priorityRunnable);
185 | }
186 | break;
187 | }
188 | }
189 |
190 | private Task delayTask = new Task() {
191 | @Override
192 | public String doInBackground() {
193 | System.out.println("[new] thread id in tinytask: " + Thread.currentThread().getId());
194 | try {
195 | Thread.sleep(5000);
196 | } catch (InterruptedException e) {
197 | e.printStackTrace();
198 | }
199 | System.out.println("[new] with callback after 5 sec");
200 | return "task with sleep 5 sec";
201 | }
202 |
203 | @Override
204 | public void onSuccess(String s) {
205 | Toast.makeText(getActivity(), "delay tinytask toast", Toast.LENGTH_SHORT).show();
206 | }
207 |
208 | @Override
209 | public void onFail(Throwable throwable) {
210 |
211 | }
212 | };
213 |
214 | private Runnable delayRunnable = new Runnable() {
215 | @Override
216 | public void run() {
217 | Toast.makeText(getActivity(), "post to main thread toast", Toast.LENGTH_SHORT).show();
218 | }
219 | };
220 |
221 | class TestTask extends SimpleTask {
222 | public TestTask(Priority priority) {
223 | super(priority);
224 | }
225 |
226 | @Override
227 | public void run() {
228 | System.out.println("[new] " + Thread.currentThread().getName() + priority);
229 | }
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/tinytask-sample/src/main/java/com/androidwind/task/sample/SynchronizedFragment.java:
--------------------------------------------------------------------------------
1 | package com.androidwind.task.sample;
2 |
3 | import android.animation.Animator;
4 | import android.animation.ValueAnimator;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.Button;
11 | import android.widget.Toast;
12 |
13 | import com.androidwind.task.Task;
14 | import com.androidwind.task.TinyTaskExecutor;
15 | import com.androidwind.task.sample.onebyone.BaseSyncTask;
16 | import com.androidwind.task.sample.onebyone.TinySyncExecutor;
17 |
18 | import java.util.ArrayDeque;
19 | import java.util.concurrent.ArrayBlockingQueue;
20 |
21 | /**
22 | * @author ddnosh
23 | * @website http://blog.csdn.net/ddnosh
24 | */
25 | public class SynchronizedFragment extends Fragment implements View.OnClickListener {
26 |
27 | private ValueAnimator valueAnimator1, valueAnimator2, valueAnimator3, valueAnimator4;
28 |
29 | public static SynchronizedFragment newInstance() {
30 | SynchronizedFragment fragment = new SynchronizedFragment();
31 | return fragment;
32 | }
33 |
34 | @Override
35 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
36 | Bundle savedInstanceState) {
37 | View view = inflater.inflate(R.layout.activity_fragment_synchronized, container, false);
38 | Button btn1 = view.findViewById(R.id.btn_1);
39 | btn1.setOnClickListener(this);
40 | Button btn2 = view.findViewById(R.id.btn_2);
41 | btn2.setOnClickListener(this);
42 | Button btn3 = view.findViewById(R.id.btn_3);
43 | btn3.setOnClickListener(this);
44 | Button btn4 = view.findViewById(R.id.btn_add);
45 | btn4.setOnClickListener(this);
46 | initView(view);
47 | return view;
48 | }
49 |
50 | private void initView(View view) {
51 | final Button btnAnim1 = view.findViewById(R.id.btn_anim_1);
52 | valueAnimator1 = ValueAnimator.ofInt(btnAnim1.getLayoutParams().width, 500);
53 | valueAnimator1.setDuration(1000);
54 | valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
55 | @Override
56 | public void onAnimationUpdate(ValueAnimator animator) {
57 | int currentValue = (Integer) animator.getAnimatedValue();
58 | btnAnim1.getLayoutParams().width = currentValue;
59 | btnAnim1.requestLayout();
60 | }
61 | });
62 | valueAnimator1.addListener(new ValueAnimator.AnimatorListener() {
63 | @Override
64 | public void onAnimationStart(Animator animation) {
65 |
66 | }
67 |
68 | @Override
69 | public void onAnimationEnd(Animator animation) {
70 | System.out.println("[OneByOne]anim played 1 secs");
71 | TinySyncExecutor.getInstance().finish();
72 | }
73 |
74 | @Override
75 | public void onAnimationCancel(Animator animation) {
76 |
77 | }
78 |
79 | @Override
80 | public void onAnimationRepeat(Animator animation) {
81 |
82 | }
83 | });
84 | final Button btnAnim2 = view.findViewById(R.id.btn_anim_2);
85 | valueAnimator2 = ValueAnimator.ofInt(btnAnim2.getLayoutParams().width, 800);
86 | valueAnimator2.setDuration(2000);
87 | valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
88 | @Override
89 | public void onAnimationUpdate(ValueAnimator animator) {
90 | int currentValue = (Integer) animator.getAnimatedValue();
91 | btnAnim2.getLayoutParams().width = currentValue;
92 | btnAnim2.requestLayout();
93 | }
94 | });
95 | valueAnimator2.addListener(new ValueAnimator.AnimatorListener() {
96 | @Override
97 | public void onAnimationStart(Animator animation) {
98 |
99 | }
100 |
101 | @Override
102 | public void onAnimationEnd(Animator animation) {
103 | System.out.println("[OneByOne]anim played 2 secs");
104 | TinySyncExecutor.getInstance().finish();
105 | }
106 |
107 | @Override
108 | public void onAnimationCancel(Animator animation) {
109 |
110 | }
111 |
112 | @Override
113 | public void onAnimationRepeat(Animator animation) {
114 |
115 | }
116 | });
117 | final Button btnAnim3 = view.findViewById(R.id.btn_anim_3);
118 | valueAnimator3 = ValueAnimator.ofInt(btnAnim3.getLayoutParams().height, 300);
119 | valueAnimator3.setDuration(3000);
120 | valueAnimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
121 | @Override
122 | public void onAnimationUpdate(ValueAnimator animator) {
123 | int currentValue = (Integer) animator.getAnimatedValue();
124 | btnAnim3.getLayoutParams().height = currentValue;
125 | btnAnim3.requestLayout();
126 | }
127 | });
128 | valueAnimator3.addListener(new ValueAnimator.AnimatorListener() {
129 | @Override
130 | public void onAnimationStart(Animator animation) {
131 |
132 | }
133 |
134 | @Override
135 | public void onAnimationEnd(Animator animation) {
136 | System.out.println("[OneByOne]anim played 3 secs");
137 | TinySyncExecutor.getInstance().finish();
138 | }
139 |
140 | @Override
141 | public void onAnimationCancel(Animator animation) {
142 |
143 | }
144 |
145 | @Override
146 | public void onAnimationRepeat(Animator animation) {
147 |
148 | }
149 | });
150 | final Button btnAnim4 = view.findViewById(R.id.btn_anim_4);
151 | valueAnimator4 = new ValueAnimator();
152 | valueAnimator4.setFloatValues(1.0f,0.1f);
153 | final float alpha = btnAnim4.getAlpha();
154 | valueAnimator4.setDuration(3000);
155 | valueAnimator4.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
156 | @Override
157 | public void onAnimationUpdate(ValueAnimator animator) {
158 | float rate = (float) animator.getAnimatedValue();
159 | btnAnim4.setAlpha(rate*alpha);
160 | }
161 | });
162 | valueAnimator4.addListener(new ValueAnimator.AnimatorListener() {
163 | @Override
164 | public void onAnimationStart(Animator animation) {
165 |
166 | }
167 |
168 | @Override
169 | public void onAnimationEnd(Animator animation) {
170 | System.out.println("[OneByOne]anim played 4 secs");
171 | TinySyncExecutor.getInstance().finish();
172 | }
173 |
174 | @Override
175 | public void onAnimationCancel(Animator animation) {
176 |
177 | }
178 |
179 | @Override
180 | public void onAnimationRepeat(Animator animation) {
181 |
182 | }
183 | });
184 | }
185 |
186 | @Override
187 | public void onClick(View v) {
188 | switch (v.getId()) {
189 | case R.id.btn_1:
190 | test1();
191 | break;
192 | case R.id.btn_2:
193 | test2();
194 | break;
195 | case R.id.btn_3:
196 | test3();
197 | break;
198 | case R.id.btn_add:
199 | final BaseSyncTask task = new BaseSyncTask() {
200 | @Override
201 | public void doTask() {
202 | valueAnimator4.start();
203 | }
204 | };
205 | TinySyncExecutor.getInstance().enqueue(task);
206 | break;
207 | }
208 | }
209 |
210 | //1 --------------------------------------------------------------------------------------------
211 | // private void test1() {
212 | // for (int i = 0; i < 10; i++) {
213 | // execute(new SimpleTask(i + "") {
214 | // @Override
215 | // public String doInBackground() {
216 | // try {
217 | // System.out.println("The taskName is :" + getTaskName());
218 | // Thread.sleep(1000);
219 | // } catch (InterruptedException e) {
220 | // e.printStackTrace();
221 | // }
222 | // return "simple task with sleep 1 sec";
223 | // }
224 | // });
225 | // }
226 | // }
227 | //
228 | // private TaskRunnable mActive;
229 | // private ArrayDeque mArrayDeque = new ArrayDeque<>();
230 | //
231 | // public synchronized void execute(final SimpleTask task) {
232 | // mArrayDeque.offer(new TaskRunnable() {
233 | // @Override
234 | // public Object call() throws Exception {
235 | // try {
236 | // task.call();
237 | // } finally {
238 | // scheduleNext();
239 | // }
240 | // return null;
241 | // }
242 | // });
243 |
244 | // if (mActive == null) {
245 | // scheduleNext();
246 | // }
247 | // }
248 | //
249 | // private void scheduleNext() {
250 | // if ((mActive = mArrayDeque.poll()) != null) {
251 | // TinyTaskExecutor.execute(mActive);
252 | // }
253 | // }
254 |
255 | //2 --------------------------------------------------------------------------------------------
256 | // private void test1() {
257 | // for (int i = 0; i < 10; i++) {
258 | // final int j = i;
259 | // execute1(new Runnable() {
260 | // @Override
261 | // public void run() {
262 | // System.out.println("The taskName is :" + (j + 1));
263 | // try {
264 | // Thread.sleep(1000);
265 | // } catch (InterruptedException e) {
266 | // e.printStackTrace();
267 | // }
268 | // }
269 | // });
270 | // }
271 | // }
272 | //
273 | // private TaskRunnable mActive;
274 | // private ArrayDeque mArrayDeque = new ArrayDeque<>();
275 | //
276 | // public synchronized void execute1(final Runnable r) {
277 | // mArrayDeque.offer(new TaskRunnable() {
278 | // @Override
279 | // public Object call() throws Exception {
280 | // try {
281 | // r.run();
282 | // } finally {
283 | // scheduleNext();
284 | // }
285 | // return null;
286 | // }
287 | // });
288 |
289 | // if (mActive == null) {
290 | // scheduleNext();
291 | // }
292 | // }
293 | //
294 | // private void scheduleNext() {
295 | // if ((mActive = mArrayDeque.poll()) != null) {
296 | // TinyTaskExecutor.execute(mActive);
297 | // }
298 | // }
299 |
300 | //3 --------------------------------------------------------------------------------------------
301 | private void test1() {
302 | for (int i = 0; i < 10; i++) {
303 | final int j = i;
304 | execute1(new TaskCallBack() {
305 | @Override
306 | public void onBackground() {
307 | System.out.println("[onBackground]The taskName is :" + (j + 1));
308 | try {
309 | Thread.sleep(1000);
310 | } catch (InterruptedException e) {
311 | e.printStackTrace();
312 | }
313 | }
314 |
315 | @Override
316 | public void onSuccess() {
317 | System.out.println("[onSuccess]The taskName is :" + (j + 1));
318 | }
319 |
320 | @Override
321 | public void onFail() {
322 | System.out.println("[onFail]The taskName is :" + (j + 1));
323 | Toast.makeText(getContext(), "The fail taskName is :" + (j + 1), Toast.LENGTH_SHORT).show();
324 | }
325 | });
326 | }
327 | }
328 |
329 | private Task mActive;
330 | private ArrayDeque mArrayDeque = new ArrayDeque<>();
331 |
332 | public synchronized void execute1(final TaskCallBack callBack) {
333 | mArrayDeque.offer(new Task() {
334 | @Override
335 | public Object doInBackground() {
336 | callBack.onBackground();
337 | return null;
338 | }
339 |
340 | @Override
341 | public void onSuccess(Object o) {
342 | try {
343 | callBack.onSuccess();
344 | } finally {
345 | scheduleNext();
346 | }
347 | }
348 |
349 | @Override
350 | public void onFail(Throwable throwable) {
351 | try {
352 | callBack.onFail();
353 | } finally {
354 | scheduleNext();
355 | }
356 | }
357 | });
358 |
359 | if (mActive == null) {
360 | scheduleNext();
361 | }
362 | }
363 |
364 | private void scheduleNext() {
365 | if ((mActive = mArrayDeque.poll()) != null) {
366 | TinyTaskExecutor.execute(mActive);
367 | }
368 | }
369 |
370 | public interface TaskCallBack {
371 | void onBackground();
372 |
373 | void onSuccess();
374 |
375 | void onFail();
376 | }
377 |
378 | //4 --------------------------------------------------------------------------------------------
379 | final ArrayBlockingQueue valve = new ArrayBlockingQueue<>(1);
380 |
381 | private void test2() {
382 | //put
383 | new Thread(new Runnable() {
384 | @Override
385 | public void run() {
386 | for (int i = 0; i < 10; i++) {
387 | final int j = i;
388 | execute2(new Runnable() {
389 | @Override
390 | public void run() {
391 | System.out.println("The taskName is :" + (j + 1));
392 | try {
393 | Thread.sleep(1000);
394 | } catch (InterruptedException e) {
395 | e.printStackTrace();
396 | }
397 | }
398 | });
399 | }
400 | }
401 | }).start();
402 | //take
403 | new Thread(new Runnable() {
404 | @Override
405 | public void run() {
406 | while (true) {
407 | Runnable s = null;
408 | try {
409 | s = valve.take();
410 | s.run();
411 | } catch (InterruptedException e) {
412 | e.printStackTrace();
413 | }
414 | }
415 | }
416 | }).start();
417 | }
418 |
419 | public synchronized void execute2(final Runnable r) {
420 | try {
421 | valve.put(r);
422 | } catch (InterruptedException e) {
423 | e.printStackTrace();
424 | }
425 | }
426 |
427 | //5 --------------------------------------------------------------------------------------------
428 | private void test3() {
429 | final BaseSyncTask task1 = new BaseSyncTask() {
430 | @Override
431 | public void doTask() {
432 | // SimCallBack cb = new SimCallBack() {
433 | // @Override
434 | // public void onComplete() {
435 | // try {
436 | // Thread.sleep(1000);
437 | // System.out.println("[OneByOne]sleep 1 secs");
438 | // TinySyncExecutor.getInstance().finish();
439 | // } catch (InterruptedException e) {
440 | // e.printStackTrace();
441 | // }
442 | // }
443 | // };
444 | // cb.onComplete();
445 | valueAnimator1.start();
446 | }
447 | };
448 | final BaseSyncTask task2 = new BaseSyncTask() {
449 | @Override
450 | public void doTask() {
451 | // SimCallBack cb = new SimCallBack() {
452 | // @Override
453 | // public void onComplete() {
454 | // try {
455 | // Thread.sleep(2000);
456 | // System.out.println("[OneByOne]sleep 2 secs");
457 | // TinySyncExecutor.getInstance().finish();
458 | // } catch (InterruptedException e) {
459 | // e.printStackTrace();
460 | // }
461 | // }
462 | // };
463 | // cb.onComplete();
464 | valueAnimator2.start();
465 | }
466 | };
467 | final BaseSyncTask task3 = new BaseSyncTask() {
468 | @Override
469 | public void doTask() {
470 | // SimCallBack cb = new SimCallBack() {
471 | // @Override
472 | // public void onComplete() {
473 | // try {
474 | // Thread.sleep(3000);
475 | // System.out.println("[OneByOne]sleep 3 secs");
476 | // TinySyncExecutor.getInstance().finish();
477 | // } catch (InterruptedException e) {
478 | // e.printStackTrace();
479 | // }
480 | // }
481 | // };
482 | // cb.onComplete();
483 | valueAnimator3.start();
484 | }
485 | };
486 | TinySyncExecutor.getInstance().enqueue(task1);
487 | TinySyncExecutor.getInstance().enqueue(task2);
488 | TinySyncExecutor.getInstance().enqueue(task3);
489 | }
490 |
491 | public interface SimCallBack {
492 | void onComplete();
493 | }
494 | }
495 |
--------------------------------------------------------------------------------