Changing image consumes lot of time - android

Is there any way that I can increase the speed of setting the image? What I am trying to say is suppose I have some hundreds of images and each of those images can be changed automatically or by pressing forward/rewind buttons. (Think of the media player situation where you can forward or rewind as many files, same I am doing with images and some audio behind).
Now, if I continuously keep pressing RW/FW buttons, the layout appears to be black for some time or asks for force close or wait of the application.
Any one know how to increase this speed of reading the bitmap and setting it to the imageview?
Here is a part of my code,
private void playAudio() {
msg = new Message();
msg.obj = (filepath);
imageHandler.sendMessage(msg);
}
private Handler imageHandler = new Handler() {
public void handleMessage(Message msg) {
try {
path = (String) msg.obj;
imagePath = RaconTours.PATH + path;
imagenamearray = imagePath.split("/");
currentImagename = imagenamearray[8];
i++;
if (!imagePath.equalsIgnoreCase(staticpath)) {
isSeekBarChangedManually = false;
staticpath = imagePath;
Bitmap snoop = readBitmap(Uri.fromFile(new File(filepath)));
image.setImageBitmap(snoop);
image.setMaxZoom(4f);
} catch (Exception e) {
e.printStackTrace();
}
}
};
Hope you get some idea with this code, this is just a small piece of the big cake.
I am not getting the method to solve this. I tried disabling the button also until some action is being performed but that is also of no use.
Any help, cheers

I think the only way to make this process "faster" is to load and cache the bitmaps in a buffer before you actually need them. When you need a bitmap, you check this forward-cache to see if it's already loaded. If it is, then it means it's already in memory -> you just need to set it for the proper ImageView (or whatever you use). If not, then you load it from the disk.
Of course, you need to know that which bitmaps you'll need most likely in the near future for this to work.
You can't really make disk I/O work any faster you see.

Related

Android piccaso callback return before load

i have an android mobile app and im trying to check if a specific LatLng is at water, so im using google static map api to get an image of the location, and then to check if the image is blue.
im using this code -
private boolean result;
public boolean IsWater(LatLng position)
{
imageView = (ImageView) this.findViewById(R.id.imageView);
checkText= (TextView) this.findViewById(R.id.checkText);
String lati = Double.toString(position.latitude);
String longi = Double.toString(position.longitude);
String url = "http://maps.googleapis.com/maps/api/staticmap?center="+lati+"," + longi + "&zoom=20&size=1x1&style=element:labels%7Cvisibility:off&style=element:geometry.stroke%7Cvisibility:off";
Picasso.with(MainActivity.this).load(url)
.into(imageView, new com.squareup.picasso.Callback() {
#Override
public void onSuccess() {
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(0, 0);
int blueValue = Color.blue(pixel);
if(blueValue>250)
result =true;
}
#Override
public void onError() {
result =false;
}
});
return result;
}
the problem, i think, is that it is not synchronized, and IsWater get to the last line and return a null for result before the onSuccess kicks in...
any thoughts?
Picasso loads images on a background thread by default. The operation you are running is asynchronous. Therefore, it does not block your method from returning result before the onSuccess callback has been called.
The problem is Picasso is running Async. within the calling method "isWater", so what ends up happening is the method will return 'false' because instead of waiting on Picasso to finish because it isn't in serial execution. This is due to the function call's stack frame being popped off the stack once it reaches the return statement.
What you need to do is the following by using a Target.
// make sure to set Target as strong reference
private Target loadtarget;
public void loadBitmap(String url) {
if (loadtarget == null){
loadtarget = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// do something with the Bitmap
handleLoadedBitmap(bitmap);
}
#Override
public void onBitmapFailed() {
}
};
}
Picasso.with(this).load(url).into(loadtarget);
}
public void handleLoadedBitmap(Bitmap b) {
// do something here
}
This code was taken from here, and should offer you some insight on how to get it work for your goal.
A Target is essentially an object that holds the bitmap you need so it is still in memory. Generally used for custom view objects though as a field. Here is documentation Target docs
Asynchronous execution is one of the hardest things to wrap ones head (and subsequently ones code) around. In all of the JavaScript frameworks I've used, the network communication is done in a background thread. The intended effect is that the User Interface thread is left free to keep the user from thinking that things locked up. Mouse-overs and tool-tips will all still work, while a background thread is dragging data out of a slow server.
The code patterns, on the other hand, aren't as nicely shaped.
My problem is/was still basically thinking linearly, or functionally, instead of embracing the event-driven nature of modern JavaScript: Passing a function to an asynchronous method to completely handle that response. Not just return a value, but perform the full task that the value was needed for. The callback can call the other functions to assist with that task, and may be able to fill in a cache (of whatever sort) so that other functions that may need this data do not necessarily have to wait for another response. This often (to me) feels backwards from the logic pattern I was following to solve the original purpose of the code.
I've stumbled on this pattern-flip many times, coming from C/C++ as my first programming language. It can sometimes help to avoid the anonymous function pattern of callback definition and define one's callback functions with names, then pass the name to the asynchronous call, but that is extra steps and extra memory use in the long run. The big hurdle is thinking in terms of Event and EventHandler, versus function and data.
I hope this helps a little.

