2016-09-03 8 views
1

컨텍스트 :
Android에서는 모든 연락처 DataSet<ContactEntry>에 대한 단일 소스를 구현하려고합니다. 따라서 연락처가 동기화 프로세스에 의해 업데이트되면 기존 어댑터에 반영되어야합니다 (활성 어댑터가있는 경우에만).
그러나 동기화에서 항상 DataSet<ContactEntry> (null이 아니더라도)을 찾음으로써 동기화의 모든 업데이트/추가/제거가 무시됩니다.왜 단일 정적 변수가 다중 읽기에 대해 다중 값을 갖는가?

소스 코드 :

public class ContactsDataSet { 

    private static final String TAG = "ContactsDataSet"; 

    private static final Object lock = new Object(); 
    private static volatile WeakReference<DataSet<ContactEntry>> instance = null; 

    public static DataSet<ContactEntry> getInstance(Context context) { 
     synchronized (lock) { 
      DataSet<ContactEntry> dataSet; 
      if (instance == null) { 
        Log.d(TAG, "Creating instance for ContactsDataSet"); 
        dataSet = createDataSet(context); 
        instance = new WeakReference<>(dataSet); 
        Log.d(TAG, "Set instance to: " + instance + " on " + Thread.currentThread().getName()); 
      } else { 
       dataSet = instance.get(); 
       if (dataSet == null) { 
        Log.d(TAG, "Re-creating Data Set"); 
        dataSet = createDataSet(context); 
        instance = new WeakReference<>(dataSet); 
        Log.d(TAG, "Set instance to: " + instance + " on " + Thread.currentThread().getName()); 
       } else { 
        Log.d(TAG, "Valid instance: " + instance + " on " + Thread.currentThread().getName()); 
       } 
      } 
      return dataSet; 
     } 
    } 

    public static void printInstance() { 
     synchronized (lock) { 
      Log.d(TAG, "printInstance() => " + instance + " on " + Thread.currentThread().getName()); 
     } 
    } 


    private static DataSet<ContactEntry> getInstance() { 
     synchronized (lock) { 
      DataSet<ContactEntry> ret= instance == null ? null : instance.get(); 
      Log.d(TAG, "getInstance() => " + instance + " on " + Thread.currentThread().getName()); 
      return ret; 
     } 
    } 


    private static DataSet<ContactEntry> createDataSet(Context context) { 
     Log.d(TAG, "Fetching contacts from DB"); 
     return new DataSet<>(DbHelper.getInstance(context).fetchValidContacts()); 
    } 


    public static void addContact(ContactEntry contact) { 
     if (contact.isDirty() || TextUtils.isEmpty(contact.getUserNumber())) { 
      Log.d(TAG, "Ignoring dirty/incomplete contact"); 
      return; 
     } 
     synchronized (lock) { 
      DataSet<ContactEntry> dataSet = getInstance(); 
      if (dataSet != null) { 
       Log.d(TAG, "Adding " + contact + " to Cache"); 
       dataSet.addItem(contact); 
      } else { 
       Log.d(TAG, "Ignoring new Contact " + contact + " as instance: " + instance + " isn't valid on " + Thread.currentThread().getName()); 
      } 
     } 
    } 

    public static void updateContact(ContactEntry contact) { 
     if (contact.isDirty() || TextUtils.isEmpty(contact.getUserNumber())) { 
      Log.d(TAG, "Removing dirty/incomplete contact"); 
      deleteContact(contact.getContactId()); 
     } 
     synchronized (lock) { 
      DataSet<ContactEntry> dataSet = getInstance(); 
      if (dataSet != null) { 
       Log.d(TAG, "Updating " + contact + " in Cache"); 
       dataSet.updateItem(contact); 
      } else { 
       Log.d(TAG, "Ignoring update Contact " + contact + " as instance: " + instance + " isn't valid on " + Thread.currentThread().getName()); 
      } 
     } 
    } 

    public static void deleteContact(int contactId) { 
     synchronized (lock) { 
      DataSet<ContactEntry> dataSet = getInstance(); 
      if (dataSet != null) { 
       Log.d(TAG, "Removing " + contactId + " from Cache"); 
       dataSet.removeItem(contactId); 
      } else { 
       Log.d(TAG, "Ignoring delete Contact " + contactId + " as instance: " + instance + " isn't valid on " + Thread.currentThread().getName()); 
      } 
     } 
    } 
} 

DataSet 클래스는 관찰자의 목록과 간단한 목록입니다.

