9

Update: Thank you all for attempting to help me solve this bug. I am still unsure as to the cause, I was able to roll back to a previous commit and continue development from there. This previous commit did show the same bug, however after I commented out button.performClick() it went away. Strangely, this does not work on the most recent commit.

I still do not understand this bug and would appreciate any more assistance in helping determine the root cause. My greatest fear would be to inadvertently re-introduce it.


I have the most crazy error I have ever seen.

The OnCreate method is being called over and over again, freezing my application and giving me a slight flicker. The only solution is then to exit to the home screen and force quit the application from the settings menu.

Here is what is happening in detail:

  1. Application starts (Main Activity)
  2. Main Activity calls the Second Activity
  3. Second Activity calls onCreate, sets up as normal
  4. Second Activity randomly decides to exit onCreate <-- I think this what's happening
  5. Second Activity's onCreate gets called again. It doesn't ever return to the Main Activity.

I have run a debugger, it appears that the second activity successfully completes the onComplete/onResume sequence, then decides to exit and restart.

Has anybody ever heard of this behavior before?

I haven't noticed any exceptions being thrown. Also, in the course of debugging, I did go ahead and check those locations that you see as silent fail. (this is the older code before I littered it with print statements)

UPDATE: When attempting to stop the process, I must turn on airplane mode. This means it has something to do with this code block (Second Activity)

else if (Network.haveNetworkConnection(Login.getContext()) && Login.checkClientId())
        {...}

With no internet, it will hit the else statement and does not display this behavior.

CODE:

onResume() of the Main Activity, where I call the Second Activity:

    @Override
    public void onResume()
    {
        super.onResume();

        //Check If logged in, else go to login page
        Login.setContext(getApplicationContext());

        //Reset Notification Number
        GCMIntentService.cancelNotifications();

        /** GO TO LOGIN **/
        if(!Login.isLoggedIn())
        {
            //If user is not logged in, open login page
            System.out.println("RESUMING MAIN AND STARTING LOGIN INTENT");
            Intent intent = new Intent(ActivityMain.this, ActivityLogin.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);

        } else
        {
            Login.setupStuffOnce();
            Event.pullEvents(); //Get New Events

            //Update ListView
            updateMainFeed();
        }


    }

This is the Second Activity:

public class ActivityLogin extends Activity
{

    private String postData;
    //private Context c;
    //final Timer timer = new Timer();

    //Facebook Stuff
    private Facebook facebook = new Facebook(Config.FBAPPID);
    private AsyncFacebookRunner mAsyncRunner = new AsyncFacebookRunner(facebook);