Android: Asynch Thread Needed?

I am creating an app that involves reading data from text files that are in the Assets folder. For each file, it stores the data in a separate ArrayList. The files are read in one after another in the onCreate() method of the activity. All of the text files combined total 1.8 MB and on the emulator it currently takes 12 seconds for the activity to load. The app does not crash on the emulator (it just takes approx 12 seconds).
I have read about asynchronous threads, but I have never had a need for them in the past. I was planning on having some sort of message or progress bar to notify the user that the activity is in fact loading and has not crashed.
So my question is: even though the app does not crash when loading the activity, should I still put the reading of the files on an asynchronous or different thread? If so, how would I go about doing it properly? (I have never done it before.)
Here is sample code with the reading of the text files:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
populateArrayLists();
}
public void populateArrayLists() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(getAssets().open(
"text1.txt")));
String text;
while ((word = br.readLine()) != null) {
ArrayList1.add(text);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close(); // stop reading
} catch (IOException ex) {
ex.printStackTrace();
}
}
br = null;
try {
br = new BufferedReader(new InputStreamReader(getAssets().open(
"text2.txt")));
// the same process is duplicated for 1-15
// it may not be the best or most efficient way but it works
Any help would be appreciated.
Yes, you'll need a background thread for this. The Loader api may be your easiest bet.
This will allow you at least display a notice and offer some content while the files load. Maybe even load them and incrementally displaying the data, if that's what you're doing.
Edit: Loaders are a 3.0 feature available in the compatibility library. If you're not willing to add the dependency, you can always fall back to AsyncTask, in which case you could take a look at this.

Android AsyncTask strangely publishing duplicates

I think this is not an easy question.
I'll be brief and give a little example of what is happening.
Let's say we have a source of data in file Byron.txt:
SHE walks in beauty, like the night
Of cloudless climes and starry skies;
And all that 's best of dark and bright
Meet in her aspect and her eyes:
Thus mellow'd to that tender light
Which heaven to gaudy day denies.
And this code execute inside an AsyncTask:
final ArrayList<Record> poem = new ArrayList<Record>();
final Object objectLock = new Object();
private Record rec = new Record();
#Override
protected Void doInBackground(Void... args) {
String line = null;
int i;
int last;
try {
process = Runtime.getRuntime().exec("cat Byron.txt");
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()), 8192);
synchronized (objectLock) {
poem.clear();
last = i = poem.size() - 1;
}
while(line = bufferedReader.readLine()) != null) {
rec.setString(line);
synchronized (objectLock) {
last++;
poem.add(last, rec);
}
while(!bPause && i < last) {
i++;
publishProgress(poem.get(i));
}
}
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected synchronized void onProgressUpdate(Record... m) {
if(m.length > 0) {
mContext.mTable.appendRow(m[0]);
}
}
where there is a TableLayout in the UI and each time we get a new line we add a new TableRow to it.
And this is the output we see in the UI:
SHE walks in beauty, like the night
Of cloudless climes and starry skies;
Of cloudless climes and starry skies;
Of cloudless climes and starry skies;
Thus mellow'd to that tender light
Thus mellow'd to that tender light
And we go into the debugger and we see why it happens.
Sometimes the synchronized (objectLock) is skipped and the loop continues.
There is no publishing because i already catched last.
Later the block is executed as many times as it was skipped,
, but the original line is lost and the current line is added instead to poem several times
Then, all the new lines are published until i catches last again.
So you see that I followed the code and I can explain what's happening, the question here is: Why the block is skipped?, Why?
I expected the synchronized block to stall until it can be executed.
At least this how I understood the function of synchronized (objectLock)
even without using wait() and notify()
I don't pretend to open a discussion here (although if you want we can open one in the chat area)
If you see some fault in the code, then, answer the question to let me know.
NOTES:
synchronized is needed because somewhere else in the app, the user may want to email the lines he got so far.
The user may pause the publishing (bpause); that's the while loop and i follows last only when bPause is false.
I decided to publish the answer. Even though I feel very embarrassed by its simplicity.
I discovered it only after I had already dug deep into AsyncTask class and message handling and whatnot.
I publish it in hope it will help people to check the basic things before jumping to
conclusions, and that someone out there will save himself half a day debugging because of
this post.
The Record rec was the same one each time. The poem ArrayList had the same element id for each entry. And the content changed on all of them at once, since they were all the same.
When the progress was published immediately it printed the right string, the last one. But if some delay cause the progress to publish later, then retrieving the poem.get(i) records retrieved a different entry but with the same pointer, thus, the same content.
The solution was to create a new Record each loop.
Do the synchronization for last object.
synchronized (last) {
last++;
poem.add(last, line);
}

