Need to wait for file to be available - java

Below is my code where I need to convert my JSON file to an Excel file. Loading the JSON from another method will take some time, so I need to wait till the file is present.
public class converter2_ES {
#Test
public void main() throws Exception {
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter dateformat = DateTimeFormatter.ofPattern("dd-MM-yyyy HH-mm-ss");
String formatedate =date.format(dateformat);
Workbook workbook = new Workbook(".//json_files//elastic_search.json");
//workbook.save(".//output-"+formatedate+".xlsx");
workbook.save(".//Excel_files//es_files//ES-"+formatedate+".xlsx");
System.out.println("Elastic_searchjson file converted successfully");
}
}

Question
In my test, the file .//json_files//elastic_search.json is actually written by another test. How can I make sure that this test is run after the test that writes the file to disk?
This question had to be extracted from the comments.
Answer
The answer is, it depends...
Generally speaking, tests should not have temporal coupling with one another. Meaning that test2() should not rely on the outcome or behavior of test1().
There are many ways of fixing this problem, it could be fixed by having your tests in two different classes each having their own particular setup() methods with an #BeforeEach annotation.
Another solution is to make sure that the tests run in the correct order. There are ways of adding order via the #Test annotation depending on which testing framework you're using.

You should make a async implementation that is, you should wait until previous task has been completed to proceed with next task, you can refer to this simple tutorial ANDROID - HTTP REQUEST USING ASYNCTASK TUTORIAL IN JAVA
Below is the code sample you can refer to:
public class MainActivity extends AppCompatActivity {
private Button btn;
private EditText time;
private TextView res;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
time = findViewById(R.id.in_time);
btn = findViewById(R.id.btn_start);
finalRes = findViewById(R.id.res);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AsyncTaskRunner runner = new AsyncTaskRunner();
String sleepTime = time.getText().toString();
runner.execute(sleepTime);
}
});
}
private class AsyncTaskRunner extends AsyncTask<String, String,
String> {
private String resp;
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(MainActivity.this,
"PleaseWait",
"Loading"+time.getText().toString()+ "secs");
}
#Override
protected String doInBackground(String... params) {
publishProgress("TimeSpent...");
try {
int time = Integer.parseInt(params[0])*1000;
Thread.sleep(time);
resp = "Time Spent" + params[0] + "secs";
} catch (InterruptedException e) {
e.printStackTrace();
resp = e.getMessage();
} catch (Exception e) {
e.printStackTrace();
resp = e.getMessage();
}
return resp;
}
#Override
protected void onPostExecute(String result) {
// execution of result of Long time consuming operation
progressDialog.dismiss();
finalRes.setText(result);
}
}
}

If you want to wait for a file to be created by another program:
How to wait on file creation - which has examples on how to use the WatchService. However, note that you get an event to indicate that a file has been created, but you don't get one to say that file creation (i.e. writing) has completed. So, depending on how the save() method works, you will probably need to check the file size of modification timestamp to see when they stop changing.
From my reading of the javadocs, the WatchService should report file events for files created by the current program as well, but there may be better ways. For example, if you want to wait for a file to be created by another thread:
If you are using naked threads or thread subclasses, use Thread.join() to wait for the thread doing the creation to finish.
If you are using an ExecutorService rather than naked threads, keep the Future object returned when you submit a task and use it to detect when the task has completed.
If you are doing this in some test code, the WatchService may be overkill. A simple polling loop (with a sleep) that tests to see that the target file has been created may be sufficient.
These won't be appropriate if you code is part of (say) a Swing or JavaFX app. These have their own ways to perform a long running task and act on its completion. (If you simply wait for the task in in the UI event loop, you will block the event loop.
Android will be different again ...

Related

Multi-threading in Android

