【问题标题】:Android activity recreate itselfAndroid Activity 重新创建自己
【发布时间】:2017-10-18 14:49:17
【问题描述】:

我的应用程序通常可以正常工作,直到我在特定设备上遇到奇怪的问题。 App中有2个活动。在 ActivityA 内启动 ActivityB 后,ActivityA 启动没有问题。但是,在我返回 ActivityA 并按下硬件按钮或调用 finish();在 ActivityB 的 closeButton 内部,ActivityA 会重新加载自身。它再次触发 onCreate() 并重新加载其所有内容。而且我不会改变手机的方向。这种奇怪的行为只出现在超过 1.000 次下载应用程序的 15 部手机中。

此问题仅出现在 Galaxy S3 Android OS 4.1.2 上。这也很奇怪。

你知道为什么会这样吗?

当我像这样在按钮监听器中启动一个新 Activity 时:

ActivityA.java (MesajlarListViewActivity)

    public class MesajlarListViewActivity extends TrackedActivity {

    Context context = null;

    // contacts JSONArray
    JSONArray contacts = null;

    ArrayList<Message> productArray = new ArrayList<Message>();

    private ProductAdapter adapter;
    private ListView productList;
    private Runnable viewOrders;
    private HoloProgressIndicator profilInfoProgress = null;

    ImageView kapatButton = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mesajlar_list);

        context = this;

        kapatButton = (ImageView) findViewById(R.id.kapat_button);
        /* kapat button onclick listener. */
        // =================================================================================================================
        kapatButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view)
            {
                // Set vibration on touch.
                KnetGenericClass.vibratePhone(context);

                finish();
            }

        });
        // =================================================================================================================
        //Progress bar.
        profilInfoProgress = (HoloProgressIndicator) findViewById(R.id.profil_info_progress);

        // cheking internet connectivity.
        if(KnetGenericClass.checkInternetConnection(context))
        {
            // start task!
            /* internet var ise web service baglantisi kurmaya baslayabiliriz. */
            startActivityIndicatorWithThread();
        }
        else
        {
            KnetGenericClass.printErrorMessage(context, "Bağlantı Hatası",
                    "Lütfen internet bağlantınızı kontrol ediniz.");
        }

        productList = (ListView) findViewById(R.id.product_list);
        adapter = new ProductAdapter(this, R.layout.message_row, productArray);
        productList.setAdapter(adapter);

        // When user click a view on list view new page is appearing.
        productList.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)
            {

                // Set vibration on touch.
                KnetGenericClass.vibratePhone(context);

                /* Navigate to message detay activity class with ilan ID. */
                Intent myIntent = new Intent(view.getContext(), MesajDetayActivity.class);
                myIntent.putExtra("messageID", productArray.get(position).getId());
                startActivity(myIntent);

                // setting image of clicked message null.
                RelativeLayout relativeLayout = (RelativeLayout) view;
                ImageView unreadedImageView = (ImageView) relativeLayout.findViewById(R.id.unreaded_image);
                unreadedImageView.setImageResource(0);
            }
        });
    }

    public class ProductAdapter extends ArrayAdapter<Message> {
        ArrayList<Message> items;

        public ProductAdapter(Context context, int textViewResourceId, ArrayList<Message> objects) {
            super(context, textViewResourceId, objects);
            this.items = objects;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {
            if(convertView == null)
            {
                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = vi.inflate(R.layout.message_row, null);
            }

            ImageView unreadedImageView = (ImageView) convertView.findViewById(R.id.unreaded_image);
            TextView productName = (TextView) convertView.findViewById(R.id.product_name);
            TextView productDetail = (TextView) convertView.findViewById(R.id.product_detail);
            // TextView productDate = (TextView)
            // convertView.findViewById(R.id.product_date);
            TextView sentDate = (TextView) convertView.findViewById(R.id.product_date);

            productName.setText(items.get(position).getSender());
            productDetail.setText(items.get(position).getTitle());
            // String bodyNoHTML = items.get(position).getBody();

            if(items.get(position).getIsReaded())
            {
                unreadedImageView.setImageResource(0);
            }
            else
            {
                unreadedImageView.setImageResource(R.drawable.bluedot);
            }

            String dateStr = items.get(position).getSentDate();
            try
            {
                sentDate.setText(dateStr.substring(6, 8) + "." + dateStr.substring(4, 6) + "." + dateStr.substring(0, 4)
                        +" "+dateStr.substring(8, 10)+":"+dateStr.substring(10, 12));
            }
            catch(Exception e)
            {
                sentDate.setText("");
            }


            return convertView;
        }

    }// @end of product adapter class.

    /* web service'e baglanti kurulan methodu threadin icerisinde cagiriyoruz. */
    public void startActivityIndicatorWithThread()
    {
        // ==============================================================================================
        // getting ilan details into arraylist.
        // setting up thread.
        viewOrders = new Runnable() {
            public void run()
            {
                getMessageListFromWebService();
            }
        };
        Thread thread = new Thread(null, viewOrders, "MagentoBackground");
        thread.start();
        profilInfoProgress.start();
        // ==============================================================================================
        // @end of the thread declaration.
    }

    public void getMessageListFromWebService()
    {
        // Creating JSON Parser instance
        JSONParser jParser = new JSONParser(context);

        // getting JSON string from URL
        JSONArray jsonArray = jParser.getAuthorizedInfoFromUrlToJSONArray(
                WebServiceInfo.getKnetWebServiceLink()+"/API/Member/GetInboxMessageList", MainActivity.getAccessToken());

        // if json is null then there is a problem.
        if(jsonArray == null)
        {
            // if json array is null then print error message.
            runOnUiThread(showAlertMessage);
            runOnUiThread(returnRes);
            return;
        }

        try
        {
            // Eger aranilan kritere gore ilan yok ise hata mesaji basiyoruz.
            if(jsonArray.length() == 0)
            {
                // if json array is null then print error message.
                runOnUiThread(showAlertIlanYokMessage);
                runOnUiThread(returnRes);
                return;
            }

            // looping through All Contacts
            for (int i = 0; i < jsonArray.length(); i++)
            {
                JSONObject c = jsonArray.getJSONObject(i);

                // Storing each json item in variable
                // String id = c.getString(TAG_ID);
                String id = c.getString("Id");
                String sender = c.getString("Sender");
                // String body = c.getString("Body");
                String title = c.getString("Title");
                String sentDate = c.getString("SentDate");
                Boolean isReaded = c.getBoolean("IsRead");

                Message productObject = new Message(id, sender, "", title, sentDate, isReaded);
                productArray.add(productObject);
            }
        }
        catch (Exception e)
        {
            Log.e("BACKGROUND_PROC", e.getMessage());
        }
        runOnUiThread(returnRes);
    }


    // @end of thread.
    private Runnable returnRes = new Runnable() {

        public void run()
        {
            profilInfoProgress.stop();
            adapter.notifyDataSetChanged();// refreshing data over adapter in
                                            // list view.
        }
    };

    // @end of thread.
    private Runnable showAlertMessage = new Runnable() {

        public void run()
        {
            // Bu hata genelde linkteki problemden, servera ulasilamamasindan
            // veya timeouttan meydana gelir.
            Toast.makeText(getApplicationContext(),
                    "Mesajlar alınamadı lütfen daha sonra tekrar deneyiniz.", 
                    Toast.LENGTH_LONG).show();
        }
    };

    private Runnable showAlertIlanYokMessage = new Runnable() {

        public void run()
        {
            // Bu hata aranilan kelimeye gore ilan bulunamazsa gelir.
            Toast.makeText(getApplicationContext(),
                    "Mesajlar bulunamadı.", 
                    Toast.LENGTH_LONG).show();
        }
    };

}

