Bitmap operations in background thread makes UI unresponsive - android

I am running following operations in the background thread:
Store byte image data locally as a jpeg.
Fetch that image as a bitmap.
Run face-detection algorithm and fetch facial points
Place an overlay according to those points
And finally save that bitmap again.
While performing these operations, I am displaying a progress bar. But the progress bar animation gets stuck i.e it becomes unresponsive until the thread completes its work(update: nothing in the whole UI seems to function while the background work is running).
Doesn't this make actual intentions of using background thread obsolete?
What approach should I take to overcome this problem?
My code is:
//Show ProgressBar
Runnable worker = () -> {
//My Operations
runOnUiThread(() -> {
//Hide ProgressBar
});
}

You can use the async approach, it will work
private class MyAsyncTask extends AsyncTask<String, Progress, Bitmap> {
protected void onPreExecute() {
// Runs on the UI thread before doInBackground
progressBar.setVisibility(ProgressBar.VISIBLE);
}
protected Bitmap doInBackground(String... strings) {
// Some long-running task like downloading an image.
// convert your bitmap
return someBitmap;
}
protected void onProgressUpdate(Progress... values) {
//update progress
}
protected void onPostExecute(Bitmap result) {
//hide progress bar
}}

Related

Android additional threads and Looper

I am writing a Android application which reads data from a SQLite Database and then displays the data on a next screen. Whenever I was doing a query on the database I would get an error message that too much work is being done on the main thread.
I then put my query in a new Thread:
(new Thread()
{
public void run()
{
Looper.prepare();
try
{
FPJobCardWizard data = dbHelperInstance.loadFPJobCardWizardFull(fitmentHash);
wState.fitmentItemSet(data.fitmentItemGet());
} catch (Exception e) {e.printStackTrace();}
Looper.loop();
}
}).start();
Now the gui/main thread is completing it's operation prior to the Query being complete and as a result the data variable is still empty. I read a few posts and the API documentation and it seems that I need to use a Looper (this seems to be the correct fix) but I have never used a Looper and cannot seem to get it to work.
Please can you check the code above and guide me in the right direction.
Thank you all in advance.
the best choice here will be using an AsyncTask, as it will enables you to perform all the background work in a background thread, then when the result is generated it will apply it using the UI thread:
So, as explained in the life cycle of AsyncTask, you can do all of your background work in the method doInBackground() and then do all of your UI work on the method onPostExecute() which will be executed after taking the result from doInBackground() method according to the life cycle, and to put your hands more on the AsyncTask, have a look at this example which provides the following example code:
public class AsyncTaskTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// This starts the AsyncTask
// Doesn't need to be in onCreate()
new MyTask().execute("my string paramater");
}
// Here is the AsyncTask class:
//
// AsyncTask<Params, Progress, Result>.
// Params – the type (Object/primitive) you pass to the AsyncTask from .execute()
// Progress – the type that gets passed to onProgressUpdate()
// Result – the type returns from doInBackground()
// Any of them can be String, Integer, Void, etc.
private class MyTask extends AsyncTask<String, Integer, String> {
// Runs in UI before background thread is called
#Override
protected void onPreExecute() {
super.onPreExecute();
// Do something like display a progress bar
}
// This is run in a background thread
#Override
protected String doInBackground(String... params) {
// get the string from params, which is an array
String myString = params[0];
// Do something that takes a long time, for example:
for (int i = 0; i <= 100; i++) {
// Do things
// Call this to update your progress
publishProgress(i);
}
return "this string is passed to onPostExecute";
}
// This is called from background thread but runs in UI
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Do things like update the progress bar
}
// This runs in UI when background thread finishes
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Do things like hide the progress bar or change a TextView
}
}
}

How to create a progressDialog onload of imageView?

I would like to load a large/complex svg image file into my imageView. Loading the svg takes time to load on my HTC Desire S and Lenovo a60. About 5 Second and 10 seconds respectively.
Right now my app becomes unresponsive for about 5 seconds until the imageView is fully loaded
I load the image using this simple code..
svg = SVGParser.getSVGFromResource(getResources(), R.raw.gf);
mImageView.setImageDrawable(svg.createPictureDrawable());
I was looking something like (webView)
webView.setWebViewClient(new WebViewClientEx(MainActivity.this, DEBUG) {
#Override
public void onPageFinished(final WebView view, String url) {
...........
.............}
});
which I used in my previous project...
Finally my questions:
1.) What is the best approach to make the app look responsive?
I was planning to use asynctask but don't know how to use it... Is it applicable here?
2.) Is there listener after the image is fully loaded?
My approach here is to show the progressDialog by the time I load the imageView and hide it after the imageView has fully loaded.
another other suggestions which you think is better to use for showing/hiding progressDialog ? Thanks!
Use an async task here. (a Loader would work aswell but async task is a bit easier to explain.)
private class LoadSVGTask extends AsyncTask<Integer, Void, Drawable> {
protected Drawable doInBackground(Integer... res) {
mProgressBar.setVisibility(View.Visible);
svg = SVGParser.getSVGFromResource(getResources(),res);
Drawable d = svg.createPictureDrawable();
return d;
}
// gets executed in main thread
protected void onPostExecute(Drawable result) {
mProgressBar.setVisibility(View.Gone);
mImageView.setImageDrawable(result);
}
}
Launch the Task with:
new LoaderSVGTask().execute(R.raw.gf, null, null);
see: http://developer.android.com/reference/android/os/AsyncTask.html
Just refer AsyncTask in that
protected void onPreExecute (){
progressDialog.show(......);
}
protected abstract Result doInBackground (Params... params){
//load your image from here
}
protected void onPostExecute (Result result){
progressDialog.dismiss();
}

use of asynctask inside asynctask