How to load images from server properly?

I have a code below, this code works perfectly fine when you are trying to load one or two images. However, the problem is, when you have a lot of images in one Activity, all images must load first before you can get in. My question is, what is the best way to handle this images? I want the images to load one by one and not simultaneously. I want it to load just like the ListView made by Fedor "http://stackoverflow.com/questions/541966/android-how-do-i-do-a-lazy-load-of-images-in-listview" (Note: I'm not using a ListView, I just want my images to load like that). Please help me, I would really appreciate it a lot. Thanks in advance!
class ImageDownlaodThread extends Thread {
ImageDownloadMessageHandler imageDownloadMessageHandler;
String imageUrl;
#Override
public void run() {
Drawable drawable = LoadImageFromWebOperations(imageUrl);
Message message = imageDownloadMessageHandler.obtainMessage(1, drawable);
System.out.println("Message sent");
}
}
class ImageDownloadMessageHandler extends Handler {
View imageTextView;
}
#Override
public void handleMessage(Message message) {
progressBar.setVisibility(View.GONE);
imageTextView.setVisibility(View.VISIBLE);
}
}
Drawable LoadImageFromWebOperations(String url) {
Drawable d = null;
InputStream is = null;
try {
} catch (IOException e) {
e.printStackTrace();
}
return d;
}
Would this tutorial help [TUT] ImageView with Loading Spinner:
http://www.anddev.org/novice-tutorials-f8/imageview-with-loading-spinner-t49439.html
It basically show's a spinner until the image has loaded from the remote site :-)
You could strip the code to show a blank space / whatever you want till it loads.
If you don't want anything to happen till it all loads, you could have a count of how many images there are and then increment this each time an image has loaded.
IMO, AsyncTask is the easiest way to do this; in fact, it was basically built for this sort of task.
There's really too much to discuss in a StackOverflow answer. Just see Painless Threading to get started.

Does Android AsyncTaskQueue or similar exist?

I read somewhere (and have observed) that starting threads is slow. I always assumed that AsyncTask created and reused a single thread because it required being started inside the UI thread.
The following (anonymized) code is called from a ListAdapter's getView method to load images asynchronously. It works well until the user moves the list quickly, and then it becomes "janky".
final File imageFile = new File(getCacheDir().getPath() + "/img/" + p.image);
image.setVisibility(View.GONE);
view.findViewById(R.id.imageLoading).setVisibility(View.VISIBLE);
(new AsyncTask<Void, Void, Bitmap>() {
#Override
protected Bitmap doInBackground(Void... params) {
try {
Bitmap image;
if (!imageFile.exists() || imageFile.length() == 0) {
image = BitmapFactory.decodeStream(new URL(
"http://example.com/images/"
+ p.image).openStream());
image.compress(Bitmap.CompressFormat.JPEG, 85,
new FileOutputStream(imageFile));
image.recycle();
}
image = BitmapFactory.decodeFile(imageFile.getPath(),
bitmapOptions);
return image;
} catch (MalformedURLException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
return null;
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(Bitmap image) {
if (view.getTag() != p) // The view was recycled.
return;
view.findViewById(R.id.imageLoading).setVisibility(
View.GONE);
view.findViewById(R.id.image)
.setVisibility(View.VISIBLE);
((ImageView) view.findViewById(R.id.image))
.setImageBitmap(image);
}
}).execute();
I'm thinking that a queue-based method would work better, but I'm wondering if there is one or if I should attempt to create my own implementation.
The key is explained in the example List13.java
Basically you have to track the scroll state of your listView and notify
the adapter when it is ready to do something of slow with the just visibile
items.
Also note that saving images to the disk is a very slow process. Using a
memory-based cache stategy would improve a lot your perfomance's
application.
I can see you decode image and compress it back to disk, after that you decode it again. Not very effective I think. You could just save the stream from network to disk, after that decompress it. That would be just one decompress instead of 3 compress/decompress. Will save you a lot of CPU processing time.
I think AsyncTask creates several threads for several images. So several images are being compressed/decompressed at the same time, several threads fight for CPU time, not very good. As far as I know AsyncTask uses thread pool, so it doesn't start new thread for each image. But anyway several threads at the same time is not so good. I agree a queue would be much more effective. The implementation is not so hard to create it yourself. I use my own queue implementation and I'm quite happy with it.
If you have your own thread I think it would be possible to give it a lower priority. That will make the UI more responsive.
You certainly need some kind of in-memory cache, otherwise UI can't be fast enough. Decompress is slow. You can store not all images but only most used ones. You may use SoftReference for cache implementation. You may use inSampleSize option to make your bitmaps smaller and occupy less memory Strange out of memory issue while loading an image to a Bitmap object.
I made a complete example of LazyList and posted the source, may also be helpful Lazy load of images in ListView.

Categories

Resources