I am developping an app that has a main activity showing the app title (two animated imageviews overlayed), two animated pictures, also overlayed, and three buttons. This activity also has a background image, which is the same that is used by the other activities.
The app flows from one activity to another and, eventually, this main activity is launched again (with the FLAG_ACTIVITY_CLEAR_TOP). Everything works fine but, after reloading it several times, an Out Of Memory error happens on my Android 2.1 device.
At first, I had all the images in the drawable folder and the problem appeared after reaching the main activity 5 times. Then, I adjusted the bitmap sizes and put them in the approppriate folders depending on the density and the problem appeared after reaching the main activity 14 times. Now, I just removed the background image for test purposes and the Out Of Memory appears after more than 20 re-launches.
Also, if I press the Home button and then switch back to my app, the problem seems not to appear until much later.
Moreover, I tested the app in a Nexus 5 and the Out Of Memory never happens.
So... is that a problem with my phone? with Android 2.1?
Thanks!
[EDIT]
I think that I have located the problem but, still, strange behavior.
For example, at one point, I need to recreate the activity. As the "recreate" method is not available for my min API level (7), I do it as follows:
Intent refresh = new Intent(getActivity(), getActivity().getClass());
refresh.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(refresh);
Which, I think, is correct. I release the onClickListeners and clear the animations in onStop(). However, if I put a breakpoint in onStop(), it is not called when I expect it to happen. Sometimes it is called as soon as the activity is recreated but sometimes it is called several seconds later.
However, if I press the Home button, onStop is properly called and when I switch back to the application everything works fine.
The easiest solution is to add in manifest under application tag
android:largeHeap="true"
But this is won't solve your problem, just delay it to a few more rounds
This link will help you to analyze your application and see what cause this:
http://blogs.innovationm.com/android-out-of-memory-error-causes-solution-and-best-practices/
My Guess this is related to images because i had this issue also..
The android official link to this problem is:
http://developer.android.com/training/displaying-bitmaps/index.html
This the link that helped me.. Try it out
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Hope that helps
check this outLoading Large Bitmaps Efficiently
Read Bitmap Dimensions and Type
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
Load a Scaled Down Version into Memory
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
imageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
Related
I have to create an animation for a Windows Phone 8.1 app. I want to change the ImageSource property of my Page.Background to display an animated splash when the app launches.
I used this sample as a model: http://www.codeproject.com/Tips/823622/Images-Animation-By-Using-Story-Board-in-Windows-P
In my code, the animation lasts 8 seconds for 80 images, but the screen stays black for 8 seconds, then only displays the last frame.
private void setupStoryboard()
{
storyboard = new Storyboard();
var animation = new ObjectAnimationUsingKeyFrames();
Storyboard.SetTarget(animation, BackgroundBrush);
Storyboard.SetTargetProperty(animation, "ImageSource");
storyboard.Children.Add(animation);
for (int i = 0; i <= 80; i++)
{
var keyframe = new DiscreteObjectKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(100 * i)), //Time Interval
Value = String.Format("ms-appx:///Assets/Animation/splash{0:D2}.png", i) //Source of images
};
animation.KeyFrames.Add(keyframe);
}
Resources.Add("Storyboard", storyboard); //Add story board to resources
}
This code is called from OnNavigatedTo, and I have a button to call storyboard.Begin();
This problem appears on simulator and device.
Update: The problem persists with a greater interval (1000ms), and smaller images (30KB jpg instead of 240KB png)
Update: Same problem with an <Image> tag
Update: Still not solved, but I managed to obtain the desired effect. I created a DispatcherTimer to manually change the image. Unfortunately, this creates a nasty flickering effect. I had to add a second identical image on top of the first, and alternate between the two: imageA loads source1, imageB loads source2, imageA loads source3, ImageB loads source4...
Mission completed, with duct tape.
I have ~10000 objects in my game and exactly 60 (maximum) FPS when mouse isn't moved. But just when you start moving mouse in circles FPS tries to reach 30 averaging at 45. When you stop mouse it's INSTANTLY 60 (as so program lost it's heartbeat). SWF is run standalone - without any browsers.
I removed any MouseEvent.MOUSE_MOVE listeners and made mouseEnabled=false and mouseChildren=false for the main class.
I increased my FPS one-by-one from 12 to 60 - I gave name to each frame I born and it's really painful watching how 15 of them die just because of nothing...
Sample code:
public class Main extends Sprite
{
private var _periods : int = 0;
/** Idling FPS is 23. Move mouse to drop FPS to 21.*/
public function Main() : void
{
//true if need to drop FPS to 18 instead of 21 moving mouse:
const readyToKill2MoreFrames : Boolean = true;
if ( readyToKill2MoreFrames )
{
var ellipse : Sprite = new Sprite;
ellipse.graphics.beginFill( 0x00FF00 );
ellipse.graphics.drawEllipse( 300, 300, 400, 200 );
ellipse.graphics.endFill();
addChild( ellipse );
//uncomment to fall only to 21 instead of 18:
/*ellipse.mouseChildren = false;
ellipse.mouseEnabled = false;*/
}
var fps : TextField = new TextField;
//uncommenting doesn't change FPS:
//fps.mouseEnabled = false;
addChild( fps );
fps.text = "???";
fps.scaleX = fps.scaleY = 3;
var timer : Timer = new Timer( 1000 );
timer.addEventListener( TimerEvent.TIMER, function( ... args ) : void
{
fps.text = _periods.toString();
_periods = 0;
} );
timer.start();
addEventListener( Event.ENTER_FRAME, function( ... args ) : void
{
//seems like PC is too fast to demonstrate mouse movement
// drawbacks when he has nothing else to do, so let's make
// his attention flow:
for ( var i : int = 0; i < 500000; ++i )
{
var j : int = 2 + 2;
}
++_periods;
} );
}
}
You've probably moved on to more modern problems, but I've recently struggled with this issue myself, so here's an answer for future unfortunates stuck with the problems created by Adobe's decade-old sins.
It turns out legacy support for old-style buttons is the culprit. Quote from Adobe's tutorial on the excellent Scout profiling tool:
"Flash Player has some special code to handle old-style button objects (the kind that you create in Flash Professional).
Independently of looking for ActionScript event handlers for mouse
events, it searches the display list for any of these buttons whenever
the mouse moves. This can be expensive if you have a large number of
objects on the display list. Unfortunately, this operation happens
even if you don't use old-style button objects, but Adobe is working
on a fix for this."
Turns out Adobe never really got around to fixing this, so any large number of DisplayObjects will wreak havoc on your FPS while the mouse is moved. Only fix is to merge them somehow, e.g. by batch drawing them using Graphics. In my early tests, it seems setting mouseEnabled = false has no real effect, either.
We are using a .net dll (http://imageresizing.net/download) for imageresizing on runtime. It works perfectly. However, it happen after some time (between 1-7 days) that system started to raise exception in the even viewer:
Exception information:
Exception type: OutOfMemoryException
Exception message: Insufficient memory to continue the execution of the program.
And after that exception the website usually stop working with the error throwing "System.OutOfMemoryException".
And if we "recycle" the application pool in which the website is running, it clears the problem and website get back to normal immediately without any code change.
Before imagereiszing dll, we were using our custom code and same problem happen with that too. Following is the code.
private Bitmap ConvertImage(Bitmap input, int width, int height, bool arc)
{
if (input.PixelFormat == PixelFormat.Format1bppIndexed ||
input.PixelFormat == PixelFormat.Format4bppIndexed ||
input.PixelFormat == PixelFormat.Format8bppIndexed)
{
Bitmap unpackedBitmap = new Bitmap(input.Width, input.Height);
Graphics g = Graphics.FromImage(unpackedBitmap);
g.Clear(Color.White);
g.DrawImage(input, new Rectangle(0,0,input.Width, input.Height));
g.Dispose();
input = unpackedBitmap;
}
double aspectRatio = (double)input.Height / (double)input.Width;
int actualHeight = CommonMethods.GetIntValue(Math.Round(aspectRatio * width, 0));
Bitmap _imgOut;
if (actualHeight > height)
{
ResizeImage resizeImage = new ResizeImage(width, actualHeight, InterpolationMethod.Bicubic);
Bitmap _tempBitmap = resizeImage.Apply(input);
Bitmap _croppedBitmap = new Bitmap(width, height);
Graphics _crop = Graphics.FromImage(_croppedBitmap);
_crop.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
_crop.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
_crop.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
_crop.DrawImageUnscaledAndClipped(_tempBitmap, new Rectangle(0, 0, width, height));
_crop.Dispose();
_imgOut = _croppedBitmap;
}
else
{
ResizeImage resizeImage = new ResizeImage(width, height, InterpolationMethod.Bicubic);
_imgOut = resizeImage.Apply(input);
}
// Draw the arc if it has been requested
if (arc)
{
Graphics _arc = Graphics.FromImage(_imgOut);
_arc.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
_arc.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
_arc.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
_arc.DrawArc(new Pen(Color.White, 24), new Rectangle(-13, -13, 50, 50), 180, 90);
_arc.Dispose();
}
// job done
return _imgOut;
}
We are resizing image like: www.mysite.com/images/myimage.jpg?width=196&height=131
Looking forward.
Farrukh
When you encounter an OutOfMemoryException (regardless of where it occurs), it can be caused by a memory leak anywhere in the application. Having debugged dozens of these instances with WinDbg, I've never found any that ended up being due to a bug in http://imageresizing.net.
That said, there's an easy way to determine whether it is a problem with http://imageresizing.net or not; create a separate application pool and subfolder application in IIS for your images and image resizing. Install nothing there except the image resizer. Next time you encounter the error, log on to the server and find out which w3wp.exe instance is responsible for the massive memory usage.
If it's in the ImageResizer app pool, go collect your $20-$50 bug bounty from http://imageresizing.net/support. If not, you need to figure out where you're leaking stuff in your main application.
If you're working with System.Drawing anywhere else in the app, that's the first place to look. Check your code against this list of pitfalls.
If you're positive you're disposing of every System.Drawing.* instance in a using or finally clause, then read this excellent article a few times to make sure you're not failing on any of the basics, then dig in with DebugDiag and/or WinDBG (see bottom of article).
I am in the process of moving a webforms app to MVC3. Ironically enough, everything is cool beans except one thing - images are served from a handler, specifically the Microsoft Generated Image Handler. It works really well - on average a 450kb photo gets output at roughly 20kb.
The actual photo on disk weighs in at 417kb, so i am getting a great reduction.
Moving over to MVC3 i would like to drop the handler and use a controller action. However i seem to be unable to achieve the same kind of file size reduction when rendering the image. I walked through the source and took an exact copy of their image transform code yet i am only achieving 230~kb, which is still a lot bigger than what the ms handler is outputting - 16kb.
You can see an example of both the controller and the handler here
I have walked through the handler source code and cannot see anything that is compressing the image further. If you examine both images you can see a difference - the handler rendered image is less clear, more grainy looking, but still what i would consider satisfactory for my needs.
Can anyone give me any pointers here? is output compression somehow being used? or am i overlooking something very obvious?
The code below is used in my home controller to render the image, and is an exact copy of the FitImage method in the Image Transform class that the handler uses ...
public ActionResult MvcImage()
{
var file = Server.MapPath("~/Content/test.jpg");
var img = System.Drawing.Image.FromFile(file);
var sizedImg = MsScale(img);
var newFile = Server.MapPath("~/App_Data/test.jpg");
if (System.IO.File.Exists(newFile))
{
System.IO.File.Delete(newFile);
}
sizedImg.Save(newFile);
return File(newFile, "image/jpeg");
}
private Image MsScale(Image img)
{
var scaled_height = 267;
var scaled_width = 400;
int resizeWidth = 400;
int resizeHeight = 267;
if (img.Height == 0)
{
resizeWidth = img.Width;
resizeHeight = scaled_height;
}
else if (img.Width == 0)
{
resizeWidth = scaled_width;
resizeHeight = img.Height;
}
else
{
if (((float)img.Width / (float)img.Width < img.Height / (float)img.Height))
{
resizeWidth = img.Width;
resizeHeight = scaled_height;
}
else
{
resizeWidth = scaled_width;
resizeHeight = img.Height;
}
}
Bitmap newimage = new Bitmap(resizeWidth, resizeHeight);
Graphics gra = Graphics.FromImage(newimage);
SetupGraphics(gra);
gra.DrawImage(img, 0, 0, resizeWidth, resizeHeight);
return newimage;
}
private void SetupGraphics(Graphics graphics)
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighSpeed;
}
If you don't set the quality on the encoder, it uses 100 by default. You'll never get a good size reduction by using 100 due to the way image formats like JPEG work. I've got a VB.net code example of how to set the quality parameter that you should be able to adapt.
80L here is the quality setting. 80 still gives you a fairly high quality image, but at DRASTIC size reduction over 100.
Dim graphic As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(newImage)
graphic.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic
graphic.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality
graphic.PixelOffsetMode = Drawing.Drawing2D.PixelOffsetMode.HighQuality
graphic.CompositingQuality = Drawing.Drawing2D.CompositingQuality.HighQuality
graphic.DrawImage(sourceImage, 0, 0, width, height)
' now encode and send the new image
' This is the important part
Dim info() As Drawing.Imaging.ImageCodecInfo = Drawing.Imaging.ImageCodecInfo.GetImageEncoders()
Dim encoderParameters As New Drawing.Imaging.EncoderParameters(1)
encoderParameters.Param(0) = New Drawing.Imaging.EncoderParameter(Drawing.Imaging.Encoder.Quality, 80L)
ms = New System.IO.MemoryStream
newImage.Save(ms, info(1), encoderParameters)
When you save or otherwise write the image after setting the encoder parameters, it'll output it using the JPEG encoder (in this case) set to quality 80. That will get you the size savings you're looking for.
I believe it's defaulting to PNG format also, although Tridus' solution solves that also.
However, I highly suggest using this MVC-friendly library instead, as it avoids all the image resizing pitfalls and doesn't leak memory. It's very lightweight, free, and fully supported.
On request I have implemented support for moving an OS X window by dragging it using an area within the content part of the window, i.e replicating the drag and move functionality of the title bar but in another area.
The problem I have yet to resolve is the fact that if the user drags the mouse quickly it can leave the window area and then no more mouse move events are received.
On windows this type of problem can simply be fixed by calling the win32 method SetCapture(), what's the corresponding OSX method?
This application is a cross platform C++ application using Carbon for the OS X specific parts. (And yes, I know all about the Cocoa benefits but this is an older code base and there no time nor money for a Cocoa port at this point in time.)
I have found Carbon API methods like for example TrackMouseLocation() but can't really see how I could use them for this application. In listing 2-7 here http://developer.apple.com/legacy/mac/library/documentation/Carbon/Conceptual/Carbon_Event_Manager/Tasks/CarbonEventsTasks.html
the mouse is captured but the problem is that TrackMouseLocation() blocks waiting for input. Blocking is something this application can not do since it also host a flash player that must be called many times per second.
The protototype I have assembled when trying to figure this out basically looks like this:
switch(GetEventKind(inEvent))
{
case kEventMouseDown:
// A silly test to make parts of the window border "draggable"
dragging = local_loc.v < 25 || local_loc.h < 25;
last_screen_loc = screen_loc;
break;
case kEventMouseUp:
dragging = false;
break;
case kEventMouseMoved:
break;
case kEventMouseDragged:
if (dragging) {
Rect rect;
GetWindowBounds (windowRef, kWindowContentRgn, &rect);
int dx = screen_loc.h - last_screen_loc.h;
int dy = screen_loc.v - last_screen_loc.v;
rect.left += dx;
rect.right += dx;
rect.top += dy;
rect.bottom += dy;
SetWindowBounds (windowRef, kWindowContentRgn, &rect);
}
last_screen_loc = screen_loc;
break;
Any ideas appreciated?
I feel you should track mouse in Window as well as out of window. Following code should solve your problem,
EventHandlerRef m_ApplicationMouseDragEventHandlerRef;
EventHandlerRef m_MonitorMouseDragEventHandlerRef;
{
OSStatus ErrStatus;
static const EventTypeSpec kMouseDragEvents[] =
{
{ kEventClassMouse, kEventMouseDragged }
};
ErrStatus = InstallEventHandler(GetEventMonitorTarget(), NewEventHandlerUPP(MouseHasDragged), GetEventTypeCount(kMouseDragEvents), kMouseDragEvents, this, &m_MonitorMouseDragEventHandlerRef);
ErrStatus = InstallApplicationEventHandler(NewEventHandlerUPP(MouseHasDragged), GetEventTypeCount(kMouseDragEvents), kMouseDragEvents, this, &m_ApplicationMouseDragEventHandlerRef);
return true;
}
//implement these functions
OSStatus MouseHasDragged(EventHandlerCallRef inCaller, EventRef inEvent, void *pUserData){}
Hope it helps!!
I Hope It Help´s you too:
// Get Mouse Position --> WAY 1
printf("Get Mouse Position Way 1\n");
HICoordinateSpace space = 2;
HIGetMousePosition(space, NULL, &point);
printf("Mouse Position: %.2f %.2f \n", point.x, point.y);
// Get Mouse Position --> WAY 2
printf("Get Mouse Position Way 2\n");
CGEventRef ourEvent = CGEventCreate(NULL);
point = CGEventGetLocation(ourEvent);
printf("Mouse Position: %.2f, y = %.2f \n", (float)point.x, (float)point.y);
I´m looking for the way to get a WindowPart Reference at a certain location (over all windows of all aplications)
Certain methods in Carbon doesn´t work, always return 0 as a windowRef... Any ideas?
You could also try just calling DragWindow in response to a click in your window's content area. I don't think you need to implement the dragging yourself.