im having an issue with TransitionDrawable class in android causing an ANR in strict mode. Here is the method call causing the ANR:
private void crossFadeImages(Drawable imageToFadeOut, Drawable imageToFadeIn) {
TransitionDrawable td = new TransitionDrawable( new Drawable[] {
imageToFadeOut,
imageToFadeIn
});
m_myimageView.setImageDrawable(td);
td.startTransition(200);
}
i am passing two drawables. the imageToFadeOut has the following specs:
337X599 PNG (32-bit color) 93.85KB
and the imageToFadeIn has the following specs:
337X599 PNG (32-bit color) 395.16KB
and the ANR is being caused in a nexus 5 emulator api 19 xxhdpi. The actual ANR shows up in strict mode mostly.
i get the following log error
"I/Choreographer: Skipped 33 frames! The application may be doing too much work on its main thread."
the method is called from the main thread. How can i resolve this ? Or is there another way to do the cross fading between two images ?
Related
Our company develops several games for mobile platforms, including Android. We use OpenGL for all visual items, including UI (more technical details are below).
We have received some weird warnings from Google Play Console in Pre-launch report, like “Your app took 20764 ms to launch”. On the video provided with this report, the game took about a second to start.
After some investigation we found that Android Systrace cannot detect OpenGL draws made from another thread. So Pre-launch tests think (wrongly) that our game is super-slow.
Is there some method to notify the system that a frame is drawn? It’s seems that eglSwapBuffers() is not enough.
There’s a link to the same problem with Cocos2d: https://discuss.cocos2d-x.org/t/frozen-frames-warnings-by-google-play-pre-launch-report-for-3-17-cocos-demo-app/42894
Some details
When a new build is published to Google Play Console, some automated tests are performed on different devices. Results of these tests are available in Pre-launch report section of the Google Play Console.
Starting from beginning of April we receive strange performance warnings on some of devices (always the same ones). Two examples:
Startup time: Your app took 20764 ms to launch…
Frozen frames: 33.33% of the frames took longer than 700ms to render
Both problems sound dreadful--would have they be true. But when we examined videos of testing, we could not see any problems. All games started pretty fast and ran without visual stuttering.
Systrace report
This is the picture of systrace showing 5 seconds of our game being started (rectangles were drawn by me).
systrace
As you can see, the systrace have found only 4 frames rendered (the pink rect), which were drawn from the RenderThread. But by some reason Android cannot detect our GL draw calls which are performed in another thread (blue rects).
Pre-launch reports also displays only 3 to 4 frames, each 300-400 ms long.
Initialization code
Our game engine runs all game logic and render code in a separate thread. This is simplified initialization code.
The worker thread is created from our Activity’s onStart() overriden method.
public class MyActivity extends Activity
{
protected Thread worker = null;
private native void Run();
#Override
protected void onStart()
{
super.onStart();
if(worker == null)
{
worker = new Thread()
{
public void run()
{
Run();
}
};
worker.start();
}
}
}
The only thing the thread does is the Run() native function. This function may be resolved into something like this:
void MyActivity::Run()
{
initApp();
while(!destroyRequested())
{
// Process the game logic.
if (activated && window != NULL)
{
time->process();
input->process();
sound->process();
logic->process();
graphics->draw();
}
}
clearApp();
}
As you can see, the worker thread constantly spins the update-and-draw loop. Vsync protects the loop from overperforming. Heavy operations like resource loading are done asynchronously to avoid freezes.
From the user side this approach works just fine. Games are loading fast and go smoothly.
I am getting a lot of different errors when trying to make my app work on android, when it works perfectly on my desktop. I've managed most of the errors but this error I cant figure out. I tried removing every drawable texture or animation one by one but still got the same error even with an empty screen.
E/AndroidRuntime: FATAL EXCEPTION: GLThread 96
java.lang.NullPointerException
at java.lang.String.<init>(String.java:443)
at com.jteck.game.states.PlayState.<init>(PlayState.java:118)
at com.jteck.game.states.MenuState.handleInput(MenuState.java:56)
at com.jteck.game.states.MenuState.update(MenuState.java:78)
at com.jteck.game.states.GameStateManager.update(GameStateManager.java:31)
at com.jteck.game.Hangman.render(Hangman.java:36)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:474)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
So, something causes the NullPointerException on the line 118 in the PlayState class.
I have a working android game which occasionally force closes on slow devices with the error
Fatal signal 6 (SIGABRT), code -6 in tid 14620 (AsyncTask #1)
Research indicated to me that this was due to delaying the execution of the UI thread, so, i bundled up the peace of code (about 200 lines of bitmap and region creation) into an AsyncTask (doInBackground method) and i now run that task from the UI thread using task.execute.
The problem is, this has in no way stopped the error. If anything the app force closes more frequently during the execution of that code despite the fact it should be running in an asyncTask.
In the interest of being thorough, the error is triggered during the execution of this part of the code (extract from the 200ish block):
Back.outerPath.setFillType(Path.FillType.EVEN_ODD);
Region tempRegion = new Region(PathBoundsRectangle);
Back.outerRegion.setPath(Back.outerPath, tempRegion);
Back.innerRegion.setPath(Back.innerPath, tempRegion);
Back.fastRegion.setPath(Back.speedPath, tempRegion);
Back.slowRegion.setPath(Back.slowPath, tempRegion);
Back.outerRegion.op(Back.innerRegion, Region.Op.XOR);
Matrix scaleMatrix = new Matrix();
RectF rectF = new RectF();
Back.innerPath.computeBounds(rectF, true);
scaleMatrix.setScale(1.1f, 1.1f,rectF.centerX(),rectF.centerY());
Back.innerPath.transform(scaleMatrix);
Back.outerPath.computeBounds(rectF, true);
scaleMatrix.setScale(0.9f, 0.9f,rectF.centerX(),rectF.centerY());
Back.outerPath.transform(scaleMatrix);
Back.outerSideBandRegion.setPath(Back.outerPath, tempRegion);
Back.outerSideBandRegion.op(Back.outerRegion, Region.Op.XOR);
Back.innerSideBandRegion.setPath(Back.innerPath, tempRegion);
Back.innerSideBandRegion.op(Back.innerRegion, Region.Op.XOR);
Any ideas? Is it possible the code is still running on the UI thread? Can this error be due to something else?
EDIT: It turns out the error is coming from the Region.op.XOR manipulations. Anyone see how this could cause a Fatal Error?
I have also observed this when calling Region.Op.INTERSECT on regions derived from extremely long and complex paths.
The solution that works for me is to maintain a record of all the path waypoints, and then to build a list of smaller paths onto which the Region.Op.INTERSECT operation gets executed individually.
In my default view I have:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Debug.startMethodTracing(Environment.getExternalStorageDirectory()+"/PosLogistics.trace", 1000000000);
and do the stop here:
protected void onStop()
{
super.onStop();
Debug.stopMethodTracing();
}
The android target is 2.2. When running on Motorolla 2.3 I can trace 900 ms. When running on Samsung Galaxy (4.0) and Sony Xperia (4.0) the app closes immediately as it starts up. Last entry from logcat is
02-15 05:25:19.940: I/dalvikvm(8740): TRACE STARTED: '/mnt/sdcard/PosLogistics.trace' 976562KB
According to this thread: Traceview maximum record time? the trace is limited by the device RAM. Might explain the Motorolla 900 ms, but what is the problem with the Galaxy and Xperia?
You are trying to allocate 1000000000 bytes ~ 1GB for trace buffer. I don't think any system will allow you to do that. It is for in memory buffer size, not for disk.
See vm/Profile.cpp line 383.
state->buf = (u1*) malloc(bufferSize);
Skip giving a buffer size. That will default it to 8MB, should be enough for your needs.
I get a clasical "VM budget excedees memory - out of memory" type error crash report from the Android Market.
I checked the app for memory leaks over and over again. This error happens on a very small percent of total application installs, around 1-2% and it always happens on start-up. The app loads some bitmaps from internal memory for each activity, but does not crash on most devices. I thought all applications had a guaranteed minimum stack size for bitmaps so this should work for every device. Min SDK is 7.
Any reason why ? Does this sound familiar to anyone ?
I had quite a similar problem, and my images were simply too big for some devices.
I have read that you have one image per Activity and I guess this happens when switching from one to another as the newly allocated Drawable cannot fit. What you could do, to save some memory, would be to unload the background image of the Activities that are not shown:
#Override
protected void onResume() {
super.onResume();
Drawable d = loadMyDrawableFromDisk();
setBackgroundDrawable(d);
}
#Override
protected void onPause {
setBackgroundDrawable(null);
super.onPause();
}
It may help as the memory will be freed a few after onPause() is called, and not when the underlying View of your Activity will be unallocated by the system.