getInstance(Context context)이 호출 될 때 instance은 항상 (처음에는 아니고) 값을가집니다. getInstance()이 방법 addContact, updateContactdeleteContact 또는 임의로부터 호출
그러나, 정적 변수 instance 항상 null 값을 갖는다 (나사 이름이 같은 경우에도 주된).

instance 변수 volatile으로 Multidex 지원을 제거했지만 작동하지 못했습니다. 어떤 도움이든지 큰 도움이 될 것입니다. 미리 감사드립니다!

로그 :

When I first invoke Adapter: 

    09-03 18:01:04.367 18369-18369/in.yyyyyyy.xxxxx D/ContactsAdapter: ContactsAdapter() 
    09-03 18:01:04.369 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: Creating instance for ContactsDataSet 
    09-03 18:01:04.369 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: Fetching contacts from DB 
    09-03 18:01:04.398 18369-18369/in.yyyyyyy.xxxxx I/ContactEntry: fetchValidContacts() => [ContactEntry { contactId: 1, contactVersion: 4, phoneNumber: +999999999999, email: null, userNumber: 7dc5baec-1e08-43f4-b124-8d65d097036e, name: CCCCCCCCCCCCCC, dirty: false }, ContactEntry { contactId: 3, contactVersion: 3, phoneNumber: +333333333333, email: null, userNumber: 13d7b667-b523-41b7-ba89-203139e0dba9, name: GGGGGG, dirty: false }, ContactEntry { contactId: 4, contactVersion: 20, phoneNumber: +999999999999, email: null, userNumber: 7dc5baec-1e08-43f4-b124-8d65d097036e, name: MMMMMM, dirty: false }] 
    09-03 18:01:04.398 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: Set instance to: [email protected] on main 
    09-03 18:01:04.398 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: printInstance() => [email protected] on main 

    Triggered Sync (after updating 3rd contact - MMMMMM): 

    09-03 18:02:43.986 28748-28748/in.yyyyyyy.xxxxx:sync D/SyncContacts: Updating User Number for ContactEntry { contactId: 4, contactVersion: 21, phoneNumber: +333333333333, email: null, userNumber: null, name: MMMMMM, dirty: true } with 13d7b667-b523-41b7-ba89-203139e0dba9 
    09-03 18:02:43.986 28748-28748/in.yyyyyyy.xxxxx:sync I/ContactEntry: updateAccount(ContactEntry { contactId: 4, contactVersion: 21, phoneNumber: +333333333333, email: null, userNumber: 13d7b667-b523-41b7-ba89-203139e0dba9, name: MMMMMM, dirty: false }) 
    09-03 18:02:43.992 28748-28748/in.yyyyyyy.xxxxx:sync D/ContactsDataSet: getInstance() => null on main 
    09-03 18:02:43.992 28748-28748/in.yyyyyyy.xxxxx:sync D/ContactsDataSet: Ignoring update Contact ContactEntry { contactId: 4, contactVersion: 21, phoneNumber: +333333333333, email: null, userNumber: 13d7b667-b523-41b7-ba89-203139e0dba9, name: MMMMMM, dirty: false } as instance: null isn't valid on main 


    When I invoke Adapter again: 

    09-03 18:07:40.255 18369-18369/in.yyyyyyy.xxxxx D/ContactsAdapter: ContactsAdapter() 
    09-03 18:07:40.257 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: Valid instance: [email protected] on main 
    09-03 18:07:40.257 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: printInstance() => [email protected] on main 
+0

인스턴스가 null이거나 instance.get()이 null입니까? –

+0

인스턴스가 null입니다. – Siva

+0

MCVE 규칙 적용에 대한 변경 사항이 있습니까? http://stackoverflow.com/help/mcve –

답변

1

문제가 동기화 서비스와이다는 다른 프로세스를 시작했다. 필자는 단일 안드로이드 프로세스가 여러 Linux 프로세스를 가질 수 있음을 알고있었습니다. 동기화 서비스 구성은 :

<service 
     android:name=".sync.SyncService" android:process=":sync"> 
     <intent-filter> 
      <action android:name="android.content.SyncAdapter" /> 
     </intent-filter> 

     <meta-data 
      android:name="android.content.SyncAdapter" 
      android:resource="@xml/syncadapter" /> 
    </service> 

나는 android:process 있다는 것입니다 모르고 인터넷에 someother 응용 프로그램에서 해당 구성을 복사.

속성 android:process을 제거했으며 작동을 시작했습니다.