I have this function that downloads all files in the ArrayList and I want to make this "synchronous" , I mean that I want to download only one file at time.
How can I make the FOR cycle to wait until a file is downloaded and than take an other file to download?
public void downloadFiles(ArrayList<String> files, final String destinationFolder){
for(String file:files){
GoogleDrive.getInstance().readFile(file, GoogleDrive.FolderLocation.ROOT_FOLDER, new GoogleDrive.GoogleDriveReadFileCallback() {
#Override
public void successful(String title, byte[] content) {
try {
FileUtils.writeByteArrayToFile(new File(destinationFolder+File.pathSeparator+title), content);
} catch (IOException e) {
Log.e(TAG,"ERROR FileManager.downloadFiles: "+e.toString());
}
}
#Override
public void notFound() { }
#Override
public void error(String error) { }
});
}
}
The question sounds pretty simple; but turns out to be hard. Why is that? Because the given code is doing things in a wrong way. What do I mean with that?
I assume that
GoogleDrive.getInstance().readFile(file,
GoogleDrive.FolderLocation.ROOT_FOLDER,
new GoogleDrive.GoogleDriveReadFileCallback()
triggers an asynchronous read from Google Drive; and upon competition, that callback instance will be called. But when we have a closer look into that callback code - we find that it is missing essential parts:
it is not doing any kind of error handling (hint: you have no idea when something went wrong with this approach)
the callback has no means to "signal" to the outside world "i am done".
Thus: the solution is to rework that thing completely. You could create a real class implementing the required interface; and that callback implementation could have methods that tell you whether file reading is still ongoing, completed successfully or failed.
In other words: you build a wrapper around GoogleDrive readFile(); and that wrapper offers synchronous reading (probably successfull() gets called when the readFile() is done - so your wrapper can simply wait for that callback); or the wrapper could return some sort of Future.
24 hours later the answear was too easy, just implemented a listener that start a new download every time an old one is terminated(with success or not) and remove it from the list. I don't know if this is the correct way to do it but it works
interface FileManagerDownloadEvent{
void downloadSuccessful(String fileName);
void downloadNotFound(String fileName);
void downloadError(String fileName,String error);
}
public class FileManager implements FileManagerDownloadEvent{
private FileManagerDownloadEvent downloadEvent;
private ArrayList<String> filesToDownload;
private String destinationFolder;
public FileManager(){
this.downloadEvent=this;
}
private void download(){
if(filesToDownload.size()!=0) {
final String file=filesToDownload.get(0);
filesToDownload.remove(0);
GoogleDrive.getInstance().readFile(file, GoogleDrive.FolderLocation.ROOT_FOLDER, new GoogleDrive.GoogleDriveReadFileCallback() {
#Override
public void successful(String title, byte[] content) {
try {
FileUtils.writeByteArrayToFile(new File(destinationFolder+File.separator+title), content);
downloadEvent.downloadSuccessful(destinationFolder+File.separator+title);
} catch (Exception e) {
Log.e(TAG,"ERROR FileManager.downloadFiles: "+e.toString());
}
}
#Override
public void notFound() {
downloadEvent.downloadNotFound(file);
}
#Override
public void error(String error) {
downloadEvent.downloadError(file,error);
}
});
}
}
#Override
public void downloadSuccessful(String filePath) {
Log.d(TAG,"downloadSuccessful: "+filePath);
download();
}
#Override
public void downloadNotFound(String fileName) {
Log.e(TAG,"downloadNotFound: "+fileName);
download();
}
#Override
public void downloadError(String fileName,String error) {
Log.e(TAG,"downloadError: "+fileName+" --> "+error);
download();
}
}
Related
I'm fairly new to RxJava and I have a basic understanding as to how to wrap a callback into an Observable but what I'm having difficulty with is doing so when the callback/listener is pre-instanced. Every example that I have found only shows instancing the callback directly into the Observable being created.
Some example code of what I'm talking about. I'm working with an Api that's works like this:
public class Api {
private ApiCallback callback;
void initialize(ApiCallback callback){
this.callback = callback;
}
void doAction1(){
this.callback.onAction1Complete();
}
}
interface ApiCallback {
void onInitialized();
void onAction1Complete();
}
With the real api I am working with I have no control over how it works so I must work with it in this state. In terms of trying to work with this Api using observables here is the struggle I am having. I have a member variable that holds the Api object:
private Api mApi = new Api();
Now in order to initialize this I have one of two options it seems.
Option 1:
Completable startApi() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
mApi.initialize(new ApiCallback() {
#Override
public void onInitialized() {
emitter.onComplete();
}
#Override
public void onAction1Complete() {
}
});
}
});
}
Option 2:
private ApiCallback premadeCallback = new ApiCallback() {
#Override
public void onInitialized() {
}
#Override
public void onAction1Complete() {
}
};
Completable startApi() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
mApi.initialize(premadeCallback);
}
});
}
Now the issue I have is that Option 2 makes more sense to me when I need to know when the other methods in the callback are called from Api calls. With my understanding of RxJava however I don't understand how I can reach these method calls with an Api that works like this.
For example:
Completable doAction1() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
// Api is already initialized with callback
// How do I reach the callback from here?
}
});
}
The only what that I can currently think of as to how to achieve this would be to create a member variable as an emitter (or a dictionary of emitters) and then call its appropriate method in the api callback when needed. My concerns with this are A. I'm unsure if RxJava can work this way B. This sounds like a terrible idea.
I've been wondering if there's any predefined class in java to handle a permanent monitoring/listening to changes on a system, in my case this system is a MQ channel, I've already writed the relevant code that provide the current status of the related channel and store it in an oracle DB.., However i have to execute it each time in order to hand over a new value to the DB ..
can you please advise me ? any bright ideas regarding this.
Hi you have to create a monitor class which will run a thread continuously and monitoring on the MQ. I have written codes for your where in comment section you have to put your code to handle your requirement. Hope this will help you:-
public final class MonitorMQ {
boolean keepProcessing_ = true;
public MonitorMQ() {
try {
Thread t = new Thread(new HealthCheck());
t.start();
}
catch (Exception e) {
}
}
private class HealthCheck implements Runnable {
public HealthCheck() {
}
#SuppressWarnings("unchecked")
public void run() {
do {
//your MQ check codes
try {
System.out.println("I will add my health check code here");
Thread.sleep(1000);
}catch(Exception e) {
e.printStackTrace();
}
}while (keepProcessing_);
}
}
private final synchronized void stopProcessing() {
keepProcessing_ = false;
}
public void destroy() {
stopProcessing();
}
}
I want to support both Synchronous and Asynchronous call using RESTEasy-JAXRS. And my asynchronous call should be based on callback, where Async request will have callbackURI, request gets processed asynchronously and upon completion makes a call to callbackURI with operation status/result. Can someone point me out to correct place? I see lot about polling model, but not callback with RESTEasy.
I am new to Asynchronous stuff...
Thanks in advance!
Thanks for your response rmlan.Yes but we have support in JAX-RS to handle asynchronous using #Suspended & AsyncResponse. I did that with following code, but i am unable to find the way to make callback to Client who called the API upon completion of task with this request.
#GET
#Path("/async")
public String checkAsync(#Suspended final AsyncResponse response) {
response.setTimeoutHandler(new TimeoutHandler() {
#Override
public void handleTimeout(AsyncResponse asyncResponse) {
response.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE)
.entity("Operation time out.").build());
}
});
response.setTimeout(2, TimeUnit.SECONDS);
new Thread(new Runnable() {
#Override
public void run() {
String result = veryExpensiveOperation();
response.resume(result);
}
private String veryExpensiveOperation() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.debug("Task is processed fully");
return "Successful";
}
}).start();
return "nothing";
}
Every method in class has one return ( or maybe void ) . but sometimes you need some callbacks from your method . this is the solution .
public abstract class MyClass {
public abstract void myCallbackMethod();
public void myMethod(){
for (int i = 0; i < 5; i++) {
// do somthing
myCallbackMethod();// it will implements in future.
}
}
}
when you make an object from MyClass , you must implement myCallbackMethod abstract method . like this
public class NewMain {
public static void main(String[] args) {
MyClass myClass=new MyClass() {
#Override
public void myCallbackMethod() {
System.err.println("this is call back");
}
};
myClass.myMethod();
}
}
and the result is
this is call back
this is call back
this is call back
this is call back
this is call back
it means you can get five call backs from void method in your class.
it is a good way when you do not have any idea for the body content of myCallBackMethod
the real example is download a file from server in your app .
you can call myCallBackMethod when bytes received and progress your progressbar
I am working on a plugin for IntelliJ Idea 13. I do some changes in beforeDocumentSaving and I use document.setText:
public class AppendAction implements ApplicationComponent
{
#Override public void initComponent()
{
MessageBus bus = ApplicationManager.getApplication().getMessageBus();
MessageBusConnection connection = bus.connect();
connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter()
{
#Override public void beforeDocumentSaving(Document document)
{
document.setText(appendSomething(document.getText()));
}
});
}
}
This works great, my only problem is that when this plugin is run, and I want to undo the changes, I get to following error message:
Cannot Undo
Following files have changes that cannot be undone:
Any Idea? :-)
The answer is wrapping the document.setText into ApplicationManager.getApplication().runWriteAction and CommandProcessor.getInstance().runUndoTransparentAction.
I found an example TrailingSpacesStripper among intellij-community sources on githib:
https://github.com/JetBrains/intellij-community/blob/master/platform/platform-impl/src/com/intellij/openapi/editor/impl/TrailingSpacesStripper.java
public class AppendAction implements ApplicationComponent
{
#Override public void initComponent()
{
MessageBus bus = ApplicationManager.getApplication().getMessageBus();
MessageBusConnection connection = bus.connect();
connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter()
{
#Override public void beforeDocumentSaving(final Document document)
{
ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(document, null)
{
#Override public void run()
{
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable()
{
#Override public void run()
{
document.setText(appendSomething(document.getText()));
}
});
}
});
}
});
}
}
You should wrap the change through the CommandProcessor API.
From IntelliJ IDEA Architectural Overview:
Any operations which modify the contents of the document must be wrapped in a command (CommandProcessor.getInstance().executeCommand()). executeCommand() calls can be nested, and the outermost executeCommand call is added to the undo stack. If multiple documents are modified within a command, undoing this command will by default show a confirmation dialog to the user.
I am trying to understand mechanism of callback handler. How is the handle() method invoked? Can anybody give an example of usage of custom callback handler (other than those used in Login Modules of JASS or so) in non Swing application?
Define an interface to handle the callback.
public interface ServiceListener<T> {
void callback(T result);
}
Define a method that takes ServiceListener as parameter and returns void.
Public void runInBackground(ServiceListener listener) {
...code that runs in the background...
listener.callback(...data to return to caller...);
}
And you can now do this from your main code:
runInBackground(new ServiceListener() {
#Override
public void callback(..returned data...) {
...Do stuff with returned data...
}
});
This is a basic example for requesting data from a webserver using the AsyncTask from an Android application.
First define the async class. Note that the constructor takes a listener which we use to publish the result once ready.
public class Webservice extends AsyncTask<String, Void, String> {
private DialogListener dialogListener;
public Webservice(final DialogListener dialogListener) {
this.dialogListener = dialogListener;
}
#Override
protected String doInBackground(final String... strings) {
// We cant trigger onComplete here as we are not on the GUI thread!
return "";
}
protected void onPostExecute(final String result) {
dialogListener.onComplete(result);
}
}
Basic server class for handling various network communications:
public class Server {
public void queryServer(final String url, final DialogListener service) {
// Simulate slow network...
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Webservice(service).execute(url);
}
}
We can now use this code inside our activity without having to worry how long the call takes as it is not going to halt the GUI as it is executed async.
Server s = new Server();
// Async server call.
s.queryServer("http://onto.dk/actions/searchEvents.jsp?minLatE6=55640596&minLngE6=12078516&maxLatE6=55642654&maxLngE6=12081948", new DialogListener() {
#Override
public void onComplete(final String result) {
toast("complete");
}
#Override
public void onError() {
toast("error");
}
});