I'm trying to create couple of Java class to perform certain work. Let's say I want to get the task done by calling my classes like this:
FirebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = task.getResult().getUser();
// ...
} else {
// Sign in failed, display a message and update the UI
Log.w(TAG, "signInWithCredential:failure", task.getException());
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
}
}
});
I could understand up to signInWithCredential(). I can't figure out how to implement addOnCompleteListener() and have a interface as argument.
I've currently create my top class like FirebaseAuth with methods like getInstance () and signInWithCredential(). Also, I tried creating an interface but I am getting error that result of the interface is never used. How can I implement the style of addOnCompleteListener(parameter 1, interface 2).
Here, addOnCompleteListener is getting parameters of activity and interface and in my case, I will be using the activity parameter for some work.
P.S: I found out this is called interface callback. If it's right, any guidance to it's structure will be great
You can do it like this:
Create an interface:
public interface onCompleteListener {
void onComplete(MyTask object);
}
Define your MyTask class:
public abstract class MyTask {
public abstract boolean someFunc1();
public abstract String someFunc2();
public abstract String someFunc3();
}
In your main class:
public class MainClass{
public static MainClass instance;
private static Activity mActivity;
public onCompleteListener onCompleteListener;
private MainClass(Activity activity) {
mActivity = activity;
}
public static synchronized MainClass getInstance(Activity activity) {
if (instance == null) {
instance = new MainClass(activity);
}
return instance;
}
public void addOnCompleteListener(#NonNull onCompleteListener var2) {
onCompleteListener = var2;
//Call your task function
doTask();
}
public void doTask(){
MyTask o = new MyTask() {
#Override
public boolean someFunc1() {
return true;
}
#Override
public String someFunc2() {
return "";
}
#Override
public String someFunc3 {
return "";
}
};
//Once done, pass your Task object to the interface.
onCompleteListener.onComplete(o);
}
}
Usage:
MainClass.getInstance(MainActivity.this).addOnCompleteListener(new onCompleteListener() {
#Override
public void onComplete(MyTask object) {
doYourWork(object);
}
});
Related
I'm trying to implement abstract fragment with typed callback to use it in several subclasses.
How can I check if Context is instance of appropriate class?
My code of abstact CallbackFragment:
public abstract class CallbackFragment<C> extends Fragment {
protected C mCallback;
public CallbackFragment() {
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
//just in case
if(context == null)
throw new NullPointerException();
try {
mCallback = (C) context; //this line not seems to throw any exception
} catch (ClassCastException exception) {
throw new RuntimeException(context.toString() + " must implement Callbacks");
}
}
#Override
public void onDetach() {
super.onDetach();
mCallback = null;
}
}
Vehicle list fragment:
public abstract class VehicleListFragment<T extends Vehicle>
extends CallbackFragment<VehicleListFragment.Callback<T>> {
//callback for any list of any vehicle
public interface Callback<T extends Vehicle> {
void onListItemSelected(T selectedItem);
}
//common code for list of any vehicle
public VehicleListFragment() {
}
}
Bus, Truck, Boat, Bike, whatever list fragment:
public class BusListFragment
extends VehicleListFragment<Bus> {
//code specific for list of bus
public BusListFragment() {
}
}
Vehicle details fragment:
public abstract class VehicleDetailsFragment<T extends Vehicle, C extends VehicleDetailsFragment.Callback<T>>
extends CallbackFragment<C> {
//common methods of callback for any vehicle
public interface Callback<T> {
void onVehicleEdited(T editeItem);
}
//common code for any vehicle
public VehicleDetailsFragment() {
}
}
Bus, Truck, Boat, Bike, whatever details fragment:
public class BusDetailsFragment
extends VehicleDetailsFragment<Bus, BusDetailsFragment.Callback> {
//specific for Bus methods
public interface Callback
extends VehicleDetailsFragment.Callback<Bus> {
void onSomethingSpecificForBusHappened(Bus bus);
}
//code specific for Bus
public BusDetailsFragment() {
}
}
I've tried to add an abstract method for CallbackFragment to get callback class:
public abstract class CallbackFragment<C> extends Fragment {
...
#NonNull
protected abstract Class<C> getCallbackClass();
#Override
public void onAttach(Context context) {
super.onAttach(context);
...
//now checking instanceof like this
if(!getCallbackClass().isAssignableFrom(context.getClass())){
throw new RuntimeException(context.toString() + " must implement Callbacks");
}
}
}
With BusDetailsFragment everything looks OK:
public class BusDetailsFragment
extends VehicleDetailsFragment<Bus, BusDetailsFragment.Callback> {
#NonNull
#Override
protected Class<Callback> getCallbackClass() {
return Callback.class;
}
...
}
But not with BusListFragment:
public class BusListFragment
extends VehicleListFragment<Bus> {
#NonNull
#Override
protected Class<Callback<Bus>> getCallbackClass() {
/**
* I'm not seeing any option here
*
* mCallback - is null yet. So, there is no way to use mCallback.getClass()
*
* Callback<Bus>.class - Cannot select from parameterized type
*/
//return mCallback.getClass();
//return Callback<Bus>.class;
}
...
}
Of course, I could create an own interface for every subclass of VehicleListFragment that extends VehicleListFragment.Callback (like in subclasses of VehicleDetailsFragment) but it will always look like this:
public interface Callback
extends VehicleListFragment.Callback<Bus> {
//nothing more here
}
This doesn't look like the best option for me. Maybe there is any other solution? Please share your thoughts. ANY help would be appreciated.
mCallback = (C) context; //this line not seems to throw any exception
this call will never throw an Exception. During Runtime, your C is replaced with Object(that's called Type-Erasure) - and everything is an Object. Therefore you can assign anything at this point.
To have the exception (or at least error-determination) at the point, where you need it, you can use:
public abstract class CallbackFragment<C> extends Fragment {
protected C mCallback;
protected Class<C> callbackClass;
public CallbackFragment(Class<C> clazz) {
this.callbackClass = clazz;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
//just in case
if(context == null)
throw new NullPointerException();
if (clazz.isAssignableFrom(context.getClass()){
mCallback = (C) context;
}else{
//oops
}
}
}
ofc. then your FragmentCreation would change from
CallbackFragment<Something> fragment = new CallbackFragment<Something>();
to
CallbackFragment<Something> fragment = new CallbackFragment<Something>(Something.class);
It's a little different, but allows you to keep track of the actual type at any time, bypassing the Type-Erasure.
ps.: For Inherited classes, you can do it more generic:
public abstract class CallbackFragment<C> extends Fragment {
protected Class<C> callbackClass;
public CallbackFragment() {
this.callbackClass = (Class<C>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];;
}
}
public class CallbackFragmentOfSomething extends <CallbackFragment<Something>>{
}
This only fails, if your actual class is not defined due to inheritance, but "on the fly":
CallbackFragment<Something> fragment = new CallbackFragment<Something>();
(Everything untested / no copy paste, but should be somewhat accurate)
I'm implementing LoaderManager.LoaderCallbacks on my MainActivity and I'm overriding onCreateLoader. In the onCreateLoader I simply return a AsyncTaskLoader object, where I override the onStartLoading method, in which I check if the query is null. For this code works, I need to call forceLoad(). Here is a snippet of the code:
#Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
return new AsyncTaskLoader<String>(this) {
#Override
protected void onStartLoading() {
// No need to peform a query if no arguments were passed
if (args == null) {
return;
}
// This needs to be called!!
forceLoad();
}
#Override
public String loadInBackground() {
/* some code */
}
};
}
The problem is that I don't know why I need to call forceLoad(), because its implementation is a "empty" method. In the source code of the Loader Class, the implementation of forceLoad is:
public void forceLoad() {
onForceLoad();
}
and the implementation of onForceLoad() is:
protected void onForceLoad() {
}
I tried to find some methods that override forceLoad() or onForceLoad in the other parts of the code (I use (getSupportLoaderManager().initLoader(arg1, arg2, arg3)), but until this moment have not succeeded. Why do I have to call forceLoad() and why does it work?
The reason Loader class is having empty implementation of onForceLoad() is that Loader is a base class. Their child classes are supposed to be implementing onForceLoad().
If we will see your code, you are using AsyncTaskLoader which basically a child of Loader so AsyncTaskLoader will have the onForceLoad() implementation which is actually this:
#Override
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
mTask = new LoadTask();
if (DEBUG) Slog.v(TAG, "Preparing load: mTask=" + mTask);
executePendingTask();
}
Your onCreateLoader()basically should be like this:
public Loader<String> onCreateLoader(int id, final Bundle args) {
AsyncTaskLoader<String> loader = new AsyncTaskLoader<String>(this) {
#Override
protected void onStartLoading() {
// No need to peform a query if no arguments were passed
if (args == null) {
return;
}
}
#Override
public String loadInBackground() {
/* some code */
}
};
loader.forceLoad(); // This basically gonna run the loader.
return loader;
}
We can also override the onStartLoading() method to call forceLoad() which is a required step to actually trigger the loadInBackground() method to execute.
public class Loader extends AsyncTaskLoader<List<data>> {
// Tag for Log messages
private static final String LOG_TAG = Loader.class.getName();
// Query URL
private String mUrl;
/**
* Constructs a new {#link data}
*
* #param context of the activity
* #param url to load the data from
*/
public Loader (Context context, String url) {
super(context);
mUrl = url;
}
#Override
protected void onStartLoading() {
forceLoad();
}
/**
* This is on the background thread
*/
#Override
public List<data> loadInBackground() {
if(mUrl == null) {
return null;
}
// Perform the network request, parse the response and extract a list of data.
List<data> data= QueryUtils.fetchData(mUrl);
return data;
}
}
I successfully created a multiple photo uploader. It works as planned. Except I would like the ability to cancel the upload if I need to.
I know I can call cancel() on an AsyncTask if I need to cancel it.
What I would like to do is keep a reference to the AsyncTask in my photo upload object, so it can be referenced to cancel if necessary.
Doing the below works, but I can't get a reference to the async task.
UploadItem item = new UploadItem();
item.setItemFilePath(imageLocation);
item.setTaskIdentifier(UUID.randomUUID().toString());
new UploadTask().execute(item);
But I want to keep a reference to the task should I need to cancel it. So I did something like this but it crashes the app.
//Create new upload item
UploadItem item = new UploadItem();
item.setItemFilePath(imageLocation);
item.setTaskIdentifier(UUID.randomUUID().toString());
item.setAsyncTask(new UploadTask());
//Start the upload
item.getAsyncTask().execute(this);
How do you keep a reference to an Async Task in a custom object?
My custom upload object.
public class UploadItem implements Serializable {
public AsyncTask mAsyncTask;
public String itemFilePath = "";
public String taskIdentifier = "";
public boolean isUploading = false;
public AsyncTask getAsyncTask() {
Log.d("Upload Item", "Getting upload task");
return mAsyncTask;
}
public void setAsyncTask(AsyncTask asyncTask) {
Log.d("Upload Item", "Setting upload task");
this.mAsyncTask = asyncTask;
}
public String getItemFilePath() {
return itemFilePath;
}
public void setItemFilePath(String itemFilePath) {
this.itemFilePath = itemFilePath;
}
public boolean isUploading() {
return isUploading;
}
public void setUploading(boolean uploading) {
isUploading = uploading;
}
public String getTaskIdentifier() {
return taskIdentifier;
}
public void setTaskIdentifier(String taskIdentifier) {
this.taskIdentifier = taskIdentifier;
}
}
The background task:
public class UploadTask extends AsyncTask<UploadItem, Integer, HashMap<String, String>> {
#Override
protected void onPreExecute() { }
#Override
protected void onProgressUpdate(Integer... values) { }
#Override
protected void onPostExecute(HashMap<String, String> r) { }
}
I have these two methods declared:
private Result mResult;
private void setResult(Result result){
this.mResult = result;
}
private Result getResult(){
new Executor(new OnResultListener() {
#Override
public void onResult(Result result) {
setResult(result);
}
}).execute();
return mResult;
}
Im using an interface while an AsyncTask is executing. What my problem is, is that I want to return the Result object of the onResult method as an object to the getResult() method.
As shown above, I tried to set it through a setter, but it seems that this is not working.
How can I succeed that?
Thanks in advance!
You have two options here. The bad one is to wait until the new thread will finish. let's don't do that). the better way is to use a callback for:
public static interface OnResultCallback {
void onResult(Result result);
}
private void getResult(final OnResultCallback callback){
new Executor(new OnResultListener() {
#Override
public void onResult(Result result) {
setResult(result);
callback.onResult(result);
}
}).execute();
}
You could provide an instance of OnResultListener as part of the constructor of your AsyncTask, which the caller has to implement. E.g.
private Result mResult;
private OnResultListener mListener;
private void setResult(Result result, OnResultListener listener){
this.mResult = result;
mListener = listener;
}
private Result getResult(){
new Executor(new OnResultListener() {
#Override
public void onResult(Result result) {
if (mListener != null) {
mListener.onResult(result);
}
setResult(result);
}
}).execute();
return mResult;
}
or you could directly provide mListener to new Executor
public class CustomOnResultListener extends OnResultListener{
Callback callback ;
public CustomOnResultListener(Callback callback){}
this.callback =callback; // use this callback to send result
}
public interface Callback{public void onCallback(Result result);};
I'm using a multiplayer Game Client that's called AppWarp (http://appwarp.shephertz.com), where you can add event listeners to be called back when event's happen, let's assume we'll be talking about the Connection Listener, where you need to implement this interface:
public interface ConnectionRequestListener {
void onConnectDone(ConnectEvent var1);
void onDisconnectDone(ConnectEvent var1);
void onInitUDPDone(byte var1);
}
My goal here is to mainly create a Reactive version of this client to be used in my Apps Internally instead of using the Client itself directly (I'll also rely on interfaces later instead of just depending on the WarpClient itself as in the example, but that's not the important point, please read my question at the very end).
So what I did is as follows:
1) I introduced a new event, named it RxConnectionEvent (Which mainly groups Connection-Related events) as follows:
public class RxConnectionEvent {
// This is the original connection event from the source client
private final ConnectEvent connectEvent;
// this is to identify if it was Connection / Disconnection
private final int eventType;
public RxConnectionEvent(ConnectEvent connectEvent, int eventType) {
this.connectEvent = connectEvent;
this.eventType = eventType;
}
public ConnectEvent getConnectEvent() {
return connectEvent;
}
public int getEventType() {
return eventType;
}
}
2) Created some event types as follows:
public class RxEventType {
// Connection Events
public final static int CONNECTION_CONNECTED = 20;
public final static int CONNECTION_DISCONNECTED = 30;
}
3) Created the following observable which emits my new RxConnectionEvent
import com.shephertz.app42.gaming.multiplayer.client.WarpClient;
import com.shephertz.app42.gaming.multiplayer.client.events.ConnectEvent;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
public class ConnectionObservable extends BaseObservable<RxConnectionEvent> {
private ConnectionRequestListener connectionListener;
// This is going to be called from my ReactiveWarpClient (Factory) Later.
public static Observable<RxConnectionEvent> createConnectionListener(WarpClient warpClient) {
return Observable.create(new ConnectionObservable(warpClient));
}
private ConnectionObservable(WarpClient warpClient) {
super(warpClient);
}
#Override
public void call(final Subscriber<? super RxConnectionEvent> subscriber) {
subscriber.onStart();
connectionListener = new ConnectionRequestListener() {
#Override
public void onConnectDone(ConnectEvent connectEvent) {
super.onConnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_CONNECTED));
}
#Override
public void onDisconnectDone(ConnectEvent connectEvent) {
super.onDisconnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_DISCONNECTED));
}
// not interested in this method (for now)
#Override
public void onInitUDPDone(byte var1) { }
private void callback(RxConnectionEvent rxConnectionEvent)
{
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(rxConnectionEvent);
} else {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
};
warpClient.addConnectionRequestListener(connectionListener);
subscriber.add(Subscriptions.create(new Action0() {
#Override
public void call() {
onUnsubscribed(warpClient);
}
}));
}
#Override
protected void onUnsubscribed(WarpClient warpClient) {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
4) and finally my BaseObservable looks like the following:
public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {
protected WarpClient warpClient;
protected BaseObservable (WarpClient warpClient)
{
this.warpClient = warpClient;
}
#Override
public abstract void call(Subscriber<? super T> subscriber);
protected abstract void onUnsubscribed(WarpClient warpClient);
}
My question is mainly: is my implementation above correct or should I instead create separate observable for each event, but if so, this client has more than 40-50 events do I have to create separate observable for each event?
I also use the code above as follows (used it in a simple "non-final" integration test):
public void testConnectDisconnect() {
connectionSubscription = reactiveWarpClient.createOnConnectObservable(client)
.subscribe(new Action1<RxConnectionEvent>() {
#Override
public void call(RxConnectionEvent rxEvent) {
assertEquals(WarpResponseResultCode.SUCCESS, rxEvent.getConnectEvent().getResult());
if (rxEvent.getEventType() == RxEventType.CONNECTION_CONNECTED) {
connectionStatus = connectionStatus | 0b0001;
client.disconnect();
} else {
connectionStatus = connectionStatus | 0b0010;
connectionSubscription.unsubscribe();
haltExecution = true;
}
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
fail("Unexpected error: " + throwable.getMessage());
haltExecution = true;
}
});
client.connectWithUserName("test user");
waitForSomeTime();
assertEquals(0b0011, connectionStatus);
assertEquals(true, connectionSubscription.isUnsubscribed());
}
I suggest you avoid extending the BaseObservable directly since it's very error prone. Instead, try using the tools Rx itself gives you to create your observable.
The easiest solution is using a PublishSubject, which is both an Observable and a Subscriber. The listener simply needs to invoke the subject's onNext, and the subject will emit the event. Here's a simplified working example:
public class PublishSubjectWarpperDemo {
public interface ConnectionRequestListener {
void onConnectDone();
void onDisconnectDone();
void onInitUDPDone();
}
public static class RxConnectionEvent {
private int type;
public RxConnectionEvent(int type) {
this.type = type;
}
public int getType() {
return type;
}
public String toString() {
return "Event of Type " + type;
}
}
public static class SimpleCallbackWrapper {
private final PublishSubject<RxConnectionEvent> subject = PublishSubject.create();
public ConnectionRequestListener getListener() {
return new ConnectionRequestListener() {
#Override
public void onConnectDone() {
subject.onNext(new RxConnectionEvent(1));
}
#Override
public void onDisconnectDone() {
subject.onNext(new RxConnectionEvent(2));
}
#Override
public void onInitUDPDone() {
subject.onNext(new RxConnectionEvent(3));
}
};
}
public Observable<RxConnectionEvent> getObservable() {
return subject;
}
}
public static void main(String[] args) throws IOException {
SimpleCallbackWrapper myWrapper = new SimpleCallbackWrapper();
ConnectionRequestListener listner = myWrapper.getListener();// Get the listener and attach it to the game here.
myWrapper.getObservable().observeOn(Schedulers.newThread()).subscribe(event -> System.out.println(event));
listner.onConnectDone(); // Call the listener a few times, the observable should print the event
listner.onDisconnectDone();
listner.onInitUDPDone();
System.in.read(); // Wait for enter
}
}
A more complex solution would be to use one of the onSubscribe implementations to create an observable using Observable.create(). For example AsyncOnSubscibe. This solution has the benefit of handling backperssure properly, so your event subscriber doesn't become overwhelmed with events. But in your case, that sounds like an unlikely scenario, so the added complexity is probably not worth it.