2012-06-26 26 views
6

Vì vậy, câu hỏi của tôi được đặt lại là khi bạn chuyển đến Cài đặt -> Tài khoản & Đồng bộ hóa và chọn tài khoản được tạo mà SyncAdapter đang đồng bộ hóa với máy chủ đám mây và chọn xóa tài khoản, điều gì xảy ra với điều kiện là SyncAdapter của bạn ? Có một hộp thoại hiển thị yêu cầu bạn xác nhận và dữ liệu trên điện thoại được liên kết với tài khoản đó sẽ bị xóa. Tôi không thể dễ dàng tin rằng khuôn khổ có thể tự động xóa dữ liệu của tôi SyncAdapter đã được lưu trữ trong cơ sở dữ liệu cục bộ, nhưng dường như ngụ ý rằng việc xóa tài khoản sẽ (và tôi đồng ý rằng) nên xóa dữ liệu đó. Có một bổ sung cho SyncAdapter của tôi sẽ phân phối như là gọi lại cho việc loại bỏ tài khoản để xử lý xóa tất cả các dữ liệu thích hợp từ cơ sở dữ liệu địa phương? Có lẽ nó phải được thực hiện thông qua các AccountManager thay vào đó; AccountManager của tôi được thông báo khi tài khoản bị xóa và từ đó tôi có thể kích hoạt xóa dữ liệu mà không cần SyncAdapter.SyncAdapter có được thông báo khi AccountManager xóa tài khoản không?

EDIT: Trên ghi chú liên quan, trình quản lý đồng bộ có gọi số SyncAdapter cho mỗi tài khoản mà nó đồng bộ hóa khi thêm tài khoản mới không? Tôi thấy onPerformSync(...) đang được thực hiện cho các tài khoản đã thêm trước đó cùng với tài khoản vừa thêm khi tôi thêm tài khoản và muốn dừng lại.

Trả lời

7

Tôi đã phát hiện ra giải pháp là làm cho ứng dụng ContentProvider của ứng dụng triển khai OnAccountsUpdateListener. Gắn ContentProvider như một người biết lắng nghe trong phương pháp onCreate với account_manager.addOnAccountsUpdatedListener(this, null, false) và sau đó thực hiện phương thức giao diện như

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

tôi xây dựng một String các tài khoản hiện kết nối, sau đó xây dựng một truy vấn SQL với String đó. Tôi thực hiện xóa trên cơ sở dữ liệu trong chuỗi nền trên truy vấn đó để xóa dữ liệu được liên kết với các tài khoản hiện không được kết nối. Và tôi thông báo rằng nội dung đã thay đổi, nhưng không cần phải đồng bộ hóa với máy chủ.

+0

Bạn có thể giải thích một chút về câu trả lời của mình không? Những gì 'onCreate' là bạn đang nói về? – akirk

+0

... Trình ContentProvider, đọc dòng đầu tiên gần hơn.Tôi không biết những gì bạn muốn "phức tạp" d –

+0

Có thể loại bỏ OnAccountsUpdateListener tại điểm thích hợp trong vòng đời ContentProviders không? – fr1550n

5

Không, nhưng Authenticator của bạn thực hiện [1]. Phương pháp này được gọi là trước khi tài khoản bị xóa:

AbstractAccountAuthenticator.getAccountRemovalAllowed(AccountAuthenticatorResponse, Account) 

các Tài khoản param là tài khoản bị xóa - hành vi mặc định là cho phép loại bỏ các tài khoản:

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

.. nhưng tôi đoán đó là một cái móc mà bạn có thể sử dụng để dọn dẹp mọi thứ hoặc chặn tài khoản bị xóa nếu bạn muốn.

[1] - đây là một hack bẩn; xin vui lòng xem bình luận của Dandre.

+2

Tôi không tin rằng phương pháp này được sử dụng để "dọn dẹp mọi thứ". Với tên và vị trí của nó trong 'AbstractAccountAuthenticator', nó có thể được sử dụng để ngăn chặn các tài khoản nội bộ mà bạn có thể sử dụng cho ứng dụng của bạn để xóa được ngoài tầm kiểm soát của bạn. Tôi đã không tìm thấy một trường hợp sử dụng cá nhân. Ý định lớn với tôi là "lấy" làm tiền tố. Bạn nên tránh các tác dụng phụ trong các phương pháp "nhận", làm cho dòng chảy khó theo dõi. Bạn có nghi ngờ một "get" để xóa tất cả dữ liệu của bạn? –

+0

Không nghi ngờ gì bạn là chính xác và nó là một hack bẩn. Tôi sẽ cập nhật câu trả lời của tôi như vậy. – fr1550n

3

Một tùy chọn khác là đăng ký phát sóng android.accounts.LOGIN_ACCOUNTS_CHANGEDAccountManager gửi đi. Rất tiếc, chương trình phát này được gửi đi bất cứ khi nào bất kỳ tài khoản nào được thay đổi và chương trình phát không cung cấp thêm thông tin về những gì đã thay đổi.

Vì vậy, bạn phải truy vấn trình quản lý tài khoản và xem có bao nhiêu tài khoản "của bạn" đã để lại và xóa dữ liệu của tài khoản bị thiếu.

+0

Vâng, giải pháp trên đây bởi @Dandre Allison dựa trên điều này. Vì vậy, câu trả lời này nên được ưa thích. Khi bạn gọi 'addOnAccountsUpdatedListener', Trình quản lý tài khoản đang đăng ký bộ thu phát quảng bá động gọi người nghe trong' onReceive' của nó. Vì vậy, về cơ bản là như nhau. Cả hai giải pháp được thông báo bất cứ khi nào bất kỳ tài khoản nào trong thiết bị (tài khoản Google, tài khoản Twitter, v.v.) được thay đổi. – blindOSX

Các vấn đề liên quan