    //Layout Stuff
    EditText username, password;
    Button loginButton, signupButton;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // Open Database
        Login.setContext(getApplicationContext());
        Database.open(getApplicationContext());
    }

    /*
     * @Override public void onPause() { s }
     */
    @Override
    public void onResume()
    {
        super.onResume();

        // shouldn't put here but oh well
        init();

        //If coming from ActivitySignup
        if(Transfer.username != null)
        {
            username.setText(Transfer.username);
            password.setText(Transfer.password);
            Transfer.password = null;
            Transfer.username = null;
            loginButton.performClick();
        }

    }

    public void init()
    {

        Login.getUserLoggedIn();
        if (Login.isLoggedIn())
        {
            //Do Any Additional Setup
            Login.setupStuffOnce();

            // If user is logged in, open main
            Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
            //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);

        } else if (Network.haveNetworkConnection(Login.getContext()) && Login.checkClientId())
        {
            // Else, Make User Login
            // Inflate Login and Present Website
            String clientid = Login.getClientId();
            System.out.println("clientid:" + clientid);
            //System.exit(0);
            postData =  "mobile=1&client_id="+Login.getClientId();



            // Inflate the view
            setContentView(R.layout.activitylogin3);

            username = (EditText) findViewById(R.id.username);
            password = (EditText) findViewById(R.id.password);



            //Inflate the Button
            loginButton = (Button) findViewById(R.id.loginButton);
            signupButton = (Button) findViewById(R.id.signupButton);

            signupButton.setOnClickListener(new View.OnClickListener()
            {

                @Override
                public void onClick(View v)
                {
                    Intent intent = new Intent(ActivityLogin.this, ActivitySignup.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
                    startActivity(intent);

                }
            });

            loginButton.setOnClickListener(new View.OnClickListener() {
                  public void onClick(View view) {

                     int res = Login.sendLogin(username.getText().toString(), password.getText().toString());

                     if(res == 202)
                     {
                         //Login Successful

                         //Check if facebooked.
                         if(Login.isFacebooked())
                         {
                             //Just go to main
                             Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
                             //Are these flags necessary?
                             //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                             startActivity(intent);
                         } else
                         {
                             //Go to facebook login page
                             //Intent intent = new Intent(ActivityLogin.this, ActivityFBLogin.class);
                             //startActivity(intent);

                             //Login via Facebook
                             doFacebook();
                         }

                     } else
                     {
                         System.out.println("Login Failed: "+res);
                         if(res == 405)
                         {
                             Toast.makeText(getApplicationContext(), "Incorrect Username/Password", Toast.LENGTH_SHORT).show();
                             password.setText("");
                         }
                         else
                             Toast.makeText(getApplicationContext(), "Network Error", Toast.LENGTH_SHORT).show(); //Not entirely true in all cases i think

                     }



                      /*Login.getUserLoggedIn();
                        if(Login.isLoggedIn())
                        {
                            Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
                            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        } else {
                            Toast.makeText(getApplicationContext(), "Please Login Above", Toast.LENGTH_SHORT).show();
                        }*/
                  }
                });



        } else
        {
            // Not Logged In and No Internet Access

            setContentView(R.layout.activitylogintext);

            EditText text = (EditText) findViewById(R.id.text);
            text.setText("No Internet Connection Detected\n requires internet to login");

            Button button = (Button) findViewById(R.id.refreshButton);

            button.setOnClickListener(new View.OnClickListener() {
                  public void onClick(View view) {
                        //Login.getUserLoggedIn();
                        if(Network.haveNetworkConnection(Login.getContext()))
                        {
                            Intent intent = new Intent(ActivityLogin.this, ActivityLogin.class);
                            //intent.setFlags();
                            startActivity(intent);
                        } else {
                            Toast.makeText(getApplicationContext(), "No Internet Access Detected", Toast.LENGTH_SHORT).show();
                        }
                  }
                });

        }

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        facebook.authorizeCallback(requestCode, resultCode, data);
    }

    public void doFacebook()
    {
         facebook.authorize(this, Config.facebookPermissions, new DialogListener() {
                @Override
                public void onComplete(Bundle values) {
                     /*SharedPreferences.Editor editor = state.edit();
                     editor.putString("access_token", facebook.getAccessToken());
                     editor.putLong("access_expires", facebook.getAccessExpires());
                     editor.commit();
                        */
                     //Input into database
                     Login.saveAccessToken(facebook.getAccessToken());
                     Login.setFB(facebook.getAccessToken());
                     //Login.sendAccessToken(facebook.getAccessToken());

                     //Intent into Main Activity
                     Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
                    //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }

                @Override
                public void onFacebookError(FacebookError error) {
                    Toast.makeText(getApplicationContext(), "Error: "+error.getErrorType(), Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onError(DialogError e) {
                    Toast.makeText(getApplicationContext(), "Error: "+e.getMessage(), Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onCancel() {}
            });
    }

    public boolean checkForUserID(Context c)
    {
        try{
            String res = Network.getUrl("www.website.com/mobile.php?got_user=1&client_id="+Login.getClientId());
            JSONObject json = JSON.constructObject(res);
            if(JSON.handleCode(json))
            {
                if(json.getString("type").equals("userid"))
                {
                    Login.setLogin(json.getString("data"));
                    return true;
                }
            }
        } catch(Exception e)
        {
            //Silent Fail
        }
        return false;
    }


}
TheRealKingK
  • 829
  • 7
  • 14
  • 6
    I think you must post some code.At least of starting activity from Main Activity. And onCreate() of second activity – MysticMagicϡ Jan 16 '13 at 05:59
  • 2
    It won't randomly decide to exit; I know of only three things that can occur 1) Exception (should be in logcat) 2) normal return (e.g. `return` or run-off-end) or 3) process is killed (which should not happen). –  Jan 16 '13 at 06:00
  • That being said, I have also heard to issues caused by passing a *negative* value to `startActivityForResult` or calling `finish` in onCreate (this won't necessarily change any of the exit points, but may lead to other interactions) –  Jan 16 '13 at 06:01
  • I haven't noticed any exceptions. I will be posting code shortly – TheRealKingK Jan 16 '13 at 06:01
  • 1
    My code-blind vote is for -- you are invoking Second Activity from the Second Activity's `onCreate` – iagreen Jan 16 '13 at 06:04
  • dude post some code .................. – Janmejoy Jan 16 '13 at 06:04
  • I have posted code from both the main and second activities – TheRealKingK Jan 16 '13 at 06:14

6 Answers6

5

I believe that the problem will be resolved if you finish your MainActivity after you call SecondActivity. The problem probably is that the onResume event is immediatelly fired when you resume your MainActivity. That is because the MainActivity was probably destroyed and recreated while it was in background. Another solution would be to save your Activity's state with onSaveInstanceState. See here for more information.

Community
  • 1
  • 1
AggelosK
  • 4,313
  • 2
  • 32
  • 37
4

Check this code in your activity:

    Button button = (Button) findViewById(R.id.refreshButton);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {

                    if(Network.haveNetworkConnection(Login.getContext()))
                    {
                        Intent intent = new Intent(ActivityLogin.this, ActivityLogin.class);
                        //intent.setFlags();
                        startActivity(intent);
                    } else {
                        Toast.makeText(getApplicationContext(), "No Internet Access Detected", Toast.LENGTH_SHORT).show();
                    }
              }
            });

Here you are calling ActivityLogin itself. That's why the onCreate() is being called again and again.

TheRealKingK
  • 829
  • 7
  • 14
MysticMagicϡ
  • 28,593
  • 16
  • 73
  • 124
  • I'll recheck this section. However since this is in the onClick() method of a button, I do not feel that this is the issue. The reason for this is that it restarts the activity in order to check for a internet connection and update the screen if required. – TheRealKingK Jan 16 '13 at 06:18
  • @TheRealKingK, Ok. And check if(!Login.isLoggedIn()) case in first activity, too. It will also restart the ActivityLogin. – MysticMagicϡ Jan 16 '13 at 06:20
  • I'm checking the button. However, it does successfully complete both the onCreate and onResume methods. Which should rule out this problem since it is located in onCreate. – TheRealKingK Jan 16 '13 at 06:26
  • 1
    @TheRealKingK `loginButton.performClick();` - won't that fire `onClick`? (I think this explanation makes sense. Start commenting out code; e.g. the `performClick` until you find the cause.) –  Jan 16 '13 at 06:29
  • There is some failed case and hence recursive calls – android2013 Jan 16 '13 at 06:29
  • @pst I will check that possibility. However they are two different variables. "loginButton" is class. "button" is local method. – TheRealKingK Jan 16 '13 at 06:36
  • ShreyaShah I have ruled out this possibility. @pst I have ruled out performClick() as well. I appreciate your help, this problem is driving me nuts! – TheRealKingK Jan 16 '13 at 06:50
2

I had a similar problem once. The problem occurred because I made configuration changes without declaring them in the android:configChanges attribute of the <activity> tag (and hence it recreates itself the whole time).

For example, if you change the locale manually you need to add locale to android:configChanges!

Mokus
  • 3,339
  • 1
  • 24
  • 30
  • I was really hoping that it was this. But after testing every single possible case I could catch, I'm forced to conclude it wasn't. But thanks for the information – TheRealKingK Jan 26 '13 at 00:43
  • Just to make sure: Do you change the locale? If yes, do you test on 4.2? If yes, you must add layoutDirection (that was the problem in my case) in addition to locale to the configChanges! – Mokus Jan 26 '13 at 08:12
  • I could not add layoutDirection, probably because it was added in API 17. It did not seem to recognize that flag as valid. I am testing for API 8 (2.2). – TheRealKingK Jan 26 '13 at 20:36
2

I think your main problem is with you onResume function as it gets called each time it comes back into view (eg: you start second activity, finish it, main activity onResume is called again. If you finish your second activity (or it quietly crashes for some reason) you will go back to your mainActivity and call onResume (which will start the cycle all over again).

Now i dont know if you are finishing activity 2 somehow but I would check that.

EDIT: ALso I would put some logcats here

if (Login.isLoggedIn())
{
      //Do Any Additional Setup
      Login.setupStuffOnce();

      // If user is logged in, open main
      Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
      //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
      Log.i("Some Tag", "Starting Main Activity From Activity 2");
      startActivity(intent);

}

The above adding of the log.i will allow you to know if this is where the error happens, and you can go from there.

Raigex
  • 1,205
  • 12
  • 32
2

It seems to me there is a good chance for endless cycling here if Login is not properly shared between the activities, causing Login.isLoggedIn() to return true in ActivityLogin but false in ActivityMain.

A few critical factors are where your Login object is located, is it static, how is it referenced between Activities? It is entirely possible that ActivityMain is being destroyed while ActivityLogin is active; storing the Login data in SharedPreferences or a database, or otherwise persisting it is important. How does isLoggedIn() resolve (determine its return value?)

Suggestion 1: Consider making use of the Singleton pattern (if you haven't already.) Suggestion 2: While discouraged, you could store Login at the Application level. Suggestion 3: You can try using Intent.FLAG_ACTIVITY_SINGLE_TOP to reduce the likelyhood of a new ActivityMain being created - which might not have access to Login, again depending on how you have it stored.

ActivityMain

onResume() {
    if(!Login.isLoggedIn()) {
        /* Not logged in, launch ActivityLogin! */
        Intent intent = new Intent(ActivityMain.this, ActivityLogin.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);

ActivityLogin

onResume() { /* ... */ init(); }

init() {
    Login.getUserLoggedIn();
    if (Login.isLoggedIn()) {
        /* Internet - launch ActivityMain! */
        Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); // <--- suggested addition
        startActivity(intent);
    else if (Network.haveNetworkConnection(Login.getContext()) && Login.checkClientId()) {
        /* No internet, the user was unable to login. */
    }
Community
  • 1
  • 1
CodeShane
  • 6,480
  • 1
  • 18
  • 24
0

I had similar problem where the activity would be recreated all the time. Re-installing the app wouldn't help, but restarting the phone did the job.