Different way of running a loop on AsyncTask java Android - java

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.

Related

Need to wait for file to be available

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 ...

The work manader's work is not controlled

I have a wok manager that I run from the Main Activity when the user logs into the application. So, I will tell you in more detail what I do in the manager: in it I start a stream in which every second there is a mining of the virtual currency of my application, that is, simply put, I just increase the variable every second.
Moving on to the problem, here's how I run the manager
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
miningWorkRequest = new
OneTimeWorkRequest.Builder(MiningManager.class)
.setConstraints(constraints)
.build();
WorkManager.getInstance(getApplicationContext()).enqueue(miningWorkRequest);
Launching the manager completely as in the documentation.
And now the manager himself is with my mining stream. Before increasing the variable, I get it every second from Firebase Realtime, and then the miningMoneyFun() method is triggered to increase it.
#NonNull
#Override
public Result doWork() {
firebaseModel.initAll();
RecentMethods.UserNickByUid(firebaseModel.getUser().getUid(), firebaseModel, new Callbacks.GetUserNickByUid() {
#Override
public void PassUserNick(String nick) {
RecentMethods.GetActiveMiner(nick, firebaseModel, new Callbacks.GetActiveMiners() {
#Override
public void GetActiveMiners(ArrayList<Miner> activeMinersFromBase) {
if(activeMinersFromBase.size()>0){
Thread thread = new Thread()
{
#Override
public void run() {
try {
RecentMethods.UserNickByUid(firebaseModel.getUser().getUid(), firebaseModel, new Callbacks.GetUserNickByUid() {
#Override
public void PassUserNick(String nick) {
RecentMethods.GetTodayMining(nick, firebaseModel, new Callbacks.GetTodayMining() {
#Override
public void GetTodayMining(double todayMiningFromBase) {
todayMining=todayMiningFromBase;
}
});
}
});
while(true) {
Thread.sleep(1000);
miningMoneyFun();
Log.d("#####", "go "+ todayMining);
}
} catch (InterruptedException e) {
}
}
};
thread.start();
}
}
});
}
});
return Result.success();
What specifically does not suit me, I see from the log that the thread can be executed 5, 10 or even 15 times per second. I thought it was a thread, but when I commented it out and put the log in the DoWork() method, the log also appeared many times per second. I want the DoWork() method to run once, and then the thread itself functions every second and as expected. I saw 2 similar questions on StackOverflow, but none had clear answers, please help and sorry for the English
Are you sure that it is only one worker?
Please check like this the number of active works:
https://developer.android.com/studio/inspect/task#view-workers
Also, you should be using unique work to be sure that there are no multiple workers:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/managing-work#unique-work
EDITED:
I am more confused by your comment. Please provide screenshots and the code the enqueue the work. At the moment you don't use periodic and unique.
Please note that you can have only 1 work in the inspector, but you can see a big list of all the executions of it.
Also, are you sure about the id? Do you generate it or it is static. It should not be possible to have multiple works when it is unique.
What flag do you use? KEEP?
Also now I saw your code in the Worker. I don't see how you block the doWork() to finish. I think you return Success, but at the same time, you have another Thread running with nothing to prevent the app to be killed.

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
}
}

Local fields from outer class unaffected by Runnable code

