In IOS we use blocks when we want to handle an action when a particular situation occur.
Is there a way like this in android to handle situation onCompletion and we can add where ever it is.
Like AsyncTask methods it knows when work is finish . it executes onPostExecute. How we can create this type of method when a particular situation reach and we handle it like .
Today i find a way which behave like Blocks in IOS
BaseAsyncTask(new Callback(){
onPostResult(string result)
{
// do whatever you want to do with the result got from asynctaks
}
});
it is a delegate and it calls when it reaches a particular situation..
Am i right that the above code is block in android as we do in IOS. or there any other way of creating blocks in android.
Behave like iOS Block:
A. Let say, in your class APISingleton (e.g Volley request-API in singleton class):
Define the Interface outside your class:
// Callback Blueprint
interface APICallback {
void onResponse(User user, boolean success, String message); // Params are self-defined and added to suit your needs.
}
In your API-request function
public void requestAPIWithURL:(String url, final APICallback callback) {
// ....
// After you receive your volley response,
// Parse the JSON into your model, e.g User model.
callback.onResponse(user, true, "aloha");
}
B. So, how to call API request and pass your callback function from your activity, or fragment, is like this:
APISingleton.getInstance().requestAPIWithURL("http://yourApiUrl.com", new APICallback() {
#Override
public void onResponse(User user, boolean success, String message) {
// you will get your user model, true, and "aloha" here
mUser = user;
Log.v(TAG, "success:" + success);
Log.v(TAG, "aloha or die?" + message);
// Your adapter work. :D
}
});
It seems that you have two questions in your question so I will answer them both
Is there a way like this in android to handle situation onCompletion and we can add where ever it is?
How we can create this type of method when a particular situation is reached?
Yes there is a way. I have asked the same thing once here.
In this cases, you use Runnable. You use it like so:
//creating a runnable block
Runnable block = new Runnable() {
#Override
public void run() {
//code here
}
};
//passing it on arguments
doSomething(block); //just like a normal variable
//using it on the method
public void doSomething(Runnable block) {
block.run();
}
Your 2nd question:
BaseAsyncTask(new Callback(){
onPostResult(string result)
{
// do whatever you want to do with the result got from asynctaks
}
});
Am i right that the above code is block in android as we do in IOS. or there any other way of creating blocks in android.
Yes in my opinion, the object Callback behaves the same as the blocks in Objective C as I have shown in my previous examples. When the async task is completed (the result is already available) then that Callback is called. Probably like so:
callback.onPostResult();
Just for your information, the Objects Runnable and Callback are java interfaces. More on interfaces here. If you do not need extra parameters for your callback, you can just use the Runnable so as to avoid reinventing the wheel. But if there is something special, i.e. you want to pass paramters to the callback, then you can create your own interface and use it like a Runnable.
Related
I've a Worker in which i first want to apply FFMPEG command before uploading it to server. As Worker is already running in background so to keep the result on hold until file uploads I've used RxJava .blockingGet() method. But I'm unable to understand that how to execute FFmpeg command synchronously by anyway i.e. RxJava etc. One tip that I found is to use ListenableWorker but it's documentation says that it stops working after 10 minutes. So, i don't want to go with that solution. Following is the method of FFmpeg just like any other async method. How can i make it synchronous or integrate it with RxJava? Any ideas would be appreciable.
ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
#Override
public void onFailure(String s) {
}
#Override
public void onSuccess(String s) {
uploadMediaItem(mediaUpload);
}
#Override
public void onProgress(String s) {
}
#Override
public void onStart() {
}
#Override
public void onFinish() {
// countDownLatch.countDown();
}
});
This is the flow of my Worker:
check pending post count in DB.
Pick first post and check if it has pending media list to upload.
Pick media recursively and check if editing is required on it or not.
Apply FFmpeg editing and upload and delete from DB.
Repeat the cycle until last entry in the DB.
Thanks
If you wanna create a syncronous job you need to use the CountDownLatch class (there is a comment in your code).
CountDownLatch is a syncronization object that can be used in cases like this.
As for now there isn't a valid method to have sync workers.
Listenable workers is useful when you want to monitor the worker itself from your app using a Livedata that return useful information (e.g. the status).
If I remember correctly the standard Worker class also descend from Listenable worker so you can use that.
In your case is useful to have two workers: the first apply a FFMPEG command, and the second worker that take the output of this command to do the network upload. Separating this two operations allows you to have more time for complete the two works (10 + 10).
In your case you can do something like this for the first worker:
private final CountDownLatch syncLatch = new CountDownLatch(1);
...ctor
doWork(){
//your asyncronous call
...
#Override
public void onFinish() {
//you need to save error status into a onSuccess and onFailure
syncLatch.countDown();
}
...
//end
syncLatch.await();
...
//evaluate if there are errors
...
//create output to pass to the next worker
Data outputData = ...
//pass the result to second worker, remember that onfailure will stop all subsequent workers
if(error==true)
{
return Result.failure(outputData);
}else{
return Result.success(outputData);
}
}
For the second worker you can do the same according to your upload function behavihour to syncronize the call.
Hope this help.
Cheers.
I have an async method makeRequest() with callback. It called many times from different classes of my application. I need that this calls start one by one and never simultaneously.
I want to implement this using Rx. Like this:
public void execute() { // This method called many times from another classes
Observable.just(true)
// what I need to add here?
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(o -> {
internalExecute();
return o;
})
.subscribe();
}
private void internalExecute() { // This method should called only when previous call was finished
makeRequest(this::onRequestFinished);
}
private void onRequestFinished() {
// here is I handle request finish
}
But at now all requests works at parallel. What I need to add here to run requests one by one?
According to comments, you have here separated streams and requests. each client that execute request expect a result from the request. but no requests allowed to run in parallel, in this case I think the easiest way is to limit the Scheduler to an application global background sequential thread Executor, i.e:
Schedulers.from(Executors.newSingleThreadExecutor())
provide somewhere in your app this single thread Executor, in singleton manner of course, it's important that each request stream will use the same object:
private final Scheduler singleThreadScheduler = Schedulers.from(Executors.newSingleThreadExecutor());
public void execute() { // This method called many times from another classes
Observable.just(true)
.map(o -> {
internalExecute();
return o;
})
.subscribeOn(singleThreadScheduler)
.subscribe();
}
private void internalExecute() { // This method should called only when previous call was finished
makeRequest(this::onRequestFinished);
}
private void onRequestFinished() {
//NOTE: you should make sure that the callback execute where you need it (main thread?)
// here is I handle request finish
}
besides that, you're not exposing Observable outside, to the clients, but rather using callback mechanism, you can leverage reactive approach further, by making execute() returning Observable. (and enjoy composition of Obesrvables, operators, proper use of observeOn/subscribeOn, error handling with onError, disposing/unsubscribing etc.), as you're using async api, you can use fromEmitter()/create() (in newer RxJava1 version)), read more here:
private final Scheduler singleThreadScheduler = Schedulers.from(Executors.newSingleThreadExecutor());
public Observable<Result> execute() { // This method called many times from another classes
return Observable.fromEmitter(new Action1<Emitter<? extends Object>>() {
#Override
public void call(Emitter<?> emitter) {
emitter.setCancellation(() -> {
//cancel request on unsubscribing
});
makeRequest(result -> {
emitter.onNext(result);
});
}
})
.subscribeOn(singleThreadScheduler)
}
I am using RxJava to move network access to a separate thread in Android, but my UI still blocks.
I am not using the wrong observable as shown here: Android RxJava, Non Blocking?
The codepoints [A], [B] and [C] in below code are passed in the order [A] -> [C] -> [B] so the current thread is processed fine and RxJava calls [C] once it had a result. This is fine.
Also, blocking is much better compared to doing the network call on the UI thread, but I still have minor blocking. The UI stays fluent after the call is made, but if the server does not respond in a matter of milliseconds, it blocks.
private search; // search is an instance variable in the same class
// [A]
Observable.just(search.find("something")) // search.find calls the REST endpoint
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Search>() {
#Override public void call(Search search) {
// further processing // [B]
}
}, new Action1<Throwable>() {
#Override public void call(Throwable throwable) {
// error handler
}
});
// [C]
Could it be a problem that search is an instance variable in the same class where the Observable uses it, but the endpoint call is performed from a separate library? It shouldn't matter, right?
Am I doing anything bad that I shouldn't be doing?
--
Find looks like this (removed exception handling for brevity):
public Search find(String searchtext) {
setSearchtext(searchtext);
SearchEndpoint.find(Session.getUser().getId(), searchtext);
return this;
}
SearchEndpoint like this:
public static Search find(final Long userId, final String searchtext) throws IOException {
return ApiService.api().searches().find(userId).setFind(searchtext).execute();
}
and makes a call to the generated Google cloud endpoint library.
Try this:
Observable.create(new Observable.OnSubscribe<Search>() {
#Override
// method signature is from memory - I hope I am correct...
public void call(Subscriber<? super Search> subscriber) {
try {
Search search = search.find("something");
subscriber.onNext(search);
subscriber.onCompleted();
} catch (SomeException e) {
subscriber.onError(e);
}
}
})
// and then continue with your .subscribeOn(...)
To clarify, maybe this makes the problem with your code more obvious:
Observable.just(search.find("something"))
is clearly equivalent to
Search search = search.find("something");
Observable.just(search)
And this makes it obvious that search.find is executed before we ever hand the control over to rxjava and it is executed on whatever thread you are currently on - then the construction of an Observable from the pre-computed value and the delivery of the value happen on another thread but that does not help you much...
I know this is a few months old-- but instead of createing an entirely new Observable (which is relatively error-prone), you can use the map operator to run the search:
String search_input = "something"; // this is where you can specify other search terms
Observable.just(search_input)
.map(s -> search.find(s)) // search.find calls the REST endpoint
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe( // your subscriber goes here
If not using lambdas, that map function should look like:
.map(new Func1<String, Search>() {
#Override
public Search call(String s) {
return search.find(s)
}
})
I think this is a quite common problem, but still I didn't find a satisfactory answer so I'm going to ask myself.
This is a piece of code:
// this is insine OnClickView
TextView status = (TextView) findViewById(R.id.status);
status.setText("Trying to connect to the server...");
try {
// this opens a socket and send a login request to the server.
int result = CommunicationManager.login(String email, String password);
switch (result) {
case CommunicationManager.SUCCESS:
// login ok, go on with next screen
break;
case CommunicationManager.WRONG_EMAIL:
status.setTextColor(Color.RED);
status.setText("Wrong Email!");
break;
case CommunicationManager.WRONG_PASSWORD:
status.setTextColor(Color.RED);
status.setText("Wrong Password!");
break;
}
} catch (CommunicationException e) {
status.setTextColor(Color.RED);
status.setText("Unable to estabilish a connection!");
} catch (ProtocolException e) {
status.setTextColor(Color.RED);
status.setText("Protocol error!");
}
This is what I would like to achieve:
User click Send button;
status textview shows "Trying to connect to the server...";
UI "waits" for communications to be over;
status textview shows result accordingly.
But instead when user clicks Send button, UI freezes (oddly before status text appears) until communication is done (I tried to connect to an unknown host).
A quick fix is to set a socket timeout, but I don't like this kind of solution: UI still freezes and which timeout should be set?
My first thought were Thread obviously, but as you can see I need to return a value, thing that in threading environment doesn't make much sense since threads run independently and asynchronously.
So what I need is definitely that UI waits for the service to be executed but without freezing.
By the way it seems to me that waiting for a return value means that UI has to wait for the task to be over, I just would not let it freeze.
I came across AsyncTask but I see two major disadvantages:
it seems to me that is too tightly coupled with UI;
what if I want to execute service with Integer, String and Boolean parameters? Should I extend AsyncTask<Object, Void, Void>?
Both leads to inextensibility.
What can I do to achieve my goal?
Please note that another request to the service will be a request for something that could not be ready yet, so I should automatically repeat request every few time (let's say ten minutes). So probably I'll need something I can use with TimerTask, but I'll still need to return a value to UI every time I execute that service (so I can update the status text and let the user know what's going on).
This is typical use case while dealing through external communication i.e. HTTP calls.
Best way is to use AsyncTask. To give you answers for your concerns for AsyncTask.
it seems to me that is too tightly coupled with UI;
Here good code design will play a role. You can write you own call back mechanism to get rid of tight coupling. Example can be below.
Create your version for request and response you need for WS call. It can be very simple primitive type or complex type parameters.
class Result{
//Define more para.
}
class Request{
//Deinf more para.
}
Write below callback interface.
public interface MyCallBack {
public void onComplete(Result result);}
Create AsyncTask and get above Interface object in constructor, same object can return Result object.
class LongRunningTask extends AsyncTask<Request, Integer, Long>{
private MyCallBack callback;
public LongRunningTask(MyCallBack callback) {
super();
this.callback = callback;
}
#Override
protected Long doInBackground(Request... params) {
// Perform your back ground task.
return null;
}
#Override
protected void onPostExecute(Long result) {
super.onPostExecute(result);
callback.onComplete(new Result()); //Here result is dummy but in real it should be contructred from doInBackground() method
}
}
Now last and important part to implement the interface and call asynctask. I am trying to reuse your code to have better clarity.
public class MainActivity extends Activity implements MyCallBack{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView status = (TextView) findViewById(R.id.status);
status.setText("Trying to connect to the server...");
}
private void onClick(){
//Similer to CommunicationManager.login(String email, String password); in your code.
LongRunningTask longRunningTask = new LongRunningTask(this);
longRunningTask.execute(new Request());
}
#Override
public void onComplete(Result result) {
try {
int result = result.getStatus
switch (result) {
case CommunicationManager.SUCCESS:
// login ok, go on with next screen
break;
case CommunicationManager.WRONG_EMAIL:
status.setTextColor(Color.RED);
status.setText("Wrong Email!");
break;
case CommunicationManager.WRONG_PASSWORD:
status.setTextColor(Color.RED);
status.setText("Wrong Password!");
break;
}
} catch (CommunicationException e) {
status.setTextColor(Color.RED);
status.setText("Unable to estabilish a connection!");
} catch (ProtocolException e) {
status.setTextColor(Color.RED);
status.setText("Protocol error!");
}
}
what if I want to execute service with Integer, String and Boolean parameters? Should I extend AsyncTask?
First Parameter is any user defined para. In case you need to pass multiple parameters then put them in to form of entity (i.e. - Class). Also, you can pass initial configuration parameter in constructor of AsyncTask i.e. - Communication URL.
Hope it will help.
Use multi threading, do all the communication in a different thread
Use worker thread, or AsyncTask for doing long-running operations.
Moreover, from Android Honeycomb, system throws exception, if you perform network operations on UI thread.
I have the following void:
public void load() {
//loading big picture from the Internet
}
And i want it to run in a new Thread.
I can call this procedure like this:
new Thread(new Runnable() {
public void run() {
load();
}
}).start();
or it would be better to modify this void:
public void load() {
new Thread(new Runnable() {
public void run() {
//loading big picture from the Internet
}
}).start();
}
and simply call it:
load();
Or there is no different?
Functionally, they are identical. There are designed details that might make you consider the first way over the other.
You may want the first option if you had a lot of different threads that didn't their own individual things but also called load(). In that case, you already had created the thread, so if they called load() you wouldn't want/need to create another.
The second option is very convenient. You can simply call load() wherever you want. If, in the future, the load() method changes to a point where it's not blocking, then you can change it and no further code changes would be needed.
Alternatively, consider using AsyncTask for this as previously suggested. It was specifically built for exactly what you're trying to do.