8

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

所以我的问题归结为:该错误来自哪里,我该如何解决?

被毁坏了有什么谎言吗?LocationListener 是否坐在某个地方并导致问题?是不是一些不相关的东西可能会提供虚假错误?

另外,我是否应该进行可怕的硬编码修复并仅提高允许的RecordView实例限制?还是继续寻找另一种方法(例如,我试图通过PendingIntent.getBroadcast(...)调用请求单个更新)?

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

    // 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它被正确断开(被破坏了?无论如何它都是空的)。然而,听众似乎是从坟墓之外更新的——也就是说,我有时会在更高级别的活动屏幕上看到关于 GPS 更新的 Toast 消息,并且 GPS 信息似乎已经更新。

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

编辑2:

我们最近添加了一个使用新活动的首选项屏幕,这InstanceCountViolationRecordView. 我们已经验证,在 Activity 中无需进行任何更改即可发生错误:只需打开几次即可。下面是我们如何从主要活动中打开子活动的示例:

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 如何处理活动创建和删除是否存在问题。

4

2 回答 2

0

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

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

为了确定这是否是一个问题,我可以推荐以下帖子:Detecting leaked Activities in Android。如果您会看到一些对象持有对此活动的引用,而这些引用与 Android 框架无关,那么您遇到的问题应该由您解决。

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

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

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

此答案中提供了更多信息。

于 2014-08-11T21:29:21.007 回答
0

似乎不需要它,但你试过打电话吗

lm.removeUpdates(locListener);

取消注册听众?

于 2013-05-27T15:29:37.673 回答