22
33import android .content .Context ;
44import android .os .Bundle ;
5-
65import androidx .annotation .NonNull ;
76import androidx .work .BackoffPolicy ;
87import androidx .work .Constraints ;
2322import java .io .FileInputStream ;
2423import java .io .IOException ;
2524import java .io .ObjectInputStream ;
25+ import java .lang .ref .WeakReference ;
2626import java .util .List ;
27+ import java .util .Map ;
28+ import java .util .concurrent .ConcurrentHashMap ;
2729import java .util .concurrent .TimeUnit ;
2830
2931public class AndroidJobStrategy implements BackgroundRequestStrategy {
3032
3133 private static final String JOB_TAG = "CLD" ;
3234
35+ private static final Map <String , WeakReference <Thread >> threads = new ConcurrentHashMap <>();
36+ private static final Object threadsMapLockObject = new Object ();
37+
3338 private Context context ;
3439
3540 public static OneTimeWorkRequest adapt (UploadRequest <?> request , File payloadFile ) {
@@ -43,7 +48,7 @@ public static OneTimeWorkRequest adapt(UploadRequest<?> request, File payloadFil
4348
4449 Data inputData = request .buildPayload (payloadFile );
4550
46- return new OneTimeWorkRequest .Builder (UploadJob .class ).setBackoffCriteria (adaptBackoffPolicy (policy .getBackoffPolicy ()), policy .getBackoffMillis (), TimeUnit .MILLISECONDS ).setInputData (inputData ).setConstraints (constraints ).addTag (JOB_TAG ).build ();
51+ return new OneTimeWorkRequest .Builder (UploadJob .class ).setBackoffCriteria (adaptBackoffPolicy (policy .getBackoffPolicy ()), policy .getBackoffMillis (), TimeUnit .MILLISECONDS ).setInputData (inputData ).setConstraints (constraints ).addTag (request . getRequestId () ).build ();
4752 }
4853
4954 private static BackoffPolicy adaptBackoffPolicy (UploadPolicy .BackoffPolicy backoffPolicy ) {
@@ -99,15 +104,48 @@ public void executeRequestsNow(int howMany) {
99104 @ Override
100105 public boolean cancelRequest (String requestId ) {
101106 Operation operation = WorkManager .getInstance (context ).cancelAllWorkByTag (requestId );
107+ killThread (requestId );
102108 return operation .getResult ().isCancelled ();
103109 }
104110
105111 @ Override
106112 public int cancelAllRequests () {
107113 WorkManager .getInstance (context ).cancelAllWork ();
114+ killAllThreads ();
108115 return 0 ;
109116 }
110117
118+ private void killThread (String requestId ) {
119+ synchronized (threadsMapLockObject ) {
120+ WeakReference <Thread > ref = threads .remove (requestId );
121+ if (ref != null ) {
122+ Thread thread = ref .get ();
123+ if (thread != null ) {
124+ thread .interrupt ();
125+ }
126+
127+ ref .clear ();
128+ }
129+ }
130+ }
131+
132+ private void killAllThreads () {
133+ synchronized (threadsMapLockObject ) {
134+ for (String requestId : threads .keySet ()) {
135+ WeakReference <Thread > ref = threads .get (requestId );
136+ Thread thread = ref .get ();
137+
138+ if (thread != null ) {
139+ thread .interrupt ();
140+ }
141+
142+ ref .clear ();
143+ }
144+
145+ threads .clear ();
146+ }
147+ }
148+
111149 @ Override
112150 public int getPendingImmediateJobsCount () {
113151 return getJobCountByState (WorkInfo .State .ENQUEUED );
@@ -137,36 +175,62 @@ public static final class UploadJob extends Worker {
137175 private final Context context ;
138176 private final WorkerParameters workParams ;
139177
178+ private String requestId ;
179+
140180 public UploadJob (@ NonNull Context context , @ NonNull WorkerParameters workerParams ) {
141181 super (context , workerParams );
142182 this .context = context ;
143183 this .workParams = workerParams ;
144184 }
145185
186+ @ Override
187+ public void onStopped () {
188+ super .onStopped ();
189+ unregisterThread (requestId );
190+ }
191+
192+ private void registerThread (String requestId , Thread thread ) {
193+ synchronized (threadsMapLockObject ) {
194+ threads .put (requestId , new WeakReference <>(thread ));
195+ }
196+ }
197+
198+ private void unregisterThread (String requestId ) {
199+ synchronized (threadsMapLockObject ) {
200+ if (requestId != null ) {
201+ WeakReference <Thread > removed = threads .remove (requestId );
202+ if (removed != null ) {
203+ removed .clear ();
204+ }
205+ }
206+ }
207+ }
208+
146209 @ NonNull
147210 @ Override
148211 public Result doWork () {
149- // Removed Wakelock logic as it causes RuntimeException ("WakeLock under-locked")
150212
151213 // Prepare extract payload data from temporary file.
152214 String payloadFilePath = workParams .getInputData ().getString (UploadRequest .PayloadData .KEY );
153215 if (payloadFilePath == null ) {
154216 // NO Payload input file created prior to request.
155217 return Result .failure ();
156218 }
219+
157220 File payloadFile = new File (payloadFilePath );
158221 try (ObjectInputStream ois = new ObjectInputStream (new FileInputStream (payloadFile ))) {
159222 UploadRequest .PayloadData payloadData = (UploadRequest .PayloadData ) ois .readObject ();
160223 AndroidJobStrategy .AndroidJobRequestParams jobInputData = new AndroidJobStrategy .AndroidJobRequestParams (payloadData );
161-
162- // call the generic processor:
163- UploadStatus result = MediaManager .get ().processRequest (context , jobInputData );
224+ requestId = payloadData . getRequestId ();
225+ registerThread ( requestId , Thread . currentThread ());
226+ UploadStatus result = MediaManager .get ().processRequest (context , jobInputData ); // Replace this with your actual upload logic
164227 return adaptResult (result );
165-
166- } catch (NullPointerException | IOException | ClassNotFoundException e ) {
228+ } catch (NullPointerException | IOException | ClassNotFoundException e ) {
167229 // Unable to deserialize payload data from file.
168230 e .printStackTrace ();
169231 return Result .failure ();
232+ } finally {
233+ unregisterThread (requestId );
170234 }
171235 }
172236
0 commit comments