9

I am using Parse.com as a backend for my app. They also offer a local database to store information, as an alternative to SQLite.

I want to add numbers from phone to my database with parse. Before adding a number I need to check if the number already exists in the database, so I use findInBackground() to get a list of numbers that match the number I want to add. If the list is empty the number I want to add doesn't exists in the database.

The method to do this is:

public void putPerson(final String name, final String phoneNumber, final boolean isFav) {

        // Verify if there is any person with the same phone number
        ParseQuery<ParseObject> query = ParseQuery.getQuery(ParseClass.PERSON_CLASS);
        query.whereEqualTo(ParseKey.PERSON_PHONE_NUMBER_KEY, phoneNumber);
        query.fromLocalDatastore();
        query.findInBackground(new FindCallback<ParseObject>() {
                                   public void done(List<ParseObject> personList,
                                                    ParseException e) {
                                       if (e == null) {
                                           if (personList.isEmpty()) {
                                               // If there is not any person with the same phone number add person
                                               ParseObject person = new ParseObject(ParseClass.PERSON_CLASS);
                                               person.put(ParseKey.PERSON_NAME_KEY, name);
                                               person.put(ParseKey.PERSON_PHONE_NUMBER_KEY, phoneNumber);
                                               person.put(ParseKey.PERSON_FAVORITE_KEY, isFav);
                                               person.pinInBackground();

                                               Log.d(TAG,"Person:"+phoneNumber+" was added.");
                                           } else {
                                               Log.d(TAG, "Warning: " + "Person with the number " + phoneNumber + " already exists.");
                                           }
                                       } else {
                                           Log.d(TAG, "Error: " + e.getMessage());
                                       }
                                   }
                               }
        );
    }

Then I call this method 3 times to add 3 numbers:

ParseLocalDataStore.getInstance().putPerson("Jack", "0741234567", false);
ParseLocalDataStore.getInstance().putPerson("John", "0747654321", false);
ParseLocalDataStore.getInstance().putPerson("Jack", "0741234567", false);
ParseLocalDataStore.getInstance().getPerson(); // Get all persons from database

Notice that the third number is the same as the first, and it shouldn't be added to database. But the logcat shows:

12-26 15:37:55.424 16408-16408/D/MGParseLocalDataStore: Person:0741234567 was added.
12-26 15:37:55.424 16408-16408/D/MGParseLocalDataStore: Person:0747654321 was added.
12-26 15:37:55.484 16408-16408/D/MGParseLocalDataStore: Person:0741234567 was added.

The third number was added even if it wasn't supposed to do this, because fintInBackground() is running in 3 background threads almost simultaneously, so it will find that there is no number in the database like the one I want to add.

In this question a guy told me that I should use Bolts library from Parse. I read about it from here and some Parse blog posts, but I don't fully understand how to use this with the method I already have, and how to syncronize the queries to be executed one after another.

If someone worked with this library please guide me on how to do this or provide some basic examples so I can understand the workflow.

Thanks!

4

3 に答える 3

1

競合状態があるようです。この問題を解決するには、さまざまな方法があります。これは、ボルト以外の代替品です。

主な問題は、検索クエリがほぼ同時に発生しているため、データベース内で重複が見つからないことです。この場合の解決方法は、一度に 1 人だけを検索して追加することです。検索を行う UI を縛りたくないので、明らかにメイン スレッドでは実行しません。では、1) 追加する必要のある項目を含む、2) 追加できることを確認する、という 2 つのことを行うリストを作成してみましょう。非同期タスクを使用して、検索をメインスレッドから切り離すことができます。

実行する必要があることの大まかなアイデアは次のとおりです。

import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.ParseQuery;

import java.util.ArrayList;
import java.util.List;

public class AddPersonAsyncQueue {

    ArrayList<ParseObject> mPeople = new ArrayList();
    Boolean mLock;
    AddTask mRunningTask;

    public synchronized void addPerson(final String name, final String phoneNumber, final boolean isFav) {

        // we aren't adding a person just yet simply creating the object
        // and keeping track that we should do the search then add for this person if they aren't found
        ParseObject person = new ParseObject(ParseClass.PERSON_CLASS);
        person.put(ParseKey.PERSON_NAME_KEY, name);
        person.put(ParseKey.PERSON_PHONE_NUMBER_KEY, phoneNumber);
        person.put(ParseKey.PERSON_FAVORITE_KEY, isFav);

        synchronized (mLock) {
            mPeople.add(person);
        }
        processQueue();
    }

