8

RecordView画像、撮影日時、緯度/経度情報などのレコードの詳細を表示するために呼び出される下位レベルのアクティビティを持つプロジェクトに取り組んでいます。カメラを操作してジオタグを付け、exif データにアクセスしようとするのではなく、位置リスナーを実装して、画像が最初に撮影された場所 (ボタンを押したとき) を取得しようとしています。このアプローチは機能します-データベース内のレコードを正しく表示および更新するために自分の場所を取得します(後でビューに戻ると、場所が最初から表示されます)。ただし、現在の状態から戻って、RecordViewさらに 2 つ (任意の組み合わせ) を入力すると、プログラムはエラーでクラッシュしますInstanceCountViolation(完全なエラーを以下に再掲します)。の生涯メソッドをオーバーライドするとRecordViewそれぞれが呼び出されたときに表示するには、再度呼び出される前に破棄されていることがわかります。つまり、常に 1 つ以上RecordView存在するようには見えません。

だから私の質問はこれに要約されます:そのエラーはどこから来て、どうすれば修正できますか?

破壊されたことについて何か嘘をついていますか?LocationListener がどこかに座っていて、問題を引き起こしていますか? 偽のエラーを提供している可能性があるのは無関係ですか?

また、ハードコードされた恐ろしい修正を行い、RecordView許可されているインスタンスの上限を引き上げる必要がありますか? または、別のアプローチを探し続けますか (例として、PendingIntent.getBroadcast(...)呼び出しを使用して単一の更新を要求しようとしています)?

参考までに、このエラーは 3.1 のエミュレーターと実際のタブレット (Xoom、3.1) で発生しています。リスナーの更新コードをコメントアウトすると、クラッシュを回避できるようです (編集 2 : 私はそれについて間違っていたようです)。リスナーに関連するコードを以下に示します (クラス内の public メソッド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)

編集:

決めたことは2つ。

1 つ目は、Logcat がアクティビティの破棄を示している場合、RecordViewアクティビティLocationListenerが正しく切断されていることです (破棄されていますか? とにかく null です)。ただし、リスナーは墓の向こうから更新されているようです。つまり、上位レベルのアクティビティ画面で GPS 更新に関するトースト メッセージが表示され、GPS 情報が更新されたように見えることがあります。

RecordView2 つ目は、アプリ全体ではなく強制終了のように見えることです。アプリのメイン チャンクは、基本的に最小化されているようです。

編集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); 

だから今、インテントがアクティビティの作成と削除を処理する方法に問題があるのではないかと思っています。

4

2 に答える 2

0

これが古い投稿であることは知っています。この問題の解決策と説明を探している人向けです。

InstanceCountViolation 例外がある場合は、Android SDK での detectActivityLeaks チェックの実装方法に関連するアクティビティ リークまたは問題が実際に発生している可能性があることを意味します。

これが問題であるかどうかを特定するには、次の投稿をお勧めします: 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 に答える