================================================ ==========================

ActivityB.java (MesajDetayActivity.java)

public class MesajDetayActivity extends TrackedActivity {

    private HoloProgressIndicator profilInfoProgress = null;

    TextView titleTextView = null;
    TextView senderTextView = null;
    TextView dateTextView = null;
    WebView bodyWebView = null;

    Message messageObject = null;

    String messageID = null;

    ImageView kapatButton = null;

    Context context;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mesajdetaylari);

        context = this;

        kapatButton = (ImageView) findViewById(R.id.kapat_button);
        /* kapat button onclick listener. */
        // =================================================================================================================
        kapatButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view)
            {
                // Set vibration on touch.
                KnetGenericClass.vibratePhone(context);

                finish();
            }

        });
        // =================================================================================================================
        //Progress bar.
        profilInfoProgress = (HoloProgressIndicator) findViewById(R.id.profil_info_progress);

        Bundle extras = getIntent().getExtras();
        if(extras != null)
        {
            messageID = extras.getString("messageID");
        }

        titleTextView = (TextView) findViewById(R.id.title_textview);
        senderTextView = (TextView) findViewById(R.id.sender_textview);
        dateTextView = (TextView) findViewById(R.id.date_textview);
        bodyWebView = (WebView) findViewById(R.id.mesaj_webView);

        // Show the ProgressDialog on this thread
        profilInfoProgress.start();

        // Start a new thread that will download all the data
        new MakeItTask().execute();

    }

    // Async task.
    private class MakeItTask extends AsyncTask<String, Void, Object> {
        protected Object doInBackground(String... args)
        {
            Log.i("MyApp", "Background thread starting");

            // This is where you would do all the work of downloading your data
            // getting message detay
            /* connect to web service */
            getMessageDetayFromWebService();

            return null;
        }

        protected void onPostExecute(Object result)
        {
            // Pass the result data back to the main activity
            // TakipListeActivity.this.data = result;
            try
            {
                titleTextView.setText("Başlık: " + messageObject.getTitle());
                senderTextView.setText("Gönderen: " + messageObject.getSender());
                dateTextView.setText("Tarih: " + messageObject.getSentDate().substring(6, 8) + "."
                        + messageObject.getSentDate().substring(4, 6) + "."
                        + messageObject.getSentDate().substring(0, 4));

                if(!messageObject.getBody().contains("img"))
                {
                    bodyWebView.loadDataWithBaseURL(null, messageObject.getBody(), "text/html", "UTF-8", null);
                }

            }
            catch (Exception e)
            {
                Log.e(CONNECTIVITY_SERVICE, "Mesaj Detayi bilgileri basilamadi.");
            }

            profilInfoProgress.stop();
        }
    }

    /* web service'e baglanti kurulan methodu threadin icerisinde cagiriyoruz. */
    public void getMessageDetayFromWebService()
    {
        // Creating JSON Parser instance
        JSONParser jParser = new JSONParser(context);

        // getting JSON string from URL
        JSONObject jsonObject = jParser.getAuthorizedInfoFromUrlToJSONObject(
                WebServiceInfo.getKnetWebServiceLink()+"/API/Member/GetInboxMessage/" + messageID, MainActivity.getAccessToken());

        // if json is null then there is a problem.
        if(jsonObject == null)
        {
            return;
        }

        try
        {
            String title = jsonObject.getString("Title");
            String id = jsonObject.getString("Id");
            String sender = jsonObject.getString("Sender");
            String date = jsonObject.getString("SentDate");
            String body = jsonObject.getString("Body");

            messageObject = new Message(id, sender, body, title, date, true);

        }
        catch (Exception e)
        {
            Log.e("BACKGROUND_PROC", e.getMessage());
        }

    }// @end of getIlanDetayFromWebService.

}

