Skip to content
This repository was archived by the owner on Dec 17, 2020. It is now read-only.

Commit 258ffb0

Browse files
committed
- Added support for android.app.Activity and android.app.Fragment with tasks but only on API 11+ and currently without easy to use TaskActivity or TaskFragment;
- Fixed a critical bug where the CallbackShadow would be wrapped by another CallbackShadow;
1 parent dde4cb9 commit 258ffb0

File tree

7 files changed

+172
-54
lines changed

7 files changed

+172
-54
lines changed

library/src/main/java/org/neotech/library/retainabletasks/Task.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,11 @@ protected void onCancelled() {
459459
private void doCancelled() {
460460
onCancelled();
461461
Callback callback = getCallback();
462-
if (callback != null && callback instanceof AdvancedCallback) {
462+
if (callback instanceof AdvancedCallback) {
463+
shouldDeliverResult = false;
463464
((AdvancedCallback) callback).onCanceled(this);
465+
} else {
466+
shouldDeliverResult = true;
464467
}
465468
}
466469

library/src/main/java/org/neotech/library/retainabletasks/TaskManager.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package org.neotech.library.retainabletasks;
22

3+
import android.annotation.TargetApi;
4+
import android.os.Build;
35
import android.support.annotation.MainThread;
46
import android.support.annotation.NonNull;
7+
import android.support.annotation.Nullable;
58
import android.support.v4.app.Fragment;
69
import android.support.v4.app.FragmentManager;
710

@@ -85,8 +88,23 @@ public interface TaskAttachListener {
8588
*/
8689
@MainThread
8790
public static TaskManager getFragmentTaskManager(@NonNull Fragment fragment){
88-
TaskRetainingFragment taskRetainingFragment = TaskRetainingFragment.getInstance(fragment.getFragmentManager());
89-
final String tag = getFragmentTag(fragment);
91+
final String tag = getTaskManagerTag(fragment.getTag());
92+
return getTaskManager(TaskRetainingFragment.getInstance(fragment.getFragmentManager()), tag);
93+
}
94+
95+
/**
96+
* Returns the {@link TaskManager} associated with the given Fragment.
97+
* @param fragment The Fragment to get the TaskManager for.
98+
* @return The TaskManager instance associated with the given Fragment.
99+
*/
100+
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
101+
@MainThread
102+
public static TaskManager getFragmentTaskManager(@NonNull android.app.Fragment fragment){
103+
final String tag = getTaskManagerTag(fragment.getTag());
104+
return getTaskManager(TaskRetainingFragment.getInstance(fragment.getFragmentManager()), tag);
105+
}
106+
107+
private static TaskManager getTaskManager(@NonNull TaskRetainingFragment taskRetainingFragment, @NonNull String tag){
90108
BaseTaskManager manager = (BaseTaskManager) taskRetainingFragment.findTaskManagerByTag(tag);
91109
if(manager == null){
92110
manager = new BaseTaskManager();
@@ -95,9 +113,9 @@ public static TaskManager getFragmentTaskManager(@NonNull Fragment fragment){
95113
return manager;
96114
}
97115

98-
private static String getFragmentTag(@NonNull Fragment fragment) {
99-
if (fragment.getTag() != null) {
100-
return "tag:" + fragment.getTag();
116+
private static String getTaskManagerTag(@Nullable String fragmentTag) {
117+
if (fragmentTag != null) {
118+
return "tag:" + fragmentTag;
101119
}
102120
throw new IllegalArgumentException("In order to associate a TaskManger with a Fragment the Fragment needs to have a tag.");
103121
}
@@ -114,6 +132,17 @@ public static TaskManager getActivityTaskManager(@NonNull FragmentManager manage
114132
return TaskRetainingFragment.getInstance(manager).getActivityTaskManager();
115133
}
116134

135+
/**
136+
* Returns the {@link TaskManager} associated with the Activity the given FragmentManger belongs to. You
137+
* should never try to supply a child/Fragment FragmentManger here.
138+
* @param manager The FragmentManger of the Activity you would like to get the TaskManager for.
139+
* @return The TaskManager instance associated with the given Activity's FragmentManger.
140+
*/
141+
@MainThread
142+
public static TaskManager getActivityTaskManager(@NonNull android.app.FragmentManager manager){
143+
return TaskRetainingFragment.getInstance(manager).getActivityTaskManager();
144+
}
145+
117146
/**
118147
* Returns the global TaskManager. The global TaskManager isn't bound to the lifecycle of an
119148
* Activity and won't automatically remove a {@link Task.Callback} listeners set to
Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,32 @@
11
package org.neotech.library.retainabletasks;
22

3+
import android.annotation.TargetApi;
4+
import android.app.Activity;
5+
import android.os.Build;
36
import android.support.annotation.NonNull;
47
import android.support.v4.app.Fragment;
5-
import android.support.v7.app.AppCompatActivity;
8+
import android.support.v4.app.FragmentActivity;
69

710
import org.neotech.library.retainabletasks.internal.BaseTaskManager;
811

912
/**
1013
* Created by Rolf on 3-3-2016.
1114
*/
12-
public class TaskManagerLifeCycleProxy {
15+
public final class TaskManagerLifeCycleProxy {
1316

1417
private BaseTaskManager fragmentTaskManager;
1518
private final TaskManagerProvider provider;
1619

1720
public TaskManagerLifeCycleProxy(@NonNull TaskManagerProvider provider){
18-
if(!(provider instanceof AppCompatActivity || provider instanceof Fragment)){
19-
throw new IllegalArgumentException("The TaskManagerProvider needs to be an instance of android.support.v7.app.AppCompatActivity, or android.support.v4.app.Fragment.");
21+
if(!(provider instanceof Activity || provider instanceof Fragment || provider instanceof android.app.Fragment)){
22+
throw new IllegalArgumentException("The TaskManagerProvider needs to be an instance of android.app.Activity (including the derived support library activities), android.app.Fragment or android.support.v4.app.Fragment!");
23+
24+
/**
25+
* Checks if the given provider is not an instance of the support library Activity or Fragment and if the API version is lower than API 11.
26+
* If so it should throw an exception as on API 11 or below we don't have access to Fragments.
27+
*/
28+
} else if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB && !(provider instanceof FragmentActivity || provider instanceof Fragment)){
29+
throw new IllegalArgumentException("This library doesn't support API level 11 or lower with the default android.app.Activity or android.app.Fragment class, you should use the android.support.v4.app.FragmentActivity or android.support.v4.app.Fragment!");
2030
}
2131
this.provider = provider;
2232
}
@@ -29,15 +39,23 @@ public void onStop(){
2939
((BaseTaskManager) getTaskManager()).detach();
3040
}
3141

42+
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
3243
public TaskManager getTaskManager(){
3344
if(fragmentTaskManager != null) {
3445
return fragmentTaskManager;
3546
}
36-
if(provider instanceof AppCompatActivity){
37-
fragmentTaskManager = (BaseTaskManager) TaskManager.getActivityTaskManager(((AppCompatActivity) provider).getSupportFragmentManager());
47+
if(provider instanceof FragmentActivity){
48+
fragmentTaskManager = (BaseTaskManager) TaskManager.getActivityTaskManager(((FragmentActivity) provider).getSupportFragmentManager());
3849
} else if(provider instanceof Fragment){
3950
fragmentTaskManager = (BaseTaskManager) TaskManager.getFragmentTaskManager((Fragment) provider);
51+
} else if(provider instanceof Activity){
52+
fragmentTaskManager = (BaseTaskManager) TaskManager.getActivityTaskManager(((Activity) provider).getFragmentManager());
53+
} else if(provider instanceof android.app.Fragment){
54+
fragmentTaskManager = (BaseTaskManager) TaskManager.getFragmentTaskManager((android.app.Fragment) provider);
55+
} /* else {
56+
//This should never happen as the constructor checks everything.
4057
}
58+
*/
4159
return fragmentTaskManager;
4260
}
4361
}

library/src/main/java/org/neotech/library/retainabletasks/internal/BaseTaskManager.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
/**
1717
* Created by Rolf on 29-2-2016.
1818
*/
19-
public class BaseTaskManager extends TaskManager {
19+
public final class BaseTaskManager extends TaskManager {
2020

21-
private static final String TAG = "SimpleTaskManager";
21+
private static final String TAG = "BaseTaskManager";
2222

2323
protected final HashMap<String, Task<?, ?>> tasks = new HashMap<>();
2424

@@ -33,7 +33,7 @@ public void attach(TaskManagerProvider taskManagerProvider){
3333
if(callback == null){
3434
throw new IllegalArgumentException("Could not attach Task '" + task.getKey() + "' because onPreAttach did not return a valid Callback listener! Did you override onPreAttach()?");
3535
}
36-
attach(task.getValue(), new CallbackShadow(callback));
36+
attach(task.getValue(), callback);
3737
}
3838
}
3939

@@ -155,12 +155,12 @@ public void detach(){
155155
private void removeFinishedTask(Task expectedTask){
156156
Task task = tasks.get(expectedTask.getTag());
157157
if(task != expectedTask){
158-
Log.i(TAG, "Task '" + expectedTask.getTag() + "' has already been removed, because another task has been added while this task was finishing.");
158+
Log.i(TAG, "Task '" + expectedTask.getTag() + "' has already been removed, because another task with the same tag has been added while this task was finishing.");
159159
}
160160
tasks.remove(expectedTask.getTag());
161161
}
162162

163-
protected final class CallbackShadow implements Task.AdvancedCallback {
163+
private final class CallbackShadow implements Task.AdvancedCallback {
164164

165165
private final Task.Callback callback;
166166

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,51 @@
11
package org.neotech.library.retainabletasks.internal;
22

3-
import android.os.Bundle;
3+
import android.annotation.TargetApi;
4+
import android.os.Build;
45
import android.support.annotation.MainThread;
56
import android.support.annotation.NonNull;
6-
import android.support.v4.app.Fragment;
77
import android.support.v4.app.FragmentManager;
88

99
import org.neotech.library.retainabletasks.TaskManager;
1010

1111
import java.util.HashMap;
1212

1313
/**
14-
* Created by Rolf on 29-2-2016.
14+
* Created by Rolf on 4-3-2016.
1515
*/
16-
public class TaskRetainingFragment extends Fragment {
16+
public final class TaskRetainingFragment {
1717

18-
private static final String FRAGMENT_TAG = "org.neotech.library.retainabletasks.TaskRetainingFragment";
19-
20-
private HashMap<String, TaskManager> fragmentTaskManagers = new HashMap<>();
18+
public static final String FRAGMENT_TAG = "org.neotech.library.retainabletasks.TaskRetainingFragment";
2119

20+
private final HashMap<String, TaskManager> fragmentTaskManagers = new HashMap<>();
2221

2322
private final BaseTaskManager taskManager = new BaseTaskManager();
2423

2524
public static TaskRetainingFragment getInstance(FragmentManager fragmentManager){
26-
TaskRetainingFragment taskFragment = (TaskRetainingFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
25+
TaskRetainingFragmentCompat taskFragment = (TaskRetainingFragmentCompat) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
26+
if(taskFragment == null){
27+
taskFragment = new TaskRetainingFragmentCompat();
28+
}
29+
if(!taskFragment.isAdded()) {
30+
fragmentManager.beginTransaction().add(taskFragment, FRAGMENT_TAG).commit();
31+
}
32+
return taskFragment.logic;
33+
}
34+
35+
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
36+
public static TaskRetainingFragment getInstance(android.app.FragmentManager fragmentManager){
37+
TaskRetainingFragmentV11 taskFragment = (TaskRetainingFragmentV11) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
2738
if(taskFragment == null){
28-
taskFragment = new TaskRetainingFragment();
39+
taskFragment = new TaskRetainingFragmentV11();
2940
}
3041
if(!taskFragment.isAdded()) {
3142
fragmentManager.beginTransaction().add(taskFragment, FRAGMENT_TAG).commit();
3243
}
33-
return taskFragment;
44+
return taskFragment.logic;
3445
}
3546

47+
48+
3649
@MainThread
3750
public void registerTaskManager(@NonNull String tag, @NonNull TaskManager manager){
3851
if(fragmentTaskManagers.containsKey(tag)){
@@ -46,33 +59,7 @@ public TaskManager findTaskManagerByTag(@NonNull String tag){
4659
return fragmentTaskManagers.get(tag);
4760
}
4861

49-
public TaskManager getActivityTaskManager(){
62+
public BaseTaskManager getActivityTaskManager(){
5063
return taskManager;
5164
}
52-
@Override
53-
public void onCreate(Bundle savedInstanceState) {
54-
super.onCreate(savedInstanceState);
55-
setRetainInstance(true);
56-
}
57-
58-
@Override
59-
public void onStop() {
60-
super.onStop();
61-
//As soon as the activity is stopped the UI should not be touched.
62-
taskManager.detach();
63-
}
64-
65-
@Override
66-
public void onDestroy() {
67-
/**
68-
* The activity is destroyed, this method WON'T be called when the fragment is being
69-
* propagated between activity instances.
70-
*
71-
* Cleanup, but let the tasks finish as they might do something important.
72-
* The references to the tasks are lost at this point.
73-
*/
74-
75-
taskManager.detach();
76-
super.onDestroy();
77-
}
7865
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.neotech.library.retainabletasks.internal;
2+
3+
import android.os.Bundle;
4+
import android.support.v4.app.Fragment;
5+
6+
/**
7+
* Created by Rolf on 29-2-2016.
8+
*/
9+
public final class TaskRetainingFragmentCompat extends Fragment {
10+
11+
final TaskRetainingFragment logic = new TaskRetainingFragment();
12+
13+
@Override
14+
public void onCreate(Bundle savedInstanceState) {
15+
super.onCreate(savedInstanceState);
16+
setRetainInstance(true);
17+
}
18+
19+
@Override
20+
public void onStop() {
21+
super.onStop();
22+
//As soon as the activity is stopped the UI should not be touched.
23+
logic.getActivityTaskManager().detach();
24+
}
25+
26+
@Override
27+
public void onDestroy() {
28+
/**
29+
* The activity is destroyed, this method WON'T be called when the fragment is being
30+
* propagated between activity instances.
31+
*
32+
* Cleanup, but let the tasks finish as they might do something important.
33+
* The references to the tasks are lost at this point.
34+
*/
35+
36+
logic.getActivityTaskManager().detach();
37+
super.onDestroy();
38+
}
39+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.neotech.library.retainabletasks.internal;
2+
3+
import android.annotation.TargetApi;
4+
import android.app.Fragment;
5+
import android.os.Build;
6+
import android.os.Bundle;
7+
8+
/**
9+
* Created by Rolf on 4-3-2016.
10+
*/
11+
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
12+
public final class TaskRetainingFragmentV11 extends Fragment {
13+
14+
final TaskRetainingFragment logic = new TaskRetainingFragment();
15+
16+
@Override
17+
public void onCreate(Bundle savedInstanceState) {
18+
super.onCreate(savedInstanceState);
19+
setRetainInstance(true);
20+
}
21+
22+
@Override
23+
public void onStop() {
24+
super.onStop();
25+
//As soon as the activity is stopped the UI should not be touched.
26+
logic.getActivityTaskManager().detach();
27+
}
28+
29+
@Override
30+
public void onDestroy() {
31+
/**
32+
* The activity is destroyed, this method WON'T be called when the fragment is being
33+
* propagated between activity instances.
34+
*
35+
* Cleanup, but let the tasks finish as they might do something important.
36+
* The references to the tasks are lost at this point.
37+
*/
38+
39+
logic.getActivityTaskManager().detach();
40+
super.onDestroy();
41+
}
42+
}

0 commit comments

Comments
 (0)