I am developing an app where I am loading images from gallery. I saw my GUI freezing a little bit and a message saying "Skipped 53 frames. Your app might be doing huge work in its main thread" something like that. Upon a little bit of research I found that it is a common issue and can be resolved using Async task etc. I have defined a method in my main activity and I am calling that method at the very beginning of my activity, that method must be doing a lot of work. I want to call that method in an Async task or on a parallel thread which will run parallel to my main thread and until it is finished I want to display a message box with the text "processing...." on my GUI. How can I achieve this. I am not passing any arguments to the method in my method call nor I am returning anything from that method.
you could use RxJava if you are using Java and Coroutines if you are using Kotlin they are the most optimal solutions at present. But if you still want to use an Async task here is the way.
create an inner class like this,
private class AsyncTaskExample extends AsyncTask<null, null, null> {
#Override
protected void onPreExecute() {
super.onPreExecute();
//show progress bar or any
thing you want to do before starting the process
}
#Override
protected void doInBackground() {
//your code that gets the images from gallery
}
#Override
protected void onPostExecute() {
super.onPostExecute();
// use this callback for if you want to stop showing the progress bar or anything that you want to do after the executing your code in Backgroud
}
}
}
then call this by doing this whenever you want to execute your code,
AsyncTaskExample asyncTask=new AsyncTaskExample();
asyncTask.execute();
Related
I've created a nested class within my Activity
public class MissionsActivity extends Activity {
class UpdateMissions implements Runnable {
#Override
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
[...]
}
[...]
}
In the thread I have to read a file and update some TextFields in the layout. I've tried implementing the run() method with a while(true) that reads and updates the fields, but the app just crashes when I start that Activity.
UPDATE: I've called the execute() method inside the onCreate() method of the UI Activity. The Task is only working the first time I enter the Activity, if i change and go back it won't do anything.
Hey a solution could be trying to use Java's Executor Framework. Put the following code in your Activity.
With executors, you can use a cachedThreadPool() singleThreadExecutor() fixedThreadPoolExecutor(int numOfThreads) etc.
Executors.newSingleThreadExecutor().submit(new Runnable() {
#Override
public void run() {
//Your task here.
}
});
Please note there are numerous Threading Models and techniques in Android, some Android Specific, some based in Android.
AsyncTask
HandlerThread
You can use an AsyncTask. It allows you to load the file and show the progress on ui thread until the load it's finished.
Here you have a good example Download a file with Android, and showing the progress in a ProgressDialog
I would recommend using RxJava or Live Data if you are more advance in developing but also the first solution is fine enough for beginning
https://developer.android.com/topic/libraries/architecture/livedata.html
In my android application, I need to execute some operations, like creating some files in the internal storage and download some data from a server on start of the app. Only when these operations are finished, the rest of the application can work properly. So it’s my intention to show an image and a progress bar when the app is opened, and after all these operations are done, a new activity is opened.
Now, I know it’s common to put potentially long running operations like downloads and file reading/writing into async tasks. However, in my case, I can’t really continue until these operations are finished, so do I need to use Async Tasks, or is it ok for the application to block in this case?
Or should I start an Async Task and then wait for it, using the get() method?
Thanks for advices, I'd really like to do this the right way.
You care create a splash activity which should be your launcher activity.
Then in the splah, start an async task for downloading and all, then after the completion of the task, you can move to your desired activities.
You can also use a thread for this purpose; in that case, you need to handle the task completion callback using a handler or runOnUIThread mechanisms.
Better to use Async task for this.
You need to put it in an async task or different thread. Internet requests on the main ui thread will create a fatal error on the newest (android 4+) systems.
It is always better to show a loading image or progress dialog than showing a hanging white screen.
For all long blocking jobs, async is required.
If you have the splash screen as your main activity, add this code for your async task:
private class YourTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
//Do your work here
//Note that depending on the type of work, you can change the parameters
//of the async task.
return count;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
//Put here the code when your job is done, for example:
//start a new activity (your real main activity).
}
}
After that, in your oncreate method of the activity, call
new YourTask ().execute(url1, url2, url3);
I'm working for an Android app and implementing a ProgressBar by using AsyncTask class.
The problem is that on some devices, it causes "CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views." in onPostExecute. On those devices, the problem occurs 100%. On other devices, it works fine.
public final class MyAsyncTask extends AsyncTask<String, Integer, String>
{
private ProgressBar progress;
private ListActivity activity;
public MyAsyncTask(ListActivity activity, ProgressBar progress)
{
this.progress = progress;
this.activity = activity;
}
protected void onPreExecute()
{
this.progress.setVisibility(view.VISIBLE);
}
protected String doInBackground(String[] arg0)
{
// getting xml via httpClient
return string;
}
protected void onPostExecute(String result)
{
this.progress.setVisibility(view.GONE);
}
I don't understand why onPostExecute does not run on the UI thread, on those certain devices.
Next, I tried to call it with runOnUiThread, to make absolutely sure that it runs on the UI thread.
runOnUiThread(new Runnable() {
#Override
public void run() {
ProgressBar progress = (ProgressBar)findViewById(R.id.some_view_progressbar);
MyAsyncTask task = new MyAsyncTask(activity, progress);
task.execute();
}
} );
Even this did not solve the problem. The same exception still occurs.
From Log, I confirmed that Thread.currentThread().getId() is certainly different from the app's main activity's thread inside the handler.
I'm stuck. Any advice will be appreciated.
NOTE:I edited the sample code (not a real code) above to fix the wrong method name and missing "return string".
I will add more information later.
I don't see anything wrong with MyAsyncTask itself, but there are still other things that can go wrong.
Starting the AsyncTask
From the Android Docs
Threading rules
There are a few threading rules that must be followed for this class
to work properly:
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
You don't show where you normally instantiate, and execute the task, so make sure that you do this in code that's already on the UI/main thread. Note that the first bullet point above might explain why this works for you on some devices, and not on others.
Creating the View Hierarchy
The message tells you
Only the original thread that created a view hierarchy can touch its views.
and you're assuming that this is because your async task is (strangely) trying to modify the UI on a background thread. However, it is possible that you get this error because the async task modifies the UI on the main thread, but the UI (ProgressBar) was not created correctly in the first place.
See this question for an example of how you can erroneously create the view on the wrong thread (anything other than the main thread), and get this same error.
More
I would, however, like to see exactly where you are logging the thread ID, and what value(s) you're getting. If you check out my first two suggestions, and they don't solve your problem, then we may need more information.
You also mention a Handler (?), but don't show how or where you use that. Normally, using AsyncTask removes the need to use Handler, so I'm a little worried about how you might be using that.
Update
Per the discussion in comments below, it looks like the issue here is the one discussed in this question. Some code, probably running on a background thread, is first to cause the AsyncTask class to be loaded. The original (pre-Jelly Bean) implementation of AsyncTask required class loading to occur on the main thread (as mentioned in the Threading Rules above). The simple workaround is to add code on the main thread (e.g. in Application#onCreate()) that forces early, deterministic class loading of AsyncTask:
Class.forName("android.os.AsyncTask");
Make sure you are invoking aysnctask.execute() from the main thread only.
Write a handler in UI thread and call the handler from onPostExecute. It will solve the problem.
Something like this. Have a handler in UI thread (main thread):
handler = new Handler(){
#Override
public void handleMessage(Message msg) {
//run on UI Thread
}
};
and call in onPostExecute() like this:
handler.sendEmptyMessage(MSG);
I'm very new to programming and I have some doubts.
I have a AsyncTask which is I call as RunInBackGround.
and I start this process like:
new RunInBackGround().execute();
But I wish to wait until this call is finish its executing, before proceeding to the other statements of code.
How can I do that?
Are there any way for it?
wait until this call is finish its executing
You will need to call AsyncTask.get() method for getting result back and make wait until doInBackground execution is not complete. but this will freeze Main UI thread if you not call get method inside a Thread.
To get result back in UI Thread start AsyncTask as :
String str_result= new RunInBackGround().execute().get();
Although optimally it would be nice if your code can run parallel, it can be the case you're simply using a thread so you do not block the UI thread, even if your app's usage flow will have to wait for it.
You've got pretty much 2 options here;
You can execute the code you want waiting, in the AsyncTask itself. If it has to do with updating the UI(thread), you can use the onPostExecute method. This gets called automatically when your background work is done.
If you for some reason are forced to do it in the Activity/Fragment/Whatever, you can also just make yourself a custom listener, which you broadcast from your AsyncTask. By using this, you can have a callback method in your Activity/Fragment/Whatever which only gets called when you want it: aka when your AsyncTask is done with whatever you had to wait for.
In your AsyncTask add one ProgressDialog like:
private final ProgressDialog dialog = new ProgressDialog(YourActivity.this);
you can setMessage in onPreExecute() method like:
this.dialog.setMessage("Processing...");
this.dialog.show();
and in your onPostExecute(Void result) method dismiss your ProgressDialog.
AsyncTask have four methods..
onPreExecute -- for doing something before calling background task in Async
doInBackground -- operation/Task to do in Background
onProgressUpdate -- it is for progress Update
onPostExecute -- this method calls after asyncTask return from doInBackground.
you can call your work on onPostExecute() it calls after returning from doInBackground()
onPostExecute is what you need to Implement.
I think the easiest way is to create an interface to get the data from onpostexecute and run the Ui from interface :
Create an Interface :
public interface AsyncResponse {
void processFinish(String output);
}
Then in asynctask
#Override
protected void onPostExecute(String data) {
delegate.processFinish(data);
}
Then in yout main activity
#Override
public void processFinish(String data) {
// do things
}
Error
05-12 11:56:45.793: ERROR/AndroidRuntime(505): Caused by: android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
what i have done
i have a list view inside my activity and i need to populate the listview by doing the following:
mylistview.setAdapter(new CustomAdapter());
now there is already too much pressure on my UI thread so , thought of calling this method inside a AsynTask.
Another problem
there is a progress dialog that shows in my acitivity when the user clicks the button to populate the listview. when i put everything inside one thread the progress dialog does not show. i had asked a question on stackoverflow about why the progress dialog does not show and i had got a reply saying that i need to put all the extra tasks inside another thread.
i have also read the updating UI in android given on android developer website:
but over there all we do is make a new runnable and post the runnable to the Handler of the UI thread so that when the UI is free, the runnable will be executed.
But how does the above solve my purpose? i mean the UI thread is still executing the instructions.
The only way i can take the load of the UI thread is if i make another thread and put all the work over there... but android does not allow this?
what is wrong with my understanding(if there is anything wrong)? How do i solve this problem
thank you in advance.
Android does allow you to put the extra work in a different thread AND publish the results on the UI thread, using AsyncTask. Add the UI update stage in the onPostExecute() method of the AsyncTask and you should be good-to-go. onPostExecute() is performed on the UI thread, the example in the AsyncTask Documentation is a great one.
Also, if you build your application properly, and don't use graphics a lot, there should not be too much work for the UI thread during the application run. Move everything that doesn't absolutely bound to the UI on a separate thread. AsyncTask is a very convenient way to do it.
AsyncTask is the correct way to solve your problem. Where you are running into difficulty is exactly what to put into the AsyncTask. Call mylistview.setAdapter(); from the onProgressUpdate or onPostExecute methods. So do something like this:
void setProgress(Integer progress){ myprogressbar.setValue(progress); }
void setAdapter(CustomAdapter result){ mylistview.setAdapter(result); }
private class LongRunningTask extends AsyncTask<String, Integer, CustomAdapter> {
protected Long doInBackground(String... urls) {
CustomAdapter res = null;
// do all the work to BUILD the custom adapter, calling publishProgress() as progress gets made
publishProgress(<progress value>);
return res;
}
protected void onProgressUpdate(Integer... progress) {
setProgress(progress);
}
protected void onPostExecute(CustomAdapter result) {
setAdapter(result);
}
}
That should fix the threading issue and let you set the progress bar.