2

一部のユーザーから、appwidget にデータを提供するカーソル ( RemoteViewService) が非アクティブ化/クローズされているという ACRA 例外レポートを受け取りました。それは私に直接起こることは決してありませんが、それが少し問題になる場合には十分に起こります.

私のRemoteViewServiceのコードは次のとおりです。

    public static class ListItemService extends RemoteViewsService {

        public RemoteViewsFactory onGetViewFactory(final Intent intent) {

            return new RemoteViewsFactory() {

                private MyCursor cursor;

                public void onCreate() {
                    // Nothing
                }

                public synchronized void onDestroy() {
                    if (this.cursor != null)
                        this.cursor.close();
                }

                public synchronized RemoteViews getViewAt(int position) {
                      // Here I read from the cursor and it crashes with
                      // the stack trace below
                }

                public int getCount() {
                      return ((this.cursor != null) ? this.cursor.getCount() : 0);
                }

                public int getViewTypeCount() {
                    return 1;
                }

                public boolean hasStableIds() {
                    return true;
                }

                public long getItemId(int position) {
                    return position;
                }

                public RemoteViews getLoadingView() {
                    return null;
                }

                public synchronized void onDataSetChanged()
                {
                    if (this.cursor != null)
                        this.cursor.close();

                    this.cursor = getApplicationCntext().getContentResolver().query(myUri, null, null, null, null);
                }
            };

スタック トレースは、プラットフォームのバージョンごとに異なります。たとえば、4.0.3 では次のようになります。

android.database.StaleDataException: Attempting to access a closed CursorWindow.Most probable cause: cursor is deactivated prior to calling this method.

2.3では、次のようになります。

java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery 

私の人生では、 fromonDestroy()onDataSetChanged(). 一部のユーザーは、クラッシュが発生したときにアプリを積極的に操作していなかったと報告しています。

ContentProvider への複数の呼び出しが同じカーソルを返す可能性があり、同じクエリを使用する UI を表示すると、それらは互いにステップします。しかし、カーソル オブジェクトが異なるため、そうではないようです。

何か案は?

4

2 に答える 2

1

複数のスレッド間の同期の問題のように見えます.1つは前のカーソルを閉じ、もう1つはその後すぐにアクセスします。

onPause イベントなど、最初にできるときにカーソルを閉じることを検討することをお勧めします。

また、再度アクセスする前にcursor.isClosed()をチェックするなどの安全対策を追加できます。コードに同期を追加することもできます。

新しいカーソルをローカル var で取得し、それが完了すると、以前のカーソルを置き換えて閉じるヘルパー メソッドが、当面はより迅速な解決策になる可能性があります。

AOSP docから;

このインターフェイスは、データベース クエリによって返される結果セットへのランダムな読み取り/書き込みアクセスを提供します。カーソルの実装は同期する必要がないため、複数のスレッドから Cursor を使用するコードは、Cursor を使用するときに独自の同期を実行する必要があります。

コンテンツ プロバイダの基本から、

ContentResolver.query() クライアント メソッドは、クエリの選択基準に一致する行に対するクエリの射影によって指定された列を含む Cursor を常に返します。Cursor オブジェクトは、含まれる行と列へのランダム読み取りアクセスを提供します。Cursor メソッドを使用すると、結果の行を反復処理し、各列のデータ型を決定し、列からデータを取得し、結果の他のプロパティを調べることができます。一部の Cursor 実装は、プロバイダーのデータが変更されたときにオブジェクトを自動的に更新するか、Cursor が変更されたときにオブザーバー オブジェクトのメソッドをトリガーするか、またはその両方を行います。

于 2013-02-26T00:14:20.667 に答える
0

メソッドを追加this.cursor = nullしてみるonDestory()

public synchronized void onDestroy() {
    if (this.cursor != null){
        this.cursor.close();
        this.cursor = null
    }
}
于 2016-12-14T07:52:59.223 に答える