2

我不知道为什么,但似乎使用较新版本的 android 我从来没有得到有用的堆栈跟踪。他们似乎没有回到足够远的地方让我找到导致崩溃的代码行。例子:

08-17 09:33:38.449: E/AndroidRuntime(14389): FATAL EXCEPTION: main
08-17 09:33:38.449: E/AndroidRuntime(14389): java.lang.RuntimeException: Unable to resume activity {com.evidence/com.evidence.activity.EvidenceList}: android.database.StaleDataException: Attempted to access a cursor after it has been closed.
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2567)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2595)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1183)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.os.Looper.loop(Looper.java:137)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.app.ActivityThread.main(ActivityThread.java:4575)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at java.lang.reflect.Method.invokeNative(Native Method)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at java.lang.reflect.Method.invoke(Method.java:511)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at dalvik.system.NativeStart.main(Native Method)
08-17 09:33:38.449: E/AndroidRuntime(14389): Caused by: android.database.StaleDataException: Attempted to access a cursor after it has been closed.
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:75)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.database.BulkCursorToCursorAdaptor.requery(BulkCursorToCursorAdaptor.java:144)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.database.CursorWrapper.requery(CursorWrapper.java:186)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.app.Activity.performRestart(Activity.java:4505)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.app.Activity.performResume(Activity.java:4531)
08-17 09:33:38.449: E/AndroidRuntime(14389):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2557)
08-17 09:33:38.449: E/AndroidRuntime(14389):    ... 10 more

有没有办法获得未显示的“另外 10 个”?

public class EvidenceList extends StandardMenuActivity implements AdapterView.OnItemClickListener {

    private ApplicationSettings settings;
    private Context mContext;
    private Cursor mCursor;
    private Uri mData;

    private ImageButton mActiveButton = null;
    private static final String TAG = EvidenceList.class.getSimpleName();
    protected static final int ACTION_LOGIN = 10;
    protected static final int ACTION_ENTER_PIN = 11;
    protected static final int ACTION_BULK_EDIT = 12;

    private static final int DIALOG_CONFIRM_DELETE = 2;
    private static final int DIALOG_LOADING = 3;
    private static final int DIALOG_FILES_MISSING = 4;

    private static final int MENU_ITEM_CANCEL_UPLOAD = 10001;
    private static final int MENU_ITEM_DELETE_EVIDENCE = 10002;
    private static final int MENU_ITEM_VIEW_EDIT_EVIDENCE = 10003;
    private EvidenceDBHelper evidenceHelper;
    protected UploadQueueHelper upHelper;
    private ListView mListView;
    EvidenceListCursorAdapter mAdapter;    
    private ImageButton mListAllButton, mListAudioButton, mListVideoButton, mListPhotoButton, mListUploadedButton;
    private Button uploadButton;
    private View actionButtonBar, tabButtonBar;    
    private TextView mTitleView;

    private Button mSelectAllButton, mImportButton;
    private EvidenceManager mEvidenceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        mContext = getApplicationContext();
        settings = ApplicationSettings.getInstance(mContext);

        mEvidenceManager = EvidenceManager.getInstance(mContext);
        setContentView(R.layout.evidence_list);

        actionButtonBar = findViewById(R.id.EvidenceSelectedItemsActionButtonBar);
        tabButtonBar = findViewById(R.id.EvidenceListTabBar);

        mData = getIntent().getData();
        if (mData == null) {
            mData = LocalEvidence.CONTENT_URI;//default data
        }
        upHelper = new UploadQueueHelper(mContext);
        evidenceHelper = new EvidenceDBHelper(mContext);