This has been killing me lately. I'm making a quick settings tile that should show as active or inactive based on whether it can communicate with a specific machine over a socket. Here are my declarations:
public class WakeUpTileService extends TileService {
private static volatile boolean online;
private final TimerTask timerTask;
private Timer timer;
Here's the constructor:
public WakeUpTileService() {
super();
online = true;
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
boolean shouldBeOn = false;
try {
Socket s = new Socket();
// 3000 is the timeout in milliseconds.
s.connect(myInetSocketAddress, 3000);
// Connection was successfully established.
s.close();
shouldBeOn = true;
} catch (Exception e) {
// Connection failed.
// shouldBeOn is already false.
} finally {
if (shouldBeOn != WakeUpTileService.online) {
WakeUpTileService.online = shouldBeOn;
// This method causes onStartListening() to be called
// on the main thread so I can update the Tile.
requestListeningState(
getApplicationContext(),
new ComponentName(
getApplicationContext(),
WakeUpTileService.class
)
);
}
}
}
};
}
Here's where the timer gets started:
#Override
public void onTileAdded() {
super.onTileAdded();
timer.scheduleAtFixedRate(timerTask, 0, 60000);
// At the moment I have it checking once per minute
// For debugging purposes. I plan to make it less frequent.
}
And here's the code that uses the value of online to update the Tile. This gets called on the main thread after WakeUpTileService.online = shouldBeOn; in the TimerTask.
#Override
public void onStartListening() {
Tile t = getQsTile();
if(WakeUpTileService.online)
t.setState(Tile.STATE_ACTIVE);
else
t.setState(Tile.STATE_INACTIVE);
t.updateTile();
}
When I step through the code in the debugger, the TimerTask code is definitely finished before onStartListening gets called, and within the context of the TimerTask, online holds the correct value. Then, when onStartListening is called, online seems to revert to the value it had at the beginning.
Thoughts I've had about what might be going on:
The online being referenced in WakeUpTileService is somehow not the same object as is being referenced in the Runnable code (that's why I made online static and used WakeUpTileService.online instead of just online.)
The assignment to online is actually not happening before online is read by onStartListening(). Again, when I stepped through the code with the debugger, this doesn't appear to be happening, and just by looking at the code below, this doesn't seem reasonable.
I don't know what else could be happening here. Please help!
Update: korolar suggested that the two classes might have been loaded by different classloaders, and after some investigation, I found that that is the cause. My service is being loaded by dalvik.system.PathClassLoader and java.util.Timer is being loaded by java.lang.BootClassLoader. I don't, however, know how to work around or solve this issue. Can anyone provide some suggestions?
In case anyone else runs into this problem, I'll let you know what I eventually did to fix it.
Apparently using the java.util.Timer class at all is generally bad practice in Android programming. Instead, I rewrote my program using the Android AlarmManager class and IntentService. That completely bypasses the classloader problem.

Java defining objects on the fly

So I have a somewhat general question regarding something I came across recently. Let's say have I have 2 classes, Activity and Task. In Activity, a new Task object is instantiated, but instead of being given its usual parameters, some new code is introduced in brackets afterward, and one of its methods is called on that instantiation. I've seen methods being called on an object as soon as it is created, but not re-defining its behavior also. This is all Android based, so maybe it's related to that, but something this syntactically weird seems more like a Java concept than something that Android introduced. Here's the class file:
class Task extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... args) {
try {
//do things here
} catch (Exception ex) {
ex.printStackTrace();
Log.e("Exception", ex.toString());
}
return Text;
}
}
which is the object to be created, and then the code which instantiates it is here:
new Task() {
#Override
public void onPostExecute(String result) {
Log.d("JSON", result);
try {
if (jObject.has("error")) {
//Do something here
}
else if (!paymentCheck(appDomain)){
//do something else
}
else {
//Do last thing
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}.execute(appDomain, email, password);
I understand that AsyncTask is a quirky class in that it passes the result from its doInBackground method to the onPostExecute one in a separate thread, and maybe that's why this is done, but I dont really understand why you wouldn't just define onPostExecute in Tasks own class file, like I've seen with other examples. Also, this thing compiles and runs perfectly fine, doing everything it's supposed to to. I just don't really understand the reasoning behind. Hopefully someone here can help! Thanks
This is a Java syntactic sugar called an anonymous class.
I'm not an Android developer so I'm not entirely familiar with any peculiarities there, but this pattern is used whenever you need to ensure that the response action occurs in a separate thread to avoid deadlocks and the like or when the onPostExecute manipulates objects that are not visible in Task. This can act as a sort of closure over any final objects that are in scope.

Categories

Resources