Skip to content

Commit

Permalink
#450 implemented delegates substitute, making the RequestObserver (Br…
Browse files Browse the repository at this point in the history
…oadcastReceiver) Lifecycle aware and adding addional onCompletedWhileNotObserving method to cover an edge case
  • Loading branch information
gotev committed Oct 20, 2019
1 parent e367817 commit 1e64b0a
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import net.gotev.uploadservice.UploadServiceConfig;
import net.gotev.uploadservice.data.RetryPolicyConfig;
import net.gotev.uploadservice.logger.UploadServiceLogger;
import net.gotev.uploadservice.observer.request.RequestObserver;
import net.gotev.uploadservice.okhttp.OkHttpStack;

import java.io.IOException;
Expand Down Expand Up @@ -64,8 +65,7 @@ public void onCreate() {

createNotificationChannel();

GlobalBroadcastReceiver receiver = new GlobalBroadcastReceiver();
receiver.register(this);
new RequestObserver(this, new GlobalBroadcastReceiver()).register();
}

private void createNotificationChannel() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import net.gotev.uploadservice.data.UploadInfo
import net.gotev.uploadservice.exceptions.UploadError
import net.gotev.uploadservice.exceptions.UserCancelledUploadException
import net.gotev.uploadservice.network.ServerResponse
import net.gotev.uploadservice.observer.request.RequestObserver
import net.gotev.uploadservice.observer.request.RequestObserverDelegate