I'm new to Android and Java. I'm trying to download 1000 plus images. I don't want to do that serially in a UI thread as that will be slow. Hence, I implemented multi-threading using thread and runnable in the below manner.
The for-loop will be called 1000 plus times. So is it an efficient way of achieving it? Will the OS manage the thread pool by its own?
private void syncS3Data() {
tStart = System.currentTimeMillis();
try {
for (final AWSSyncFile f : awsSyncData.getFiles()) {
new Thread(new Runnable() {
#Override
public void run() {
beginDownload(f);
}
}).start();
}
} catch (Exception ex) {
progressDialog.dismiss();
showMessage("Error:" + ex.getStackTrace().toString());
}
}
for Sure you can't do that in MainThread (UI Thread) because if you did, the application will not be responding.. and then it will be killed by system, you can use AsyncTask class in order to do what do you need but i prefer to use intentservice
However you have to use Intentservice it's a worker thread (long operation) but be noted intentservice will not execute anything until it finish the current task, if you need to download it in parallel then you have to use Service it works with UI Thread so you need asyncTask in order to perform the action but make sure of calling stopSelf() unlike intentService it will be stopped once it finish
Instead of creating threads for each download, create one thread and use that for downloading all images.
You can use AsyncTask Refer: https://developer.android.com/reference/android/os/AsyncTask.html
private class DownloadFilesTask extends AsyncTask<SomeObject, Integer, Long> {
protected Long doInBackground(SomeObject... objs) {
for (final AWSSyncFile f : obj.getFiles()) {
beginDownload(f);
}
}
protected void onPostExecute(Long result) {
//Task Completed
}
new DownloadFilesTask().execute(someObj);
I had developed an e-commerce app before and have encountered a similar problem in which I had to download some 200+ images for each category.The way I did it was using a loop within an AsyncTask and after each download was completed the image was displayed at the relevant place using the onProgessUpdate() function.I can't share the actual code,so i will give a skeleton example.
public class DownloadImages extends AsyncTask<String,String,String>
{
File image;
protected String doInBackground(String... params)
{
//download the image here and lets say its stored in the variable file
//call publishProgress() to run onProgressUpdate()
}
protected void onProgressUpdate(String... values)
{
//use the image in variable file to update the UI
}
}

AsyncTask executes but only sometimes

So i use this code to call my AsyncTask
Log.d("before","make_connection");
new Make_Connection().execute();
Log.d("after","make_connection");
My class
private class Make_Connection extends AsyncTask<Void,Void,String>{
final int port = 4445;
#Override
protected void onPreExecute() {
Toast.makeText(KeyboardActivity.this,"This runs",Toast.LENGTH_LONG).show();
}
#Override
protected String doInBackground(Void... params) {
Log.d("Connection","Started");
Log.e("Connec","this runs");
try {
socket = new Socket(IP,port);
//dout = new DataOutputStream(socket.getOutputStream());
//dout.writeUTF("Connection Formed");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
Toast.makeText(KeyboardActivity.this,"Connection Made",Toast.LENGTH_SHORT).show();
}
}
Now i can see in the android monitor that these two are always execute
Log.d("before","make_connection");
Log.d("after","make_connection");
But half of the time i cannot see the output produced by
Log.d("Connection","Started");
Log.e("Connec","this runs");
Even though onPreExecute() runs properly everytime.
I have tested on two diffent mobilies running 7.1 and 7.0
Can someone please tell me why this is happening
Try:
new Make_Connection().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
instead of only
new Make_Connection().execute();
This is needed, because in Android SDK 13 or higher they run serially by default. So if you want to run more than one AsyncTask simultaneously, use executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
For more details, see explanation under order of execution from This docs
AsyncTasks are run sequentially by default. They all execute on the same executor. Taken from here https://developer.android.com/reference/android/os/AsyncTask.html
If you truly want parallel execution, you can invoke
executeOnExecutor(java.util.concurrent.Executor, Object[]) with
THREAD_POOL_EXECUTOR.

Different way of running a loop on AsyncTask java Android

So I needed a while loop that would auto-refresh the text on the layout and I finally found a way like this (I only put the important part so you get the idea) :
public void restart() {
GetRate asyncRate = new GetRate();
asyncRate.execute();
}
private class GetRate extends AsyncTask<Void, Integer, String> {
#Override
protected String doInBackground(Void... params) {
try {
String p = urlfind();
return p;
}
catch (IOException e) {
return "0";
}
}
#Override
protected void onPostExecute(String p) {
price_text.setText(p);
restart();
}
now my question is, is this a good way of getting this done or could this cause problems ? the app seems to be working fine and I am not getting any errors for the moment, if there is a better or simpler way to do this please give an answer. thanks
Edit : this turned out to be a really bad idea even when I added sleep intervals the app would work for a 15min then crash so I dont advise anyone to use this.
Instead of calling the thread manually, AlarmManager or ScheduledExecutorService could be used to fire the task at certain intervals or at certain time.
AlarmManager is generally used for large intervals and the later one for short intervals.
Using these classes, you can fire your task and get your UI updated.

Cancel AsyncTask after some time

This could be a duplicate question but I did not find what I was looking for.
I am calling an AsyncTask in the UI activity new LoadData().execute(); and in doInBackground I call a method which takes time. I want to interrupt this thread if the data is not return after some time.
Below is the code how I tried to do this.
class LoadData extends AsyncTask<String, String, String>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
startTime = System.currentTimeMillis();
}
protected String doInBackground(String... args)
{
DataCollector dc = new DataCollector();
data = dc.collectData(query);
//Here I check if the time is greater than 30 seconds then cancel
if(((System.currentTimeMillis()-startTime)/1000)>30)
{
cancel(true);
}
return null;
}
}
But this does not stop the task after 30 seconds, in fact it is taking more time.
I have tried get(long timeout, TimeUnit unit); as well but that does not work either.
Can anyone show me how can I do it or how do I use isCancelled() in doInBackground.
Thanks.
You need a thread that cancels your task after a certain amount of time. That Thread could look like this:
public class TaskCanceler implements Runnable{
private AsyncTask task;
public TaskCanceler(AsyncTask task) {
this.task = task;
}
#Override
public void run() {
if (task.getStatus() == AsyncTask.Status.RUNNING )
task.cancel(true);
}
}
And when you call your AsyncTask, you need to run the cancle task after a certain amount of time (=the timeout, in this case 20 sec)
private Handler handler = new Handler();
private TaskCanceler taskCanceler;
...
LoadData task = new LoadData();
taskCanceler = new TaskCanceler(task);
handler.postDelayed(taskCanceler, 20*1000);
task.execute(...)
It's a good idea if you clean this up on cancel or finish with
if(taskCanceler != null && handler != null) {
handler.removeCallbacks(taskCanceler);
}
You can of course wrap this in an custom implementation of AsyncTask. I've used this pattern many times and it works like a charm. One thing to note, in rare cases the handler would not start, I suspect if you create it in the wrong context it will not survive in certain instances, so I forced the handler to be an the UI Thread with handler= new Handler(Looper.getMainLooper());
You have to do the Time check on a different thread.
What you currently do is: executing the dc.collectData(query) (in background) and once it is ready you check if you should cancel. So if the query takes 1 minute, you will do the cancel check after 1 minute, which is already too late.
What you could do is schedule a TimerTask that should run 30 seconds after the LoadData().execute() and if the timer Task is run, you can cancel the AsyncTask (if it is still running)
I would translate this into an async/await problem making all the expensive methods as async methods.
First, Modify DataCollector's collectData(query) to collectDataAsync(query). (If you can't modify DataCollector, there are work arounds to wrap it in a lambda function or something similar).
Second, change doInBackground as an async task, something like this:
protected async Task<String> doInBackgroundAsync(String... args)
{
DataCollector dc = new DataCollector();
int timeout = 1000;
var task = dc.collectDataAsync(query);
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
data = task.Result;
} else {
// timeout logic
}
}
Basically, you have two tasks inside doInBackgroundAsync: collectDataAsync and a delay task.
Your code waits for the faster one. Then you know which one was and you can react accordingly.
If you also need to cancel collectDataAsync task, then you want to used a cancellationToken.
I use this to solve your problem https://stackoverflow.com/a/11191070/3307066.
Note that now doInBackgroundAsync is a async, so it changes a bit the way of using it.
Hope it helps.
Short answer is you CAN'T cancel an AsyncTask once its started. What you can do, is insert a loop inside doInBackGround() which will check for isCancelled() and if it is set to true sometime in the future - return a value from the function (which will in turn call onPostExecute() if you have defined it);
Note that just because you can't stop an AsyncTask doesn't mean that the OS won't cancel it if it's low on memory. You should have this in mind if you are doing essential tasks in the AsyncTask (ones that you want executed 100%). If so, it is better to use a Service - a component that is automatically killed and restarted by the OS as need.
try this :
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
private final ProgressDialog progressDialog;
public MyTask(Context ctx) {
progressDialog = gimmeOne(ctx);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true);
}
});
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
while (running) {
// does the hard work
}
return null;
}
// ...
}
Courtesy and for more details see this answer.