        mListAllButton = (ImageButton) findViewById(R.id.EvidenceListAllTabButton);
        mListVideoButton = (ImageButton) findViewById(R.id.EvidenceListVideoTabButton);
        mListAudioButton = (ImageButton) findViewById(R.id.EvidenceListAudioTabButton);
        mListPhotoButton = (ImageButton) findViewById(R.id.EvidenceListPhotoTabButton);
        mListUploadedButton = (ImageButton) findViewById(R.id.EvidenceListUploadTabButton);
        mTitleView = (TextView) findViewById(R.id.EvidenceListTypeTitle);
        mSelectAllButton = (Button) findViewById(R.id.CheckAll);        
        mImportButton = (Button) findViewById(R.id.ImportEvidence);
        mImportButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showDialog(DIALOG_IMPORT_EVIDENCE);
            }
        });
        mSelectAllButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {   
                EasyTracker.getTracker().trackEvent(TAG, "select_all", "on", 1);
                Toast.makeText(mContext,  getString(R.string.message_select_all), Toast.LENGTH_SHORT).show();
                mAdapter.checkAll();
            }           
        });

        ListHasCheckedItemsListener checkedItemsListener = new ListHasCheckedItemsListener() {

            @Override
            public void onListCheckedStatusChange(boolean hasCheckedItems) {
                showTabsOrButtons(hasCheckedItems);

            }
        };
        mListView = (ListView) findViewById(android.R.id.list);
        mListView.setEmptyView(findViewById(android.R.id.empty));
        mCursor = getCursor();
        mAdapter = new EvidenceListCursorAdapter(this, mCursor, getUriForCursor(), checkedItemsListener);
        Log.d(TAG, "onCreate, cursor: " + mCursor + " with adapter@uri " + getUriForCursor());
        uploadButton = (Button) findViewById(R.id.UploadEvidenceButton);

        mListView.setAdapter(mAdapter);
        mListView.setOnItemClickListener(this);
        setActiveButton();
        checkIfIntentHasTab(getIntent());

        UploadManagerService.startUploader(this, UploaderAction.OP_START, 1, null);
    }

    @Override
    public void onNewIntent(Intent intent) {
        checkIfIntentHasTab(intent);
    }

    private void checkIfIntentHasTab(Intent intent) {
        String tab = getIntent().getStringExtra("tab");
        if (tab != null) {
            if (tab.equals("uploads_completed")) {
                changeView(R.id.EvidenceListUploadTabButton);
            } else if (tab.equals("all_evidence")) {
                changeView(R.id.EvidenceListAllTabButton);
            } else if (tab.equals("videos")) {
                changeView(R.id.EvidenceListVideoTabButton);
            } else if (tab.equals("photos")) {
                changeView(R.id.EvidenceListPhotoTabButton);
            } else if (tab.equals("audio")) {
                changeView(R.id.EvidenceListAllTabButton);
            } else {
                Log.e(TAG, "no match for tab " + tab);
            }
        }
    }


    public void titlebarLogoClicked(View button) {
        Log.d(TAG, "Clicked titlebar");
        launchMainActivity();
    }

    public void launchMainActivity() {
        Intent i = new Intent(this, Home.class);
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(i);

    }
    //should be called after switching the cursor
    private void setActiveButton() {
        if (mData.equals(LocalEvidence.CONTENT_URI)){
            mActiveButton = mListAllButton;
        } else if (mData.equals(LocalEvidence.CONTENT_AUDIO_URI)){
            mActiveButton = mListAudioButton;
        } else if (mData.equals(LocalEvidence.CONTENT_VIDEO_URI)) {
            mActiveButton = mListVideoButton;
        } else if (mData.equals(LocalEvidence.CONTENT_PHOTO_URI)) {
            mActiveButton = mListPhotoButton;
        } else if (mData.equals(LocalEvidence.CONTENT_UPLOADED_URI)) {
            mActiveButton = mListUploadedButton;
        }
        mActiveButton.setSelected(true);
        setOthersInactive(); 
    }
    private void setOthersInactive() {
        if (mActiveButton != mListAllButton) {
            mListAllButton.setSelected(false);
        }
        if (mActiveButton != mListVideoButton) {
            mListVideoButton.setSelected(false);
        }
        if (mActiveButton != mListAudioButton) {
            mListAudioButton.setSelected(false);
        }
        if (mActiveButton != mListPhotoButton) {
            mListPhotoButton.setSelected(false);
        }
        if (mActiveButton != mListUploadedButton) {
            mListUploadedButton.setSelected(false);
        }
    }

    private void changeCursor() {
        mAdapter.changeCursor(getCursor());
    }


    private Cursor getCursor() {        
        return managedQuery(mData, null, null, null, null);
    }

    private Uri getUriForCursor() {
        return LocalEvidence.CONTENT_URI;
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "onDestroy");
        mAdapter.close();
        super.onDestroy();
    }



    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");
        if (!FileUtils.isExternalStorageAvailableAndWritable(mContext)) {
            Util.showAlertMsgNoExternalStorage(this);
            return;
        }
        if (settings.requiresPin() && settings.getLastPinSuccessEntryTime() < System.currentTimeMillis() - (1000 * 60 * 15)) {
            sendToEnterPin();
            return;
        }
        //Set<Long> selections = mAdapter.getSelectedCheckboxMediaIds();
        //setTabsOrButtons(selections);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        //super.onSaveInstanceState(outState);
        //outState.
    }
    @Override
    public void onItemClick(AdapterView<?> l, View v, int position, long id) {
        Log.d(TAG, "onListItemClick, item clicked with id " + id);
        Intent openEvidenceIntent = getIntentForEvidenceId(id);
        startActivity(openEvidenceIntent);
    }

    private void uncheckAll() {
        mAdapter.uncheckAll();
    }

    @Override
    public void onBackPressed() {
        Log.d(TAG, "onBackPressed");

        if (mAdapter.hasSelectedCheckboxes()) {
            uncheckAll();
        } else {
            Intent i = new Intent(this, Home.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);         
            startActivity(i);
            finish();
            //super.onBackPressed();
        }
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        Log.d(TAG, "onCreateDialog");
        switch (id) {
            case DIALOG_CONFIRM_DELETE:
                String msg = getString(R.string.alert_delete_imported);
                return new AlertDialog.Builder(this)
                        .setMessage(msg)
                        .setCancelable(false)
                        .setPositiveButton(getString(R.string.yes_btn),
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        EvidenceList.this.doRemoveEvidence();
                                    }
                                })
                        .setNegativeButton(R.string.no_btn, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        }).create();
            case DIALOG_LOADING:
                ProgressDialog pdialog = new ProgressDialog(this);
                pdialog.setMessage(getString(R.string.alert_checking_login));
                return pdialog;
            case DIALOG_FILES_MISSING:
                return new AlertDialog.Builder(this)
                        .setTitle(getString(R.string.alert_files_missing_title))
                        .setMessage(getString(R.string.alert_files_missing))
                        .setNeutralButton(getString(R.string.ok_btn), new OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int arg1id) {
                                dialog.cancel();
                            }
                        }).create();
            default:
                return super.onCreateDialog(id);
        }

    }

    public void removeEvidence(View v) {
        Log.d(TAG, "removeEvidence");
        //Toast.makeText(mContext,  "Going to delete.. ", Toast.LENGTH_LONG).show();
        showDialog(DIALOG_CONFIRM_DELETE);
    }

    public void bulkEditEvidence(View v) {
        Log.d(TAG, "bulkEditEvidence");
        EasyTracker.getTracker().trackEvent(TAG, "bulk_edit", "", 1);
        Set<Long> selections = mAdapter.getSelectedCheckboxMediaIds();
        Iterator<Long> selectionIter = selections.iterator(); 
        // Pass the array of id's checked to the intent service. 
        // We need to convert from Long[] to long[] 
        long[] ids = new long[selections.size()];
        int i = 0;
        while(selectionIter.hasNext()) {            
            long curr = selectionIter.next();
            ids[i++] = curr;
        }
        Intent bulkEditIntent = new Intent(this, BulkEditEvidence.class);
        bulkEditIntent.putExtra(BulkEditEvidence.EXTRA_EVIDENCE_IDS, ids);
        startActivityForResult(bulkEditIntent, ACTION_BULK_EDIT);
    }

    public void doRemoveEvidence() {
        Log.d(TAG, "doRemoveEvidence");
        EasyTracker.getTracker().trackEvent(TAG, "delete", "", 1);
        Set<Long> selectedIds = mAdapter.getSelectedCheckboxMediaIds();
        if (selectedIds == null || selectedIds.size() < 1) {
            Toast.makeText(mContext,  getString(R.string.alert_no_evidence_removed), Toast.LENGTH_LONG).show();
            return;
        }
        Iterator<Long> selectedIter = selectedIds.iterator();   
        List<Long> deleted = new ArrayList<Long>();
        while(selectedIter.hasNext()) {
            long selectedId = selectedIter.next();
            Log.d(TAG, "going to delete evidence id: " + selectedId);
            Evidence ev = evidenceHelper.getEvidencefromMediaRecord(selectedId);

            if (ev != null) {
                if (ev.getMediaId() > 0) {
                    //has a media id
                    int rowsAffected = evidenceHelper.deleteById(selectedId);
                    upHelper.deleteById(selectedId);
                    if (rowsAffected >0) {
                        deleted.add(selectedId);                         
                    }
                } else {
                    if (ev != null) {
                        try {
                            ev.getFile().delete();
                            int rowsAffected = evidenceHelper.deleteById(selectedId);
                            upHelper.deleteById(selectedId);
                            if (rowsAffected > 0) {
                                deleted.add(selectedId);
                            }
                        } catch(Exception e) {
                            Log.e(TAG, "error trying to delete evidence  " + selectedId + " msg: " + e.getMessage(), e);
                        }
                    }
                }
            } else {
                String msg = String.format(getString(R.string.alert_ev_with_id_could_not_delete), "" + selectedId);
                Toast.makeText(mContext, msg, Toast.LENGTH_LONG).show();
            }
        }
        if (deleted != null && deleted.size() > 0) {
            Long[] deletedArr = deleted.toArray(new Long[1]);
            mAdapter.uncheckIds(deletedArr);
        }
        try {
            dismissDialog(DIALOG_CONFIRM_DELETE);
        } catch(Exception e) {
            //who cares
        }
    }
    public void uploadSelected(View v) throws URISyntaxException, IOException {     
        Log.d(TAG, "uploadSelected");
        uploadButton.setEnabled(false);
        showDialog(DIALOG_LOADING);
        //if the last time the session was checked was more than 15 minutes (-5 seconds)
        //then check the session again..

        if (!settings.canUserAutoLogin()) {
            dismissDialog(DIALOG_LOADING);
            sendToLogin();
        } else {
            doUploadSelected();
            uploadButton.setEnabled(true);
        }

    }

    private void sendToLogin() {
         Intent i = new Intent(Action.LOGIN);         
         startActivityForResult(i, ACTION_LOGIN);
    }

    private void sendToEnterPin() {
        startActivityForResult(new Intent(this, EnterPin.class), ACTION_ENTER_PIN);
    }

    private void doUploadSelected() {
        Log.d(TAG, "doUploadSelected");

        Set<Long> selections = mAdapter.getSelectedCheckboxMediaIds();
        Iterator<Long> selectionIter = selections.iterator(); 
        // Pass the array of id's checked to the intent service. 
        // We need to convert from Long[] to long[] 

        Long[] origArr = selections.toArray(new Long[selections.size()]);
        Log.d(TAG, "about to pass evidence IDs for upload | on thread " + Thread.currentThread().getId());
        List<Long> toUpload = new ArrayList<Long>(); 
        long[] ev_ids = new long[selections.size()];
        int i = 0;
        boolean alertMissing = false;
        while(selectionIter.hasNext()) {
            long curr = selectionIter.next();
            Evidence ev = evidenceHelper.getEvidencefromMediaRecord(curr);
            if (FileUtils.isFileAvailableAndReadable(ev.getFile())) {
                toUpload.add(curr);
                ev_ids[i] = curr;
                i++;
            } else {
                alertMissing = true;
            }
        }
        try {
            dismissDialog(DIALOG_LOADING);
        } catch(Exception e) {}

        if (alertMissing) {
            showDialog(DIALOG_FILES_MISSING);
        }
        if (ev_ids.length < 1) {
            return;
        }
        EasyTracker.getTracker().trackEvent(TAG, "upload_selected", "" + ev_ids.length + " items" , 1);
        UploadManagerService.startUploader(this, UploaderAction.OP_QUEUE_UPLOAD, 1, ev_ids);

        uploadButton.setEnabled(true);
        mAdapter.markIdsAsDisabled(origArr);

    }

    private void onLoginResult(int resultCode, Intent data) {
        EasyTracker.getTracker().trackEvent(TAG, "login", "on", (resultCode == RESULT_OK) ? 1 : 0);
        if (resultCode == RESULT_OK) {

            doUploadSelected();         
        } else {
            try {
                dismissDialog(DIALOG_LOADING);
            } catch (Exception e) {}
            uploadButton.setEnabled(true);
            Toast.makeText(mContext, getString(R.string.alert_cannot_upload_without_internet),  Toast.LENGTH_LONG).show();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {                
        Log.d(TAG, "onActivityResult");

        switch (requestCode) {
            case ACTION_LOGIN:
                onLoginResult(resultCode, data);
                return;
            case ACTION_ENTER_PIN:
                if (resultCode != Activity.RESULT_OK) {                
                     finish();//throw error message
                 }
                return;
            case ACTION_BULK_EDIT:
                if (resultCode == RESULT_OK) {
                    uncheckAll();
                }
                return;
            case ACTION_IMPORT_AUDIO:
            case ACTION_IMPORT_VIDEO:
            case ACTION_IMPORT_PHOTO:
                onImportResult(requestCode, resultCode, data);
                return;                
            default:
                super.onActivityResult(requestCode, resultCode, data);
        }
    }

    private void onImportResult(int requestCode, int resultCode, Intent intent) {

        ImportAction action = ImportAction.IMPORT_PHOTO;
        if (requestCode == ACTION_IMPORT_AUDIO) {
            action = ImportAction.IMPORT_AUDIO;
        } else if (requestCode == ACTION_IMPORT_VIDEO) {
            action = ImportAction.IMPORT_VIDEO;
        }
        EasyTracker.getTracker().trackEvent(TAG, "import", action.toString(), resultCode == RESULT_OK ? 1 : 0);
        if (resultCode == RESULT_OK) {
            Evidence ev = mEvidenceManager.importEvidence(this, intent, action);
            if (ev != null) {
                launchEvidenceListActivity(null);
                BackupService.start(this, BackupService.OP_DATA_CHANGED);
            }
        }
    }


    public void showTabsOrButtons(boolean hasCheckedItems) {        
        if (hasCheckedItems) {
            tabButtonBar.setVisibility(View.INVISIBLE);
            actionButtonBar.setVisibility(View.VISIBLE); 
            if (mData.equals(LocalEvidence.CONTENT_UPLOADED_URI)) {
                actionButtonBar.findViewById(R.id.UploadEvidenceButton).setVisibility(View.GONE);
                actionButtonBar.findViewById(R.id.BulkEditEvidenceButton).setVisibility(View.GONE);
            } else {
                actionButtonBar.findViewById(R.id.UploadEvidenceButton).setVisibility(View.VISIBLE);
            }
        } else {
            actionButtonBar.setVisibility(View.GONE);
            tabButtonBar.setVisibility(View.VISIBLE);
        }
    }

    public void changeView(int id) {
        Uri newUri = null;
        String newTitle = "";
        if (id == R.id.EvidenceListAllTabButton) {
            newUri = LocalEvidence.CONTENT_URI;
            newTitle = getString(R.string.tab_all_pending_upload);
            EasyTracker.getTracker().trackEvent(TAG, "switched_tab", "all", 1);
        } else if (id == R.id.EvidenceListAudioTabButton) {
            newUri = LocalEvidence.CONTENT_AUDIO_URI;
            newTitle = getString(R.string.tab_audio_pending_upload);
            EasyTracker.getTracker().trackEvent(TAG, "switched_tab", "audio", 1);
        } else if (id == R.id.EvidenceListPhotoTabButton) {
            newUri = LocalEvidence.CONTENT_PHOTO_URI;
            newTitle = getString(R.string.tab_photos_pending_upload);
            EasyTracker.getTracker().trackEvent(TAG, "switched_tab", "photos", 1);
        } else if (id == R.id.EvidenceListVideoTabButton) {
            newUri = LocalEvidence.CONTENT_VIDEO_URI;
            newTitle = getString(R.string.tab_video_pending_upload);
            EasyTracker.getTracker().trackEvent(TAG, "switched_tab", "videos", 1);
        } else if (id == R.id.EvidenceListUploadTabButton) {
            newUri = LocalEvidence.CONTENT_UPLOADED_URI;
            newTitle = getString(R.string.tab_all_uploaded);
            EasyTracker.getTracker().trackEvent(TAG, "switched_tab", "uploaded", 1);
        }

        //only change something if its a different view
        if (!mData.equals(newUri) && newUri != null) {
            mData = newUri;
            changeCursor();
            setActiveButton();
            mTitleView.setText(newTitle);
        }
    }
    public void changeView(View button) {
        changeView(button.getId());
    }

}
4

1 回答 1

0

我使用了一个很棒的免费工具,BugSense,它很容易插入到您的应用程序中,当发生崩溃时,它会告诉您导致崩溃的行号。它还会通知您有关崩溃的信息,为您提供有关 android 版本、应用程序版本、先前发生次数、设备状态等的信息。

这是我的应用程序崩溃报告中的一个示例: 在此处输入图像描述

于 2012-08-17T16:54:07.030 回答