2012-06-26 9 views
6

私の質問は、設定 - >アカウント&と同期して、SyncAdapterがクラウドサーバーと同期しているアカウントを選択してアカウントを削除すると、SyncAdapterに関係があります?確認するダイアログが表示され、そのアカウントに関連付けられている電話機のデータが削除されることが示されます。私は簡単にフレームワークが自動的に私のSyncAdapterは、ローカルデータベースに保存されたデータを削除することができると信じてすることはできませんが、アカウントを削除すると、そのデータを削除(と私はそれがすべきである同意するだろう)になることを意味するようです。 SyncAdapterに、ローカルデータベースからすべての適切なデータを削除するためのアカウント削除のコールバックとして機能するものが追加されていますか?たぶんそれはAccountManagerを通して行わなければならないかもしれません。私AccountManagerアカウントが削除される際に通知され、そこから私はSyncAdapterせずにデータの削除をトリガすることができます。AccountManagerがアカウントを削除したときにSyncAdapterに通知されますか?

EDIT: 関連するメモでは、新しいアカウントが追加されたときに同期するアカウントごとに同期マネージャーが私のSyncAdapterを呼び出していますか?私はonPerformSync(...)が以前に追加されたアカウントのために、アカウントを追加したばかりの追加されたアカウントと共に実行されているのを見て、それを止めたいと思っています。

答えて

7

私は解決策は、アプリケーションのContentProviderOnAccountsUpdateListenerを実装することです発見しました。 account_manager.addOnAccountsUpdatedListener(this, null, false)とそのonCreate方法でリスナーとしてContentProviderを取り付けた後、私はそのStringでSQLクエリを構築し、その後、現在接続しているアカウントのStringを構築

@Override 
public void onAccountsUpdated(final Account[] accounts) { 
    Ln.i("Accounts updated."); 
    final Iterable<String> account_list = new Iterable<String>() { 
     @Override 
     public Iterator<String> iterator() { 
      return new Iterator<String>() { 
       private final Iterator<Account> account_list = Arrays.asList(accounts).iterator(); 

       @Override 
       public boolean hasNext() { 
        return account_list.hasNext(); 
       } 

       /** Extracts the next account name and wraps it in single quotes. */ 
       @Override 
       public String next() { 
        return "'" + account_list.next().name + "'"; 
       } 

       @Override 
       public void remove() { throw new UnsupportedOperationException("Not implemented"); } 
      }; 
     } 
    }; 
    final String account_set = TextUtils.join(", ", account_list); 
    Ln.i("Current accounts: %s", account_set); 

    // Removes content that is associated with accounts that are not currently connected 
    final SelectionBuilder builder = new SelectionBuilder(); 
    builder.table(Tables.CALENDARS) 
      .where(Calendars.CALENDAR_USER + " NOT IN (?)", account_set); 

    new SafeAsyncTask() { 
     @Override 
     public Void call() throws Exception { 
      _model.openWritableDatabase(); 
      _model.delete(builder); 
      return null; 
     } 
    }.execute(); 


    getContext().getContentResolver().notifyChange(Calendars.NO_SYNC_URI, null, false); 
} 

のようなインターフェイスメソッドを実装します。私は、現在の接続されていないアカウントに関連付けられているデータを削除するために、そのクエリのバックグラウンドスレッドでデータベースの削除を実行します。そして、私はコンテンツが変更されたことを通知しますが、サーバーと同期する必要はありません。

+0

あなたはあなたの答えに少し詳しく説明してもらえますか?あなたは「onCreate」と何を話していますか? – akirk

+0

... ContentProviderは、最初の行を近くに読みます。あなたがもっと精巧にしたいものが何であるか分かりませんd –

+0

ContentProvidersライフサイクルの関連ポイントでOnAccountsUpdateListenerを削除できますか? – fr1550n

5

ありませんが、あなたのオーセンティケータはない[1]。アカウントが削除される前に、このメソッドが呼び出されます。

AbstractAccountAuthenticator.getAccountRemovalAllowed(AccountAuthenticatorResponse, Account) 

アカウント paramが削除されるアカウントです - デフォルトの動作では、アカウントの削除できるようにすることです:

return super.getAccountRemovalAllowed(response, account); // returns Bundle[{booleanResult=true}] 

を..しかし、それはあなたが整理するのに使うことができるフックだと思うか、あなたが望むなら削除されているアカウントをブロックすることができます。

[1] - これは汚いハックです。 Dandreのコメントをご覧ください。

+2

私は、その方法が "物事をきれいにする"ために使用されることを意図しているとは思わない。 'AbstractAccountAuthenticator'にその名前と場所が与えられている場合、あなたのアプリケーションのために使用する可能性のある内部アカウントをコントロール外で削除できないようにするために使用されます。私はユースケースを個人的に見つけられませんでした。私の大きな意思は接頭辞として "get"です。あなたは "取得"メソッドで副作用を避ける必要があり、フローを追いつくのが難しくなります。すべてのデータを削除することを「取得する」と思われますか? –

+0

あなたは間違いなくあなたが正しいとそれは汚れたハックだ。私はそのようなものとして私の答えを更新します。 – fr1550n

3

もう1つの方法は、AccountManagerが送信するandroid.accounts.LOGIN_ACCOUNTS_CHANGEDブロードキャストに登録することです。残念ながら、このブロードキャストは、のアカウントが変更されたときにいつでもに送信され、ブロードキャストは変更された情報を配信しません。

アカウントマネージャーに問い合わせて、残っている「あなたの」アカウントの数を見て、欠落しているアカウントのデータを削除する必要があります。

+0

これをベースにした@Dandre Allisonのソリューションはこれに基づいています。だから、この答えが好まれるはずです。 'addOnAccountsUpdatedListener'を呼び出すと、AccountManagerはリスナーを' onReceive'で呼び出す動的な放送受信機を登録しています。基本的に同じです。両方のソリューションは、デバイス内のアカウント(Googleアカウント、Twitterアカウントなど)が変更されるたびに通知されます。 – blindOSX