OnCreate方法不断被重复调用

9

更新:感谢大家尝试帮助我解决这个bug。我仍然不确定原因,但我能够回滚到以前的提交并从那里继续开发。这个之前的提交也显示了相同的bug,但是在我注释掉 button.performClick() 之后,它消失了。奇怪的是,这在最近的提交上不起作用。

我仍然不理解这个bug,如果有任何更多的帮助确定根本原因,我将不胜感激。我的最大担心是无意中重新引入它。


我遇到了一个最疯狂的错误。

OnCreate方法一遍又一遍地被调用,导致我的应用程序冻结并出现轻微的闪烁。唯一的解决方案是退出到主屏幕,并从设置菜单强制退出应用程序。

以下是详细情况:

  1. 应用程序启动(主Activity)
  2. 主Activity调用第二个Activity
  3. 第二个Activity调用onCreate,像往常一样进行设置
  4. 第二个Activity随机决定退出onCreate <-- 我认为这就是正在发生的事情
  5. 第二个Activity的onCreate再次被调用。它永远不会返回到主Activity。

我运行了调试器,似乎第二个Activity成功完成了onComplete/onResume序列,然后决定退出并重新启动。

有人听说过这种行为吗?

我没有注意到任何异常被抛出。此外,在调试过程中,我确实检查了你看到的那些静默失败位置。(这是在我将其填满打印语句之前的旧代码)

更新:当尝试停止进程时,我必须打开飞行模式。这意味着它与这个代码块有关(第二个Activity)

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

没有网络的情况下,它会触发else语句并且不显示这种行为。
代码: 在主Activity的onResume()函数中,我调用了第二个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();
        }


    }

这是第二个活动:
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;
    }


}

6
我认为你必须发布一些代码。至少是从主活动开始的活动和第二个活动的onCreate()函数。 - MysticMagicϡ
2
它不会随机决定退出;我只知道可能发生的三件事情:1)异常(应该在logcat中)2)正常返回(例如return或运行到结尾)或3)进程被杀死(这不应该发生)。 - user166390
话虽如此,我也听说过通过向startActivityForResult传递负值或在onCreate中调用finish引起的问题(这不一定会改变任何退出点,但可能会导致其他交互)。 - user166390
我还没有注意到任何异常。我很快会发布代码。 - TheRealKingK
1
我的代码盲投票是给你的 - 你正在从第二个Activity的onCreate中调用第二个Activity。 - iagreen
显示剩余2条评论
6个回答

5

我相信,如果你在调用SecondActivity之后完成MainActivity,问题将会得到解决。问题可能是当你恢复MainActivity时,onResume事件立即触发。这是因为MainActivity可能在后台被销毁并重新创建。另一个解决方案是使用onSaveInstanceState保存Activity的状态。有关更多信息,请参见此处


我很快就会测试这个。但我认为它根本没有返回到MainActivity。 - TheRealKingK
不幸的是,在主函数中调用finish()并没有解决这个问题。 - TheRealKingK

4

请在您的活动中检查此代码:

    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();
                    }
              }
            });

你正在调用ActivityLogin本身。 这就是为什么onCreate()会被不断调用的原因。


我会重新检查这个部分。但是由于这是在按钮的onClick()方法中,我不认为这是问题所在。 原因是它重新启动活动以检查是否有网络连接,并在需要时更新屏幕。 - TheRealKingK
@TheRealKingK,好的。请检查第一个活动中的if(!Login.isLoggedIn())语句,它也会重新启动ActivityLogin。 - MysticMagicϡ
1
@TheRealKingK loginButton.performClick(); - 这不会触发 onClick 吗?(我认为这个解释很有道理。从注释掉的代码开始;例如,注释掉 performClick 直到找到原因。) - user166390
有一些失败的情况,因此进行了递归调用。 - android2013
ShreyaShah 我已经排除了这种可能性。 @pst 我也排除了 performClick()。 非常感谢您的帮助,这个问题让我抓狂! - TheRealKingK
显示剩余2条评论

2
我认为你的主要问题在于onResume函数,因为每次它重新进入视图时都会被调用(例如:你启动第二个活动,完成它,主活动的onResume再次被调用。如果你完成第二个活动(或它因某些原因默默崩溃),你将回到主活动并调用onResume(这将重新开始循环)。
现在我不知道你是否以某种方式完成了第二个活动,但我会检查一下。
编辑: 此外,我会在这里放一些日志记录。
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);

}

在上面添加log.i将使您知道错误是否发生在此处,然后您可以从那里开始。


正如我之前所提到的,它从不返回到Main.onResume()。我已经彻底检查了这种行为。 - TheRealKingK

2
如果 Login 没有正确地在活动之间共享,导致 Login.isLoggedIn()ActivityLogin 中返回 true,但在 ActivityMain 中返回 false,那么这里就很可能出现无尽循环的情况。
关键因素有几个:你的 Login 对象位于哪里,它是否是静态的,在活动之间如何引用?完全有可能在 ActivityMain 活动处于激活状态时被销毁;将登录数据存储在 SharedPreferences 或数据库中,或以其他方式持久化是很重要的。 isLoggedIn() 如何解决(确定其return值)?
建议1:考虑使用单例模式(如果尚未使用)。 建议2:虽然不鼓励,但可以将 Login 存储在 Application 级别上。 建议3:可以尝试使用 Intent.FLAG_ACTIVITY_SINGLE_TOP 来减少创建新的 ActivityMain 的可能性——这可能导致它无法访问 Login,具体取决于你如何存储它。

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. */
    }

2

我曾经遇到过类似的问题。这个问题是因为我在没有在<activity>标签的android:configChanges属性中声明配置更改(因此它一直在重新创建自己)。

例如,如果您手动更改语言环境,则需要将locale添加到android:configChanges中!


我真的很希望是这样的。但在测试了我能够捕捉到的每一个可能的情况之后,我不得不得出结论,它并不是这样的。但还是谢谢你提供的信息。 - TheRealKingK
只是为了确保:您是否更改了语言环境?如果是,您是否在4.2上进行了测试?如果是,您必须在configChanges中添加layoutDirection(这是我的问题)以及语言环境! - Mokus
我无法添加layoutDirection,可能是因为它是在API 17中添加的。它似乎没有将该标志识别为有效标志。我正在测试API 8(2.2)。 - TheRealKingK

0
我曾经遇到过类似的问题,即活动一直被重新创建。重新安装应用程序没有帮助,但是重启手机解决了这个问题。

哇!我很高兴人们仍然在查看我的帖子!不幸的是,我尝试重新启动手机没有取得成功。 - TheRealKingK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接