Opening a sub-activity several times causes an Ins

2019-04-06 11:47发布

I'm working on a project that has a lower level activity called RecordView to display record details such as an image, the date and time it was taken, and the latitude/longitude information. Rather than trying to manipulate the camera to geotag and access exif data I'm trying to implement a location listener to get the location where the image is first taken (on the button press). This approach works - I get my location to display and update the record in the database correctly (returning to the view later displays the location from the beginning). However, if I back out of the current RecordView and then enter two more (any combination) the program will crash with the error InstanceCountViolation (full error reprinted below). When I override the lifetime methods of RecordView to display when each is called we find that it is destroyed before being called again. That is to say, it doesn't appear that more than a single RecordView exists at any given time.

So my question boils down to this: where is that error coming from and how can I fix it?

Is something lying about being destroyed? Is the LocationListener sitting around somewhere and causing problems? Is it something unrelated that might be providing a bogus error?

Also, should I do the horrible hard coded fix and just up the limit of RecordView instances allowed? Or continue hunting for another approach (as an example I'm attempting to request a single update using a PendingIntent.getBroadcast(...) call)?

For reference this error has appeared on the emulator for 3.1 and on an actual tablet (a Xoom, 3.1). Commenting out the listener update code seems to avoid the crash (EDIT 2: I appear to have been wrong about that). The code as it relates to the listener is below (it can be found inside a public method updateLocation inside the RecordView class).

    // 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);

The full error:

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

EDIT:

Two things I've determined.

The first is that when Logcat shows the destruction of the RecordView activity the LocationListener is correctly disconnected (destroyed? It's null anyway). However the listener seems to update from beyond the grave as it were - that is, I sometimes see my Toast message about a GPS update on the higher level activities screen and the GPS information appears to have been updated.

The second is that it isn't exactly crashing per say - it appears to be Force Closing the RecordView rather than the entire app. The main chunk of the app seems to just basically be minimized.

EDIT 2:

We recently added a preference screen using a new activity and this has the same InstanceCountViolation error as the RecordView. We've verified that nothing has to be changed in the activity for the error to occur: it only needs to be opened a few times. An example of how we open our sub-activities from the main activities is below:

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

So now I'm wondering if there's a problem in how the Intent is handling activity creation and deletion.

2条回答
兄弟一词,经得起流年.
2楼-- · 2019-04-06 11:56

It seems like it shouldn't be needed, but have you tried calling

lm.removeUpdates(locListener);

to un-register the listener?

查看更多
Luminary・发光体
3楼-- · 2019-04-06 12:00

I know that this is old post. Just for guys who is looking for solution and explanation to this problem.

In case there is InstanceCountViolation exception it means that there can be real with Activity leak or problem which is related to how detectActivityLeaks check is implemented in Android SDK.

To identify if this is a problem I can recommend the following post: Detecting leaked Activities in Android. If you will see that there are objects holding a reference to this activity which don't related to Android Framework then you have a problem which should be fixed by you.

In case there are no objects holding a reference to this activity which don't related to Android Framework than it means that you encountered with the problem related to how detectActivityLeaks check is implemented. In this case to fix the problem with failed activity without turning off detectActivityLeaks you can simply run System.gc() before starting activity in debug configuration like in the following example:

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

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

More information are available in this answer.

查看更多
登录 后发表回答