为什么单个静态变量在多次读取时有多个值?

时间:2016-09-03 17:14:29

标签: java android weak-references

上下文
在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 class是一个包含Observers列表的简单列表。

调用getInstance(Context context)时,instance始终有值(当然,不是第一次)。
但是,当从任何方法getInstance()addContactupdateContact调用deleteContact时,静态变量instance始终具有值null(偶数)当线程名称相同时:main)。

我尝试删除Multidex支持,使instance变量volatile但无法使其正常工作。任何帮助都会得到很好的帮助。提前谢谢!

日志:

    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: java.lang.ref.WeakReference@90e9b43 on main
    09-03 18:01:04.398 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: printInstance() => java.lang.ref.WeakReference@90e9b43 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: java.lang.ref.WeakReference@90e9b43 on main
    09-03 18:07:40.257 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: printInstance() => java.lang.ref.WeakReference@90e9b43 on main

1 个答案:

答案 0 :(得分:2)

问题在于Sync Service作为不同的进程启动。我知道单个Android进程可以拥有多个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是什么。

我删除了属性android:process,它开始工作。