I wanted to use AsyncTask to load images to the ListView.
private class LoadImageTask extends AsyncTask<HashMap<String,Bitmap>,Void,Bitmap>{
#SuppressWarnings("unchecked")
#Override
protected void onPostExecute(Bitmap result) {
if(model.getIconCache().get(cellIcon)!=null){
icon.setImageBitmap(model.getIconCache().get(cellIcon));
}else{
new LoadImageTask().execute(model.getIconCache());
}
}
#Override
protected Bitmap doInBackground(HashMap<String, Bitmap>... params) {
//return model.getIconCache().get(cellIcon);
return null;
}
}
Ok, I know that this not an affective code. However it works well but with a lot of memory allocation. When reading the documentation about AsyncTask it said that Asynctask can be called only from UI thread, how could it let to use inside itself? And of course I want to make my code work inside a single AsyncTask. "model" in the code is an object that is updated at runtime through another thread. So I need to find a way to use a single Asynctask with periodically control the state of an object. How do I do that? Thanks
only do in backGround runs on backGround thread and postExecute and preExecute run on UI thread itself.. For the same reason u can show and dismiss dialogs in it..
if u want to use single Asynctask for multiple purpose u can play around by passing Different constants.. in .execute() method..
I mean something like this.
Integer Constant1 = 1;
int Constant2 = 2;
and while calling,,
new Background.execute(Constan1 or 2)
and in AsyncTask
doInBackground(Object.. arg0)
{
if(arg0.equals())
{
}
else if(arg0.equals())
{
}
}
Take a look at the asynctask documentation: http://developer.android.com/reference/android/os/AsyncTask.html
private class MyTask extends AsyncTask<Void, Integer, Boolean> {
protected Boolean doInBackground(Void...) {
int i = 0;
while(true){
publishProgress(i++);
}
}
protected void onProgressUpdate(Integer... progress) {
myObject.setState(progress[0]);
}
}
You do your background stuff in the doInBackground method (which runs in the background thread).
You control the state of your object in the onProgressUpdate (which runs on the ui thread)
You send messages between the background thread and the ui thread using publishProgress. These messages could contain the state of your object.

Android: display image during async background streaming task

I am trying to retrieve JPGs from an MJPG Stream using an async task. I first thought, i could let the task continuously be running and just letting the buffered JPGs pop up in the onProgressUpdate() method. But this doesn't seem to work, because the method only displays integers, no drawables...what I tried:
private class StreamTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
image = readMJPGStream();
return null;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
imView.setImageDrawable(image); // << doesn't work
}
}
Do you have any ideas? What approach should I try?
Thank you very much in advance!
Huck
When you start a AsyncTask, the doInBackground is called, but it is only run once. I'm not sure what readMJPGStream does, but assuming it blocks until an image is retrieved, its certainly possible that onProgressUpdate gets called several times while your image is still null, then once image get set to something valid and doInbackground quickly exits, there are no further calls to OnProgressUpdate.
You should probably put the call to imView.setImageDrawable in onPostExecute to make sure it gets called when the image has been downloaded. You may also need to call invalidate() on your image view to ensure it gets redrawn. Additionally, if you intend to loop and continue downloading images, you'll need to devise a mechanism of triggering updates. In reality, the issue you're having is because you want 'on demand' get on the UI Thread, but you're dependent on calls to onProgressUpdate. You'd have much better luck using a Handler and your own Runnable/Thread because then when an image download completes, you can post to the UI thread (using the Handler) without having to wait for the onProgressUpdate.
I now got it running this way:
public class StreamActivity extends Activity implements Runnable{
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imView = (ImageView) findViewById(R.id.imView);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void run() {
while (connected){
image = readMJPGStream();
handler.sendEmptyMessage(0);
}
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
imView.setImageDrawable(image);
}
};
public Drawable readMJPGStream() {
//...
return image;
}
}
The only problem is that my while loop is not fast enough. Any ideas are very much appreciated!
Huck

How to add tabbar in doinbackground asynctask in android

How to add tabbar in doinbackground asynctask in android? or how to run splash screen in thread? I want to show a progress dialog or splash screen until tab bar is loaded from calling tabbar class I am calling webservices and parsing the value takes time, for few mins mean time, I have to show progessbar or splash screen. Can anybody tell me how to implement this? Can anybody give sample code?
I tried but its not working
dlg = ProgressDialog.show(this, "Working..", "Downloading Data...", true, false);
Thread splashThread = new Thread() {
#Override
public void run() {
try {
sleep(100000);
} catch (InterruptedException e) {
// do nothing
} finally {
}
}
};
splashThread.start();
you cannot touch anything of the main ui thread from a background thread, in order to do that you have to use a handler who manages the synchronization between background thread and ui main thread.
the better way is subclassing the AsyncTask, doing this, you already have methods who works on background and methods who work on the ui. With this, you can perform the background operation and inmediatly shows the result...
public class AsynchronousTask extends AsyncTask<Runnable, String, Result> {
//method executed automatically in the ui event before the background thread execution
#Override
protected void onPreExecute() {
//show the splash screen and add a progress bar indeterminate
}
//method executed automatically in the ui event AFTER the background thread execution
#Override
protected void onPostExecute(Result result) {
//hide the splash screen and drop the progress bar or set its visibility to gone.
}
//method executed in a background event when you call explicitly execute...
#Override
protected Result doInBackground(Runnable... tasks) {
Result result;
if(tasks != null && tasks.length > 0){
for (Runnable runnable : tasks) {
//publishProgress( ... );
runnable.run();
//result = ...
//publishProgress( ...);
}
}
return result;
}
}
http://developer.android.com/reference/android/os/AsyncTask.html
read more here
hope this helps...

Categories

Resources