编辑:不仅这两个活动有这个问题,所有活动在某些手机上的行为都相同。

【问题讨论】:

  • ActivityA 重新创建自己有什么问题?有可能发生..
  • 每次回到ActivityA,它都会重新创建自己。自动重启的应用程序可能会让用户感到厌烦。我们得到的关于这个问题的报告不是很多用户。
  • 我还是不明白,活动娱乐不需要那么烦人。我认为 ActivityA 被重新创建的唯一可能性是它之前已经被销毁了。
  • 覆盖ActivityAonDestroy方法,在里面放一个断点,看看这个方法是否被调用,并检查它是如何被调用的堆栈跟踪。
  • 尝试使用@Override public void onBackPressed() { this.finish();返回; } 在活动 B??

标签: android mobile galaxy


【解决方案1】:

检查设置 > 系统 > 开发者选项 > 下是否不保留活动 >应用程序是否启用。

【讨论】:

  • 谢谢你告诉我原因。有时进入内部会让你的事情变得更加复杂。我不相信我怎么看不到这一点并浪费时间尝试修复代码。
  • 谢谢你说的原因,我完全不知道原因。
  • 它有效,但为什么会在特定活动中发生这种情况?
【解决方案2】:

Activity 文档 (http://developer.android.com/reference/android/app/Activity.html) 对后台 Activity 的生命周期进行了如下说明:

后台活动(对用户不可见且已暂停的活动)不再重要,因此系统可以安全地终止其进程以回收其他前台或可见进程的内存。如果它的进程需要被杀死,当用户导航回活动(使其再次在屏幕上可见)时,将使用它之前在 onSaveInstanceState(Bundle) 中提供的 savedInstanceState 调用它的 onCreate(Bundle) 方法,以便它可以以与用户上次离开时​​相同的状态重新启动。

换句话说,ActivityA 可能会或可能不会在 ActivityB 处于活动状态时被操作系统销毁,因此必须在代码中处理这种情况。如果 ActivityA 已被销毁,当用户在 ActivityB 中按下返回按钮时,将调用 onCreate(Bundle)。

【讨论】:

  • 感谢 Mads,但在后台活动时不会发生这种情况。我知道如何处理内存不足的活动。这发生在 UI 出现在屏幕上时。
  • 我仍然认为这个答案适用。 UI 在屏幕上,但它显示的是 ActivityB,对吧?如果 ActivityA 没有显示在屏幕上,它会被暂停,从而被认为是可以被操作系统销毁的后台 Activity。
  • 是的,可能是因为内存不足的问题。但是,自动重启的应用程序仍然会让用户感到厌烦。处理 onSaveInstanceState 和 onRestoreInstanceState 不是我的问题的解决方案。因为,每次返回到堆栈上的活动都会再次重新启动活动。
  • 我同意,重新启动的应用程序可能会让用户感到烦恼。但是,我确实认为,无论如何你都应该在代码中处理这个问题,因为由于活动生命周期,它可能发生在任何人身上(不仅仅是那些遇到问题的人,每次都会发生)。对于那些在每次返回活动时遇到问题的人来说,这听起来更像是他们的操作系统中的一个错误,或者他们的设备内存极低。如果应用程序像您问题中的简单示例一样工作,那么绝对不应该在每次返回 Activity 时发生。
  • @OzBoz ,您可以尝试一些方法来测试这个答案。最简单的方法是覆盖 Activity 中的onLowMemory 方法,并在内存不足时打印一些内容。还可以尝试向onDestroy 添加一些内容。您应该能够将状态保存在onSaveInstanceState - 但您也可以将android:largHeap="true" 添加到您的Android Manifest。这不能保证任何事情 - 但它可能会有所帮助。您也可以在新的视图对象中设置动画,并将所有新的 Activity 代码移动到旧的 Activity 中。这不是最好的方法,但会是一种适当的解决方法。
【解决方案3】:

有一个名为“不保留活动”的 Android 开发者设置。此选项的描述是“用户离开后立即销毁所有活动”。这听起来很好地描述了您所看到的内容,并且由于您只在少数手机上看到它,因此认为这是由非默认系统设置引起的想法似乎是合理的。

理想情况下,您的应用在这种情况下仍然可以正常工作,即使不是最理想的。但如果此设置对您的应用来说是个问题,您可能希望为您的用户记录此问题。

【讨论】:

  • 这也是正确答案,但是很抱歉没有给 +50。非常感谢。
【解决方案4】:

您是否尝试过更改 Android Manifest 中的 launchmode?尝试将此添加到您的 Activity 声明中:

android:launchMode="singleTask"

接下来,尝试使用startActivityForResult,而不是startActivity。这将强制 Activity A 在 Activity B 完成时调用其 onActivityResult(int, int, Intent) 方法 - 这可能会跳过对 onCreate 的此(错误)调用。然后,在 Activity A 中,实现该方法来做某事(例如打印调试语句):

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    Log.i("Test", "Did this work???");
    //TODO send notification to your server to verify this works?
}

