The main problem is that the app starts only after installation or reboot.
Second time the application does not run correctly.
Details are below.
I have encountered with a few strange problems
1) Libgdx did not detect screen size correctly on Android 4 in
SCREEN_WIDTH = Gdx.graphics.getWidth();
I got 369*320 instead of 960*540
I do as follows to fight with this problem:
I run main Activity class, where I get screen size using Display
Then I run AndroidApplication class where I start Admob and Libgdx class.
2) The second problem is that the app starts
with no initialized values, that is to say with the same memory.
No initialization of values such as boolean abc=false;
Looks like invalid exit?
In Libgdx class (third class) I set some value exit=true and exit,
disposing all textures. Program returns to the second class .
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Data.exit) finish();
Second class returns to main activity
which checks exit in the same manner
3) Next interesting thing is that now Gdx.graphics.getWidth()
gets screen size correctly. Mistery...
4) If so, I remade the app.
And now main class starts Libgdx class.
It works and exits good, but only first time after installation or reboot.
Seconds time Libgdx onCreate starts, but render() does not.
Looks like invalid exit after first start again:
The main class code is here
public class MyActivity extends AndroidApplication
implements IActivityRequestHandler {
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
context.startService(new Intent(context, BillingService.class));
....
// Create the libgdx View
View gameView = initializeForView(new MyGame(this), false);
// Create and setup the AdMob view
adView = new AdView(this, AdSize.BANNER, "aaaaaaa");
}
#Override
public synchronized void onPause() {
super.onPause();
}
#Override
public void onStop() {
super.onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
Any ideas? Thanks!!
You are using statics. They preserve their value when you close the app, and you open it again before Android destroys the process, hence using the same VM. You cannot control when Android will destroy it, so try to initialize these variables in the constructor/create method of their class.
Instead of:
static boolean abc=false;
Use:
static boolean abc;
public MyClass/create(){
abc=false;
}
Or do not use statics unless necessary.
Related
I'm developing an app that integrates with Unity3d, in some part of my code I call an UnityPlayerActivity that starts the Unity3d code. When user finishes using the Unity3d he press a button and go back to Android code.
My problem is when I go back to android code, after UnityPlayerActivity calls:
#Override protected void onDestroy ()
{
mUnityPlayer.quit();
super.onDestroy();
}
The application is closed, not only the Unity Activity. I could not call this method, but I think that would be wasting memory.
Is there any way I could quit only Unity3d activity and keep my application running normally so I could start Unity3d part again another time?
Tks
Found an answer. Just need to use another process on manifest.
Basically means, you have to explicitly name your Activity process in your AndroidManifest.xml.
For instance.
<activity
android:name=".UnityPreviewActivity"
android:process=".UnityPreviewActivity" />
Reference
http://answers.unity3d.com/questions/587979/how-do-i-stop-munityplayerquit-closing-the-entire.html
1.override kill() method of UnityPlayer class
class MyUnityPlayer extends UnityPlayer {
public MyUnityPlayer(Context context) {
super(context);
}
#Override
protected void kill() {
}
}
kill() is invoked in mUnityPlayer.quit() and it will kill current process:
protected void kill() {
Process.killProcess(Process.myPid());
}
So override it to avoid process being killed.
2.change the type of mUnityPlayer to MyUnityPlayer in UnityPlayerActivity
3.call finish() method of UnityPlayerActivity when you want to exit the Activity.
(In my case,App crashed after fininshing UnityPlayerActivity after starting a new activity from UnityPlayerActivity.)
You could also just use reflection and therefore avoid calling the kill() method (which is called in quit()) which kills the current process
i.e.
try {
//1
Field v = unityPlayer.getClass().getDeclaredField("v");
v.setAccessible(true);
Method a = v.getType().getMethod("a");
a.invoke(v.get(unityPlayer));
//2
Field o = unityPlayer.getClass().getDeclaredField("o");
o.setAccessible(true);
o.set(unityPlayer, true);
//3
unityPlayer.pause();
Method unloadVR = unityPlayer.getClass().getDeclaredMethod("unloadGoogleVR");
unloadVR.setAccessible(true);
unloadVR.invoke(unityPlayer);
//4
unityPlayer.removeAllViews();
//5
Method h = unityPlayer.getClass().getDeclaredMethod("h");
h.setAccessible(true);
h.invoke(unityPlayer);
} catch (Exception e) {
e.printStackTrace();
}
First I have a method which creates an activity which displays a view:
Intent intent = new Intent(viewController, TestActivity.class);
viewController.TestActivity(intent);
My TestActivity class calls setContentView(layout) and displays a view.
This works fine, my problem is trying to remove the Intent/View from the screen. I know I can call destroy() from within my Activity, however I am trying to remove the view from outside of the Activity class. I want the class which created the Activity/Intent to be able to remove it as well.
Any ideas? It seems like this should be a trivial fix however I'm unable to find the solution online for some reason. Thanks!
Make a sigleton-like pattern to get the instance of the started activity.
public class TestActivity extends Activity{
private static TestActivity instance;
public static TestActivity getInstance(){
return instance;
}
public void onCreate(Bundle savedInstanceState){
//xxxxx
super.onCreate(savedInstanceState);
instance = this;
}
protected void onDestroy(){
//xxxxx
super.onDestroy();
instance = null;
}
public void finishOutSide(){
this.finish();
}
}
Then in the outside,use these code to finish the activity:
if(TestActivity.getInstance() != null){
TestActivity.getInstance().finishOutSide();
}
All of your Activity instances can be destroyed when the sustem is running low on memory. Hence, it causes unexpected behaviour. Finish an Activity itside itself only or in a foreground Service that cannote be unexpectedly killed.
You have to rethink your application architecture to avoid such issue.
During the normal course of development, I noticed that a particular activity appears to have stopped responding the second time it is called.
i.e. menu->(intent)->activity->(back button)->menu->(intent)
There is nothing relevant in logcat.
I don't even know where to start debugging this nor what code to show so here are the onClick and onResume fragments:
if (!dictionary.getClassName().equals("")) {
this.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent i;
i = new Intent(mContext, NVGlobeNavigatorVC.class);
i.putExtra("PAGE_TITLE", title);
i.putExtra("TITLE", _dictionary._title);
mContext.startActivity(i);
});
} else {
findViewById(R.id.greaterthan).setVisibility(View.GONE);
}
and in the Activity being launched:
#Override
protected void onResume() {
super.onResume();
...
Nothing unusual in manifest either:
<activity
android:name=".NVViews.NVGlobeNavigatorVC"
android:theme="#style/WindowTitleBackground"
android:label="GlobeNavigator"/>
For clarity, I put breakpoints on mContext.startActivity(i) and super.onResume(). I click the view with the onClickListener and both breakpoints are hit as expected. I then press the back button which returns me to the menu. onPause() is called as expected.
I touch the view to launch the activity again, and the breakpoint on startActivity is hit but not in onResume() in the target activity. The screen goes black and the only way I can get going again is to restart the app. If I pause the debugger, it pauses in dalvik.system.NativeStart() which implies that the activity is never relaunched.
I don't think it's relevant, but I'm using Intellij IDEA and have deleted all of the output directories, invalidated the caches and done a full rebuild.
Target API is 8. I've tested on 2.3 and 4.0.4.
Any ideas? I'm stumped.
[EDIT]
In onPause, I save some stuff to prefs. The purpose of onResume() is to get them back again:
#Override
protected void onPause() {
super.onPause();
SCPrefs.setGlobeViewViewPoint(globeView.getViewPoint());
SCPrefs.setGlobeViewZoom(globeView.getZoom());
SCPrefs.setGlobeViewScale(globeView.getScale());
}
This code:
i = new Intent(mContext, NVGlobeNavigatorVC.class);
creates a new intent. The intent is of class NVGlobeNavigatorVC.class.
If you call it once, you create a new activity, lets call it "iTheFirst". If you back out of the activity, it executes "on pause". When you run the above code again, you create another new activity of the same class, but a different acitivity. Hence it won't resume your other activity, but make a new one that we could call "iTheSecond". It looks just like iTheFirst but is unique.
If you want to resume the above, after backing out of it, you need to keep a reference to it in your menu. Then in your onClick, look to see if that activity exists, and if not, make a new one and start it, and if it does exist, just resume it.
Here is a sample activity that remembers and restarts an activity:
Intent savedCueCardActivity = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.landing);
}
public void goToNextScreen(View v) {
if (savedCueCardActivity == null) {
savedCueCardActivity = new Intent().setClass(this, CueCardActivity.class);
startActivity(savedCueCardActivity);
// lastActivity.finish();
} else {
savedCueCardActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(savedCueCardActivity);
}
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
}
I found the problem, and it's a bit esoteric.
I have a large static data structure which is loaded in a class static initialiser. There was a bug in that initialiser causing an infinite loop the second time it was called if the data structure was still loaded.
Because that class is referenced in my Activity, the class loader is loading it before onCreate() or onResume() is called.
The loop gave the appearance that the Activity loader had hung.
i'm trying to jump from activity one to activity two but after 1 second. So i used Thread.sleep(1000) and after that the activity two comes to front.Its working good but problem is I have given a image background in activity one which is not shown.
public class Activity1 extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
Thread.sleep(1000);
Intent i=new Intent(Activity1.this,Activity2.class );
startActivity(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
additionally I included a button in Activity two which does the functionality of jumping to Activity one, in this case the image is shown for 1 second but not the first time when I open up my app.
You can create RelativeLayout and show/hide it and use 1 Activity only
public class MyView extends RelativeLayout{
private ImageView view = ....;
....
view.setVisibility(View.VISIBLE);
....
view.setVisibility(View.GONE);
}
You UI is not built until after onCreate() finishes. Therefore, if you start activity 2 in onCreate(), you will never see activity 1.
Instead:
#Override
void onAttachedToWindow() {
// start activity 2
}
As others have said in their comments, you should never use sleep on the UI thread. Indeed, I wish that Java made it much harder to use sleep because it is used far too much and often as a quick fix which avoids the right solution.
In this case, you should use an AsyncTask to start the second activity after one second.
I've been working with AsyncTasks in Android and I am dealing with an issue.
Take a simple example, an Activity with one AsyncTask. The task on the background does not do anything spectacular, it just sleeps for 8 seconds.
At the end of the AsyncTask in the onPostExecute() method I am just setting a button visibility status to View.VISIBLE, only to verify my results.
Now, this works great until the user decides to change his phones orientation while the AsyncTask is working (within the 8 second sleep window).
I understand the Android activity life cycle and I know the activity gets destroyed and recreated.
This is where the problem comes in. The AsyncTask is referring to a button and apparently holds a reference to the context that started the AsyncTask in the first place.
I would expect, that this old context (since the user caused an orientation change) to either become null and the AsyncTask to throw an NPE for the reference to the button it is trying to make visible.
Instead, no NPE is thrown, the AsyncTask thinks that the button reference is not null, sets it to visible. The result? Nothing is happening on the screen!
Update: I have tackled this by keeping a WeakReference to the activity and switching when a configuration change happens. This is cumbersome.
Here's the code:
public class Main extends Activity {
private Button mButton = null;
private Button mTestButton = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mButton = (Button) findViewById(R.id.btnStart);
mButton.setOnClickListener(new OnClickListener () {
#Override
public void onClick(View v) {
new taskDoSomething().execute(0l);
}
});
mTestButton = (Button) findViewById(R.id.btnTest);
}
private class TaskDoSomething extends AsyncTask<Long, Integer, Integer>
{
#Override
protected Integer doInBackground(Long... params) {
Log.i("LOGGER", "Starting...");
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 0;
}
#Override
protected void onPostExecute(Integer result) {
Log.i("LOGGER", "...Done");
mTestButton.setVisibility(View.VISIBLE);
}
}
}
Try executing it and while the AsyncTask is working change your phones orientation.
AsyncTask is not designed to be reused once an Activity has been torn down and restarted. The internal Handler object becomes stale, just like you stated. In the Shelves example by Romain Guy, he simple cancels any currently running AsyncTask's and then restarts new ones post-orientation change.
It is possible to hand off your Thread to the new Activity, but it adds a lot of plumbing. There is no generally agreed on way to do this, but you can read about my method here : http://foo.jasonhudgins.com/2010/03/simple-progressbar-tutorial.html
If you only need a context and won't use it for ui stuff you can simply pass the ApplicationContext to your AsyncTask.You often need the context for system resources, for example.
Don't try to update the UI from an AsyncTask and try to avoid handling configuration changes yourself as it can get messy. In order to update the UI you could register a Broadcast receiver and send a Broadcast.
You should also have the AsyncTask as a separate public class from the activity as mentioned above, it makes testing a lot easier. Unfortunately Android programming often reinforces bad practices and the official examples are not helping.
This is the type of thing that leads me to always prevent my Activity from being destroyed/recreated on orientation change.
To do so add this to your <Activity> tag in your manifest file:
android:configChanges="orientation|keyboardHidden"
And override onConfigurationChanged in your Activity class:
#Override
public void onConfigurationChanged(final Configuration newConfig)
{
// Ignore orientation change to keep activity from restarting
super.onConfigurationChanged(newConfig);
}
To avoid this you can use the answer givin here: https://stackoverflow.com/a/2124731/327011
But if you need to destroy the activity (different layouts for portrait and landscape) you can make the AsyncTask a public class (Read here why it shouldn't be private Android: AsyncTask recommendations: private class or public class?) and then create a method setActivity to set the reference to the current activity whenever it is destroyed/created.
You can see an example here: Android AsyncTask in external class