尽管多次打开子活动会导致InstanceCountViolation被破坏

时间:2011-07-06 19:56:14

标签: android android-strictmode

我正在开发一个名为RecordView的低级活动项目,以显示记录详细信息,例如图像,拍摄日期和时间以及纬度/经度信息。我试图实现一个位置监听器来获取首次拍摄图像的位置(按下按钮),而不是试图操纵相机进行地理标记和访问exif数据。这种方法有效 - 我得到我的位置以正确显示和更新数据库中的记录(返回视图以后显示从头开始的位置)。但是,如果我退出当前RecordView然后再输入两个(任何组合),程序将崩溃并显示错误InstanceCountViolation(下面重新打印完整错误)。当我覆盖RecordView的生命周期方法以显示每个方法时,我们发现它在被再次调用之前被销毁。也就是说,在任何给定时间似乎不存在多个RecordView

所以我的问题可以归结为:错误来自何处以及如何解决?

是否存在被摧毁的谎言? LocationListener是否位于某处并导致问题?它是否与可能提供虚假错误无关的东西?

另外,我是否应该执行可怕的硬编码修复并且仅允许RecordView个实例的限制?或者继续寻找其他方法(例如我尝试使用PendingIntent.getBroadcast(...)调用请求单个更新)?

作为参考,此错误已出现在3.1和实际平板电脑的模拟器上(Xoom,3.1)。评论听众更新代码似乎可以避免崩溃(编辑2 :我似乎错了)。与侦听器相关的代码如下(可以在updateLocation类中的公共方法RecordView内找到。)

    // Listener for the update request
    LocationListener locListener = new LocationListener() {
        // Store the currentRecord so the listener can update it after return
        Record currentRecord = record;
        GeoDatabase database = data;
        @Override
        public void onLocationChanged(Location location) {
            if (location != null) {
                myLocation = location;
                Log.d(TAG, "Location pulled as " + myLocation);
                String lat = Location.convert(myLocation.getLatitude(), 
                        Location.FORMAT_SECONDS);
                String lon = Location.convert(myLocation.getLongitude(), 
                        Location.FORMAT_SECONDS);

                // Update the record values
                currentRecord.setRecordLatitude(lat);
                currentRecord.setRecordLongitude(lon);
                database.updateRecord(currentRecord);
                Log.d(TAG, "Record values now listed as "+ record.getValues());

                // Update the text boxes
                latitude.setText(lat);
                longitude.setText(lon);

                Toast.makeText(getBaseContext(),"GPS location updated",
                        Toast.LENGTH_LONG).show();
            } else {
                Log.w(TAG, "Passed location is null!");
                Toast.makeText(getBaseContext(),
                        "GPS error - unusable location", 
                        Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onProviderDisabled(String provider) {
            Toast.makeText(getBaseContext(),
                    "GPS disabled", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onProviderEnabled(String provider) {
            Toast.makeText(getBaseContext(),
                    "GPS enabled", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    };

    lm.requestSingleUpdate(LocationManager.GPS_PROVIDER, locListener, null);

完整错误:

android.os.StrictMode$InstanceCountViolation:class [program path].RecordView; instances=3; limit=2
    at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

修改

我已经确定了两件事。

首先,当Logcat显示RecordView活动的销毁时,LocationListener被正确断开(被销毁?无​​论如何都是null)。然而,听众似乎从坟墓之外更新 - 也就是说,我有时会在更高级别的活动屏幕上看到关于GPS更新的Toast消息,并且GPS信息似乎已经更新。

第二个问题是它并没有完全崩溃 - 它似乎是强制关闭RecordView而不是整个应用程序。该应用程序的主要部分似乎基本上被最小化。

编辑2:

我们最近添加了一个使用新活动的偏好设置屏幕,这与InstanceCountViolation具有相同的RecordView错误。我们已经验证在错误发生的活动中不需要更改任何内容:它只需要打开几次。我们如何从主要活动中打开子活动的示例如下:

Intent intent = new Intent(this.getActivity()
        .getApplicationContext(), RecordView.class);
Bundle extras = new Bundle();
extras.putString("tableName", "table1");
extras.putInt("id", mId);
extras.putBoolean("newRecord", false);
extras.putLong("folder_id", mFolderId);
extras.putString("type", recordList.get(mId).getTableName());
intent.putExtras(extras);

startActivity(intent); 

所以现在我想知道Intent是如何处理活动创建和删除的。

2 个答案:

答案 0 :(得分:0)

好像不应该这样,但是你试过调用

lm.removeUpdates(locListener);

取消注册听众?

答案 1 :(得分:0)

我知道这是老帖子。仅适用于那些正在寻找解决方案并解释此问题的人。

如果存在InstanceCountViolation异常,则意味着可能存在与Activity泄漏或问题有关的问题,这与在Android SDK中如何实现detectActivityLeaks检查有关。

要确定这是否有问题,我可以推荐以下帖子:Detecting leaked Activities in Android。如果您发现存在与此活动有关的对象与Android Framework无关,那么您有一个问题需要由您修复。

如果没有任何对象持有对此活动的引用与Android Framework无关,则意味着您遇到与如何实现detectActivityLeaks检查相关的问题。在这种情况下,为了解决活动失败的问题而不关闭detectActivityLeaks,您可以在调试配置中启动活动之前运行 System.gc(),如下例所示:

 if (BuildConfig.DEBUG)
 {         
     System.gc();
 }

 Intent intent = new Intent(context, SomeActivity.class);
 this.startActivity(intent);

answer中提供了更多信息。