【讨论】:

  • 1.android:launchMode="singleTask" 不会改变任何东西。 2.是的。它可以工作,但 Activity 仍然会重新创建自己。
  • 我遇到了同样的问题,使用 startActivityForResult 解决了它。我在第一个活动中使用了“startActivity”,然后是“finish()”来停止它。现在,我在第一个活动中使用“startActivityForResult()”,在第二个活动返回后在“onActivityResult”中使用“finish()”。似乎工作得很好。我认为这是有道理的,因为 android 的生命周期模型假设您启动活动并返回第一个活动。如果那不存在,并且第二个活动完成,屏幕上没有任何活动,我可以理解为什么 Android 会尝试通过重新启动活动来“让事情变得正确”。
【解决方案5】:

我认为这种行为没有任何问题。

如果您希望保留ActivityA 的状态,请使用onSaveInstanceStateonRestoreInstanceState 方法。有关详细信息,请参阅http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle 的活动生命周期。

另请参阅https://stackoverflow.com/a/10492967/332210 以获得更深入的了解。

【讨论】:

    【解决方案6】:

    您可以尝试在onCreate() 中提供您的布局,然后在onStart() 中完成其余工作??如果它有效??

    喜欢:

     public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.show);
       }
    

          @Override
           protected void onStart() {
           // TODO Auto-generated method stub
        super.onStart();
        Log.i(TAG, "On Start .....");
    
          }
    

    Activity Lifecycle

    【讨论】:

      【解决方案7】:

      也许你应该使用

      Intent startIntent = new Intent(view.getContext(), ActivityB.class); 
      startActivity(startIntent); 
      finish() ;
      

      Intent startIntent = new Intent(view.getContext(), ActivityA.class); 
      startActivity(startIntent); 
      finish() ;
      

      每次后退或前进。

      【讨论】:

      • 我猜你误会了。我不是在问如何重新创建 Activity。我在问如何停止自我重建。
      【解决方案8】:

      它也遇到了确切的问题并通过在manifestactivity 中使用android:launchMode="standard" 解决了问题。

      【讨论】:

      • 我将 android:launchMode="standard" 放在每个活动上,并将其放在 下,但问题仍然没有消失。
      【解决方案9】:

      在 Activity A 中重写 onStart() 和 onResume 方法并检查问题是否仍然存在。如果可能,请在此处提供您的活动 A 和 B 代码。

      【讨论】:

      • 请在这两个活动上覆盖 onResume。
      • 我在两个 Activity 中都覆盖了 onResume、onStart 和 onStop,但没有任何改变。
      • 这里的 TrackedActivity 是什么?尝试删除它并仅将 Acitivity 与 onResume 和其他方法放在代码中
      • TrackedActivity 是 Activity 的子类。它是 GoogleAnalytics 框架的一部分,在这里用于获取分析报告。我删除它并在有故障的设备上再次编译,它仍然给出同样的问题。
      【解决方案10】:

      Activity A 使用布局 R.layout.mesajlar_list

      Activity B 使用布局 R.layout.mesajdetaylari

      但两者都有以下代码行:

      kapatButton = (ImageView) findViewById(R.id.kapat_button);
      

      R.id.kapat_button 在哪个布局中?在不同的布局中使用相同的 id 是一件非常冒险的事情。我不能保证它会导致您所看到的,但它可能会导致奇怪的行为。

      【讨论】:

        【解决方案11】:

        我认为不是因为内存的限制。

        https://www.box.com/s/7pd0as03bb8wwumuc9l9

        您应该测试这两个活动并检查它是否也在此示例中发生。也请分享您的 AndroidManifest.xml 文件内容,这将有助于调试。

        【讨论】:

          【解决方案12】:

          我最近遇到了这个问题,这让我很生气。我认为该问题围绕 2 个选项解决方案进行检查,但无用。

          关于此处更正的“不保留活动”设置,我使用此代码检查它是否可选检查(我的测试设备基于版本 2.3.5 自定义并且不显示此选项):

          private boolean isAlwaysFinishActivitiesOptionEnabled() {
              int alwaysFinishActivitiesInt = 0;
              if (Build.VERSION.SDK_INT >= 17) {
                  alwaysFinishActivitiesInt = Settings.System.getInt(getApplicationContext().getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0);
              } else {
                  alwaysFinishActivitiesInt = Settings.System.getInt(getApplicationContext().getContentResolver(), Settings.System.ALWAYS_FINISH_ACTIVITIES, 0);
              }
          
              if (alwaysFinishActivitiesInt == 1) {
                  return true;
              } else {
                  return false;
              }
          }
          

          在我的情况下,结果检查是错误的。我也在运行应用程序时检查了内存,但没有任何反应。

          【讨论】:

            【解决方案13】:

            您可以在清单中使用android:launchMode="singleTop"

            <activity
                    android:name=".MainActivity"
                    android:label="@string/app_name"
                    android:launchMode="singleTop"
                    android:configChanges="orientation|keyboardHidden|screenSize"
                    android:theme="@style/AppTheme.NoActionBar">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN"/>
            
                        <category android:name="android.intent.category.LAUNCHER"/>
                    </intent-filter>
                </activity>
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-02-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-03-01
              • 1970-01-01
              相关资源
              最近更新 更多