/**
* @author Aleksandar Gotev
*/
class GlobalBroadcastReceiver : RequestObserver() {
class GlobalBroadcastReceiver : RequestObserverDelegate {
override fun onProgress(context: Context, uploadInfo: UploadInfo) {
Log.e("RECEIVER", "Progress: $uploadInfo")
}
Expand All @@ -21,7 +21,7 @@ class GlobalBroadcastReceiver : RequestObserver() {
}

override fun onError(context: Context, uploadInfo: UploadInfo, exception: Throwable) {
when(exception) {
when (exception) {
is UserCancelledUploadException -> {
Log.e("RECEIVER", "Error, user cancelled upload: $uploadInfo")
}
Expand All @@ -40,4 +40,8 @@ class GlobalBroadcastReceiver : RequestObserver() {
override fun onCompleted(context: Context, uploadInfo: UploadInfo) {
Log.e("RECEIVER", "Completed: $uploadInfo")
}

override fun onCompletedWhileNotObserving() {
Log.e("RECEIVER", "Completed while not observing")
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package net.gotev.uploadservicedemo;

import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

import net.gotev.recycleradapter.AdapterItem;
import net.gotev.uploadservice.data.UploadInfo;
import net.gotev.uploadservice.network.ServerResponse;
import net.gotev.uploadservice.observer.request.RequestObserverDelegate;
import net.gotev.uploadservice.protocols.multipart.MultipartUploadRequest;
import net.gotev.uploadservicedemo.adapteritems.EmptyItem;
import net.gotev.uploadservicedemo.adapteritems.UploadItem;
import net.gotev.uploadservicedemo.utils.UploadItemUtils;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.UUID;

Expand Down Expand Up @@ -72,8 +79,34 @@ public void onFile(UploadItem item) {

});

request.startUpload();
finish();
request.subscribe(this, new RequestObserverDelegate() {
@Override
public void onProgress(@NotNull Context context, @NotNull UploadInfo uploadInfo) {
Log.e("LIFECYCLE", "Progress " + uploadInfo.getProgressPercent());
}

@Override
public void onSuccess(@NotNull Context context, @NotNull UploadInfo uploadInfo, @NotNull ServerResponse serverResponse) {
Log.e("LIFECYCLE", "Success " + uploadInfo.getProgressPercent());
}

@Override
public void onError(@NotNull Context context, @NotNull UploadInfo uploadInfo, @NotNull Throwable exception) {
Log.e("LIFECYCLE", "Error " + exception.getMessage());
}

@Override
public void onCompleted(@NotNull Context context, @NotNull UploadInfo uploadInfo) {
Log.e("LIFECYCLE", "Completed ");
finish();
}

@Override
public void onCompletedWhileNotObserving() {
Log.e("LIFECYCLE", "Completed while not observing");
finish();
}
});

} catch (Exception exc) {
Toast.makeText(this, exc.getMessage(), Toast.LENGTH_LONG).show();
Expand Down
2 changes: 1 addition & 1 deletion manifest.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ext {
library_licenses = ["Apache-2.0"]
library_licenses_url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
library_project_group = 'net.gotev'
library_version = '4.0.0-alpha01'
library_version = '4.0.0-alpha02'
version_code = 40
min_sdk = 21
target_sdk = 29
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import net.gotev.uploadservice.data.UploadFile
import net.gotev.uploadservice.data.UploadNotificationConfig
import net.gotev.uploadservice.data.UploadTaskParameters
import net.gotev.uploadservice.extensions.startNewUpload
import net.gotev.uploadservice.observer.request.SingleRequestObserver
import net.gotev.uploadservice.observer.request.RequestObserver
import net.gotev.uploadservice.observer.request.RequestObserverDelegate
import java.util.*

/**
Expand Down Expand Up @@ -63,10 +64,19 @@ constructor(protected val context: Context, protected var serverUrl: String) {
* Subscribe to events of this upload request
* @param observer observer to listen for events.
*/
fun subscribe(observer: SingleRequestObserver) {
fun subscribe(observer: RequestObserver) {
observer.subscribe(this)
}

/**
* Subscribe to events of this upload request by creating a new request observer.
* @param context context
* @param delegate Observer delegate implementation
*/
fun subscribe(context: Context, delegate: RequestObserverDelegate): RequestObserver {
return RequestObserver(context, delegate).apply { subscribe(this@UploadRequest) }
}

protected abstract fun getAdditionalParameters(): Parcelable

@Suppress("UNCHECKED_CAST")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,29 @@ package net.gotev.uploadservice.observer.request
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import net.gotev.uploadservice.UploadRequest
import net.gotev.uploadservice.UploadService
import net.gotev.uploadservice.UploadServiceConfig
import net.gotev.uploadservice.data.BroadcastData
import net.gotev.uploadservice.data.UploadInfo
import net.gotev.uploadservice.data.UploadStatus
import net.gotev.uploadservice.network.ServerResponse

abstract class RequestObserver : BroadcastReceiver() {
class RequestObserver(
private val context: Context,
private val delegate: RequestObserverDelegate
) : BroadcastReceiver(), LifecycleObserver {

final override fun onReceive(context: Context, intent: Intent?) {
private var subscribedUploadID: String? = null

init {
(context as? LifecycleOwner)?.lifecycle?.addObserver(this)
}

override fun onReceive(context: Context, intent: Intent?) {
val safeIntent = intent ?: return
if (safeIntent.action != UploadServiceConfig.broadcastAction) return
val data = BroadcastData.fromIntent(safeIntent) ?: return
Expand All @@ -23,81 +37,53 @@ abstract class RequestObserver : BroadcastReceiver() {
}

when (data.status) {
UploadStatus.IN_PROGRESS -> onProgress(context, uploadInfo)
UploadStatus.ERROR -> onError(context, uploadInfo, data.exception!!)
UploadStatus.SUCCESS -> onSuccess(context, uploadInfo, data.serverResponse!!)
UploadStatus.COMPLETED -> onCompleted(context, uploadInfo)
UploadStatus.IN_PROGRESS -> delegate.onProgress(context, uploadInfo)
UploadStatus.ERROR -> delegate.onError(context, uploadInfo, data.exception!!)
UploadStatus.SUCCESS -> delegate.onSuccess(context, uploadInfo, data.serverResponse!!)
UploadStatus.COMPLETED -> delegate.onCompleted(context, uploadInfo)
}
}

/**
* Method called every time a new event arrives from an upload task, to decide whether or not
* to process it. This is useful if you want to filter events based on custom business logic.
* to process it. If this request observer subscribed a particular upload task, it will listen
* only to it
*
* @param uploadInfo upload info to
* @return true to accept the event, false to discard it
*/
open fun shouldAcceptEventFrom(uploadInfo: UploadInfo): Boolean {
return true
private fun shouldAcceptEventFrom(uploadInfo: UploadInfo): Boolean {
val uploadId = subscribedUploadID ?: return true
return uploadId == uploadInfo.uploadId
}

/**
* Register this upload receiver.<br></br>
* If you use this receiver in an [android.app.Activity], you have to call this method inside
* [android.app.Activity.onResume], after `super.onResume();`.<br></br>
* If you use it in a [android.app.Service], you have to
* call this method inside [android.app.Service.onCreate], after `super.onCreate();`.
*
* @param context context in which to register this receiver
* Register this upload receiver to listen for events.
*/
fun register(context: Context) {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun register() {
context.registerReceiver(this, UploadServiceConfig.broadcastIntentFilter)

subscribedUploadID?.let {
if (!UploadService.taskList.contains(it)) {
delegate.onCompletedWhileNotObserving()
}
}
}

/**
* Unregister this upload receiver.<br></br>
* If you use this receiver in an [android.app.Activity], you have to call this method inside
* [android.app.Activity.onPause], after `super.onPause();`.<br></br>
* If you use it in a [android.app.Service], you have to
* call this method inside [android.app.Service.onDestroy].
*
* @param context context in which to unregister this receiver
* Unregister this upload receiver from listening events.
*/
fun unregister(context: Context) {
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun unregister() {
context.unregisterReceiver(this)
}

/**
* Called when the upload progress changes.
*
* @param context context
* @param uploadInfo upload status information
* Subscribe to get only the events from the given upload request. Otherwise, it will listen to
* all the upload requests.
*/
abstract fun onProgress(context: Context, uploadInfo: UploadInfo)

/**
* Called when the upload is completed successfully.
*
* @param context context
* @param uploadInfo upload status information
* @param serverResponse response got from the server
*/
abstract fun onSuccess(context: Context, uploadInfo: UploadInfo, serverResponse: ServerResponse)

/**
* Called when an error happens during the upload.
*
* @param context context
* @param uploadInfo upload status information
* @param exception exception that caused the error
*/
abstract fun onError(context: Context, uploadInfo: UploadInfo, exception: Throwable)

/**
* Called when the upload is completed wither with success or error.
*
* @param context context
* @param uploadInfo upload status information
*/
abstract fun onCompleted(context: Context, uploadInfo: UploadInfo)
fun subscribe(request: UploadRequest<*>) {
subscribedUploadID = request.startUpload()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package net.gotev.uploadservice.observer.request

import android.content.Context
import net.gotev.uploadservice.data.UploadInfo
import net.gotev.uploadservice.network.ServerResponse

interface RequestObserverDelegate {
/**
* Called when the upload progress changes.
*
* @param context context
* @param uploadInfo upload status information
*/
fun onProgress(context: Context, uploadInfo: UploadInfo)

/**
* Called when the upload is completed successfully.
*
* @param context context
* @param uploadInfo upload status information
* @param serverResponse response got from the server
*/
fun onSuccess(context: Context, uploadInfo: UploadInfo, serverResponse: ServerResponse)

/**
* Called when an error happens during the upload.
*
* @param context context
* @param uploadInfo upload status information
* @param exception exception that caused the error
*/
fun onError(context: Context, uploadInfo: UploadInfo, exception: Throwable)

/**
* Called when the upload is completed wither with success or error.
*
* @param context context
* @param uploadInfo upload status information
*/
fun onCompleted(context: Context, uploadInfo: UploadInfo)

/**
* Called only when listening to a single upload ID and you register the request observer,
* but the upload ID is not present in UploadService's task list, meaning it has completed.
* In this case, you cannot know with which state it finished (success or error).
*
* Useful when used in activities and the following scenario applies:
* - user triggers an upload in an activity which shows the progress
* - user navigates away from that activity and comes back later after the upload completed and
* you need to to some stuff to adjust UI properly
*/
fun onCompletedWhileNotObserving()
}

This file was deleted.

0 comments on commit 1e64b0a

Please sign in to comment.