Can't create handler inside thread. How do I use Looper.prepare()? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can’t create handler inside thread that has not called Looper.prepare() inside AsyncTask for ProgressDialog
I'm developing an Android service that try to obtain the device IP address every x time and comunicate it to a server.
I'm using:
Netbeans 7.2Android SDKAndroid Google-Api 8SQLite
I know there are a few questions related to this same issue, but none of them gave me a solution to my problem. As you can see in my code below, I'm not trying to access to the UI of the service main thread (well, I tried, but after I commented the line, the error remains the same). On the other hand, I'm using AsyncTask, which I think is the appropriate way to do it.
This is the main part of my service:
public class ArsosService extends Service {
private NotificationManager mNM;
private final Messenger mMessenger = new Messenger(new IncomingHandler());
protected DatabaseUtil dbu = null;
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
try {
dbu = DatabaseUtility.getInstance(this);
} catch (IOException ex) {
Log.e("Service", ex);
}
Timer timer = new Timer();
timer.schedule(new Checks(), 0, 15000);
}
private class Checks extends TimerTask {
#Override
public void run() {
CheckIpAddress_Task checkIp = new CheckIpAddress_Task();
checkIp.execute();
}
}
// Other methods
private class CheckIpAddress_Task extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... arg0) {
String ipLocal = getLocalIpAddress();
String text = null;
// ipLocal==null means there is no available connection, so we do nothing.
if (ipLocal != null) {
String ipDb = dbu.getLastIP(); // we get the IP saved in the DB.
if (ipDb == null) {
dbu.addProperty("IP", ipLocal); // we save the IP in the DB.
} else if (!ipLocal.equals(ipDb)) {
dbu.setProperty("IP", ipLocal); // we update the IP in the DB.
}
}
if (text != null) {
//showNotification(1, text, ipLocal);
}
return 0;
}
private String getLocalIpAddress() {
String result = null;
// Irrelevant code
return result;
}
}
}
I think the problem may be related to the threads, but I can't see where. Any help will be appreciated.
EDITED: Although I have accepted one of the answers as correct, or maybe because of it, I've been searching for some more information regard to it. I've run into this page I want to share with all of you who someday need to know more about this issue. Its author,Tejas Lagvankar, explains everything about threads, loopers and handler in a very clear and understandable way.
Try this...
- First declare the Handler Object reference variable at class scope.
Handler h;
- Inside the onCreate() method create the instance of the Handler.
h = new Handler();
- Use it with thread like below:
new Thread(new Runnable(){
public void run(){
h.post(new Runnable(){
// Do the UI work here.
});
}
});
- You can very well use the AsyncTask, provided in android, its known as P*ainless threading.*
Handler always runs in the Looper thread context. When you declare a seperate thread, its context is different from the Looper. Hence the error.
Simple solution is always declare Handlers in onCreate(), onStart() and onResume(). If you use AsyncTasks, you can very well declare handlers in onPreExecute() and onPostExecute() as they too run in the Looper context.

Categories

Resources