    public boolean processQueue() {
        boolean running = false;

        synchronized (mLock) {
            if (mRunningTask == null) {
                if (mPeople.size() > 0) {

                    mRunningTask = new AddTask(null);
                    mRunningTask.execute();
                    running = true;
                } else {
                    // queue is empty no need waste starting an async task
                    running = false;
                }
            } else {
                // async task is already running since it isn't null
                running = false;
            }
        }
        return running;
    }

    protected void onProcessQueueCompleted() {
        mRunningTask = null;
    }

    private class AddTask extends AsyncTask<Void, ParseObject, Boolean> {
        AddPersonAsyncQueue mAddPersonAsyncQueue;

        public AddTask(AddPersonAsyncQueue queue) {
            mAddPersonAsyncQueue = queue;
        }

        @Override
        protected Boolean doInBackground(Void... voids) {
            boolean errors = false;
            ParseObject nextObject = null;

            while (!isCancelled()) {

                synchronized (mLock) {
                    if (mPeople.size() == 0) {
                        break;
                    } else {
                        // always take the oldest item fifo
                        nextObject = mPeople.remove(0);
                    }
                }

                if (alreadyHasPhoneNumber(nextObject.getInt(ParseKey.PERSON_PHONE_NUMBER_KEY))) {
                    // do nothing as we don't want to add a duplicate
                    errors = true;
                } else if (addPerson(nextObject)) {
                    // nice we were able to add successfully

                } else {
                    // we weren't able to add the person object we had an error
                    errors = true;
                }

            }
            return errors;
        }

        private boolean alreadyHasPhoneNumber(int phoneNumber) {
            try {
                ParseQuery<ParseObject> query = ParseQuery.getQuery(ParseClass.PERSON_CLASS);
                query.whereEqualTo(ParseKey.PERSON_PHONE_NUMBER_KEY, phoneNumber);
                query.fromLocalDatastore();
                List<ParseObject> objects = query.find();
                return objects.size() > 0;
            } catch (Exception error) {
                // may need different logic here to do in the even of an error
                return true;
            }
        }

        private boolean addPerson(ParseObject person) {
            try {
                // now we finally add the person
                person.pin();
                return true;
            } catch (ParseException e) {
                e.printStackTrace();
                return false;
            }
        }

        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
            onProcessQueueCompleted();
        }
    }


}
于 2016-01-05T13:30:21.570 に答える
0

データベースに保存する前に、重複レコードを削除する必要があります。およびメソッドHashSetをオーバーライドして人物オブジェクトを使用および作成すると、重複レコードの問題が解決されます。電話番号は一意の値であるため、電話番号が他の番号と等しい場合は、そのうちの 1 つだけを保存する必要があります。これは、フィールドのみを使用してオブジェクトのメソッドをオーバーライドする必要があることを意味します。equals()hashCode()equals()hashCode()Personphone

public class Person {
    private String name;
    private String phone;
    private boolean isFav;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public boolean isFav() {
        return isFav;
    }

    public void setFav(boolean isFav) {
        this.isFav = isFav;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((phone == null) ? 0 : phone.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (phone == null) {
            if (other.phone != null)
                return false;
        } else if (!phone.equals(other.phone))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", phone=" + phone + ", isFav=" + isFav + "]";
    }
}

テスト:

public static void main(String[] args) {

    HashSet<Person> persons = new HashSet<Person>();

    Person person;

    person = new Person();
    person.setName("Joe");
    person.setPhone("+199999");
    person.setFav(false);
    persons.add(person);

    person = new Person();
    person.setName("Jessie");
    person.setPhone("+133333");
    person.setFav(false);
    persons.add(person);

    person = new Person();
    person.setName("Johnny");
    person.setPhone("+199999");
    person.setFav(false);
    persons.add(person);

    System.out.println(persons);
}

版画:

[人 [name=Joe, phone=+199999, isFav=false], Person [name=Jessie, phone=+133333, isFav=false]]

HashSet にはPerson、一意の電話番号を持つオブジェクトがあります。Johnny は Joe と同じ電話番号を持っているためHashSet、Johnny をリストに追加することを拒否します。

CallBackまた、メソッド onを追加するputPerson()と、ピン留め操作の失敗について役立ちます。

person.pinInBackground( new SaveCallback() {

    @Override
    public void done( ParseException e ) {
        if( e == null ) {
            pinnedPersonList.add(person)
        } else {
            unPinnedPersonList.add(person)
        }
    }
} );
于 2015-12-30T13:20:52.150 に答える