Android - first app onCreate null parameter - java

I start develop app for Android. I have some code write in Eclipse and I use attached emulator. When I send porgram to my emulator I get some error.
Debugger show in line super.onCreate(savedInstanceState); // savedInstanceState = null
My code
public class PushAndroidActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
try
{
super.onCreate(savedInstanceState);
checkNotNull(SENDER_ID, "SENDER_ID");

Could you just try rotating your device - left ctrl F11. you will realize that the bundle is != null
onSaveInstanceState() will be called by default for a view if it has an id. The default implementation takes care of most of the UI per-instance state for you by calling onSaveInstanceState() on each view in the hierarchy that has an id. You could check these :
savedInstanceState is always null
When are ALL the cases when the onSaveInstanceState() method called?

Related

Android Java onCreate

So I followed Google's first Android app sample. If I tapped the send button, it opened up the DisplayMessageActivity. But upon tapped the back button (left arrow) from the DisplayMessageActivity, the onCreate(Bundle savedInstanceState) of the MainActivity got called again. It looks like it created a new instance of MainActivity. I could verify this by setting a bool value in onCreate of MainActivity and it was not retained.
How do you go back to the previous instance of MainActivity (the caller)?
You should have a look at Androids Activity Lifecycle.
If you want to access the state of the activity again, I would suggest to use the method
public void onSaveInstanceState(Bundle outState)
to save the current state.
Retrieve the previously saved values in this method:
public void onRestoreInstanceState(Bundle savedInstanceState)`
An example can be found here
You can call finish() in the onClickListener of the back arrow view. It will finish the DisplayMessageActivity and you will return to the caller activity (MainActivity in your case).
Something like:
backArrow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
It looks like it created a new instance of MainActivity.
Yes, I think, that was quite a normal behavior.
Basically, Android OS would keep only one Activity at once so that free as many memory resources as possible.
You should design your application with understanding about such lifecycle concepts.
You can save some of the states of your Activity in certain manners (Parcelable, Bundle or SharedPreferences, etc.).

Why does the change in position of the setContentView change the behavior of the the app?

When I place "setContentView" above the "NumbersClickListners" line the app works as expected.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NumbersClickListners numbersClickListners = new NumbersClickListners();
TextView numbers = (TextView) findViewById(R.id.numbers);
numbers.setOnClickListener(numbersClickListners);
}
But as soon as the "setContentView" is placed below the three lines starting with "NumbersClickListners" the app crashes. The code looks like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NumbersClickListners numbersClickListners = new NumbersClickListners();
TextView numbers = (TextView) findViewById(R.id.numbers);
numbers.setOnClickListener(numbersClickListners);
setContentView(R.layout.activity_main);
}
I'm pretty much unsure of the reason for this behavior. Can anybody help me with that please?
Let's look at the life of layout.
First of all, you have to create it by declaring XML file, where you do your design in a user-friendly way and name the elements according to your needs.
Now your layout is just a file, that Android doesn't really care about for performance reasons.
Next thing you wanna do is use your layout. To do that your file needs to be converted to internal structure of objects known as ViewGroup and Views.
This process is called inflating. That's the point where the system can find the views for you by calling findViewById().
So in the second snippet you ask activity to find you a button, which is not inflated. That leads to throwing exception.
Generally speaking, first thing you want to do in the onCreate is to call setContentView().

Android findFragmentByTag returns null when debugging

Background:
I am writing an android application with an activity that can be populated by one of a number of fragments. Relatively often, I need to pass a bundle of data to the active fragment so that it can update the UI accordingly.
To get the current fragment, I call getfragmentManager().findFragmentByTag() and cast the returned fragment to my custom fragment class.
The problem:
The above method usually works fine. However, findFragmentByTag() occasionally returns null. Upon further investigation, I have concluded that this will only occur when I run or debug from Android studio (and even then it doesn't happen every time).
Relevant Code:
protected void onCreate(Bundle savedInstanceState){
//Do lots of stuff
currentFragmentTag = "";
getFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
currentFragmentTag = getFragmentManager().getBackStackEntryAt(getFragmentManager().getBackStackEntryCount() - 1).getName();
}
}
});
init();
//Do some more stuff
//this should always be the case
if (currentFragmentTag.equals(LOGIN_FRAGMENT_TAG)) {
((LoginFragment) getFragmentManager().findFragmentByTag(currentFragmentTag)).beginLogin();
}
}
private void init(){
//changed to reflect George Mulligan's advice
Fragment currentFrag = getFragmentManager().findFragmentByTag(LOGIN_FRAGMENT_TAG);
if(currentFrag == null) {
currentFragmentTag = LOGIN_FRAGMENT_TAG;
getFragmentManager().beginTransaction()
.add(R.id.container, loginFrag, LOGIN_FRAGMENT_TAG)
.addToBackStack(LOGIN_FRAGMENT_TAG)
.commit();
getFragmentManager().executePendingTransactions();
}
}
public void updateFragment(){
Bundle dataBundle = new Bundle();
//put stuff in dataBundle
if (currentFragmentTag.equals(LOGIN_FRAGMENT_TAG)) {
LoginFragment currentFrag = (LoginFragment) getFragmentManager().findFragmentByTag(currentFragmentTag);
if (currentFrag != null) {
currentFrag.passBundleToFragment(dataBundle);
Log.d(TAG, "Fragment returned is valid.");
} else {
Log.d(TAG, "Fragment returned is null.");
}
}
//else if a different fragment is active then update it in the same way
}
//Manually open the loginFragment. This can be called from other fragments. My problem always occurs before this is called however.
#Override
public void openLoginScreen() {
if(/*some conditions*/) {
LoginFragment loginFrag = LoginFragment.newInstance();
getFragmentManager().beginTransaction()
.replace(R.id.container, loginFrag, LOGIN_FRAGMENT_TAG)
.addToBackStack(LOGIN_FRAGMENT_TAG)
.commit();
getFragmentManager().executePendingTransactions();
currentFragmentTag = LOGIN_FRAGMENT_TAG;
updateFragment();
}
}
Normally, my logcat looks something like this:
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
...etc.
But every now and then, and only when I start the app from Android Studio, I get something like:
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is valid
Fragment returned is valid
What on Earth is going on here?
UPDATE:
I have been able to reproduce this error while disconnected from Android Studio by clicking the app switch button, closing my app and immediately restarting it. Provided I do this quickly enough, it never fails to behave as I described above.
After some more logging and chasing down other issues, I discovered that in these particular cases, onCreate() is being called twice.
My app is designed to run only in landscape mode, in part to avoid issues that come with recreating the activity. It would seem, however, that when the app is closed and restarted quickly, Android never finishes the necessary rotation to portrait mode for the home screen before my app is launched again. My assumption is that this causes the OS to rotate back to landscape after the app is running and thereby restart it.
All of this is fine and dandy, except for the fact that it doesn't explain why findFragmentByTag() sometimes returns null.
Every object in my Activity class should be recreated, right? So shouldn't the FragmentManager be re-initialized as well? Or is getFragmentManager() a static reference to something outside of the Activity itself?
SECOND UPDATE:
I tried George's idea of checking if the fragment had already been added before I call beginTransaction() and, although it didn't solve the problem, I noticed something strange when debugging:
I set a breakpoint at Log.d(TAG, "Fragment returned is null.");. Closing the app and quickly restarting it guarantees that this code will be reached as I mentioned above. Then, if I view the Fragment Manager by calling getFragmentManager() in the Evaluate Expression window, I notice that a `Login Fragment' has already been added, but it doesn't have a tag associated with it.
Setting a breakpoint at Log.d(TAG, "Fragment returned is valid.");in the same app session, however, reveals the LoginFragment is added with a tag as would be expected.
There is no point in my code where I ever add a fragment without setting a tag. Could this have something to do with the activity being recreated and the Fragment manager losing tags even though it holds onto the fragments themselves?
A few things to note on this.
In updateFragment you should really compare your Strings using .equals instead of reference comparison == so LOGIN_FRAGMENT_TAG.equals(currentFragmentTag)as a best practice and to avoid confusion.
Also, the FragmentManager will remember which fragments you have added to it across orientation changes. So in the one example you mentioned where you get into onCreate twice you will then likely have two instances of your LoginFrag on the back stack.
You can avoid this by doing the same lookup you are doing in your updateFragment method and only adding the fragment if it isn't found.
LoginFragment currentFrag = (LoginFragment) getFragmentManager()
.findFragmentByTag(LOGIN_FRAGMENT_TAG);
if(currentFrag == null) {
currentFrag = getFragmentManager().beginTransaction()
.replace(R.id.container, loginFrag, LOGIN_FRAGMENT_TAG)
.addToBackStack(LOGIN_FRAGMENT_TAG)
.commit();
//executePendingTransactions() usually isn't necessary...
getFragmentManager().executePendingTransactions();
}
I'm guessing multiple fragments are used in this activity since you bother having the String currentFragmentTag but if not then it would be better for you to just keep a reference to your LoginFragment as a field on the class so you can avoid the additional lookup of it in the updateFragment method.
Other than that I tried reproducing your error and I cannot so the error might be elsewhere in code you are not showing.
This isn't a direct answer to your question, but a suggestion for avoiding the problem in the first place.
Because the interaction between the Fragment and Activity Lifecycles is so complex and difficult to reason about, I've found that it's much easier if you completely decouple the two.
Instead of obtaining a reference to the Fragment and invoking a method on it directly, I set up a message bus (e.g. Otto or GreenRobot) and in your case, would have the Activity post a message to the bus, and have the Fragment subscribe to that message. Much cleaner, and if the Fragment happens to not be ready (hasn't registered with the bus yet), there's no error condition.
Ok, this should be a comment but, code formatting is ugly as a comment. Perhaps your fragment gets paused.
try this
#Override
public void onResume() {
super.onResume();
updateFragment();
}

Stuck with Facebook fall back share dialog

When on Android there is not Facebook native app, then in order to share a post from another Android app a web dialog is being opened. Here on step 4 there is a description how to open that dialog (see publishFeedDialog function).
My problems is that all the other code described in this tutorial I have wrote in AppActivity which is a subclass of Activity. Hence, getActivity() method is not defined as far as it is defined for Fragments. To solve this problem I have defined a private variable like this:
private Activity activity;
Assigned a value in onCreate method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;
// .......
}
and used in all places where there was a call of getActivity(). As I not a Java neither an Android expert, I would like to understand whether I have done it correctly.

Error in using a checkbox between multiple activities

I am trying to write a settings activity in an application on Eclipse. In the Main Activity, it has a button that runs a certain command. In the settings activity, I want to have a checkbox that when checked, changes what the button in the Main Activity runs when it is tapped. Right now, I have it so that when the checkbox is checked, it changes the value of a boolean and passes it to the main activity. When the button in the main activity is tapped, it checks to see if the boolean is true or false. All of this works perfectly, but when I return to the settings activity after that, the checkbox is unchecked. What should I do to have it stay checked after I go to another activity?
I believe the comment I posted is the answer:
You need to save the state of the activity. This information can be found at Saving Android Activity state using Save Instance State but in short you need to override these two methods:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
}
and
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
you can use shared preference in android to store state. take look at this
http://developer.android.com/guide/topics/data/data-storage.html#pref
and
http://www.androidhive.info/2012/08/android-session-management-using-shared-preferences/

Categories