9

Parse.com用作我的应用程序的后端。他们还提供了一个本地数据库来存储信息,作为SQLite.

我想通过解析将电话中的号码添加到我的数据库中。在添加数字之前,我需要检查该数字是否已存在于数据库中,因此我使用findInBackground()来获取与我要添加的数字匹配的数字列表。如果列表为空,则我要添加的数字在数据库中不存在。

这样做的方法是:

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

然后我调用这个方法3次添加3个数字:

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

请注意,第三个数字与第一个数字相同,不应将其添加到数据库中。但logcat节目:

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.

第三个数字即使不应该这样做也被添加了,因为fintInBackground()几乎同时在3个后台线程中运行,所以它会发现数据库中没有我想要添加的数字。

这个问题中,一个人告诉我我应该使用Bolts来自Parse. 我从这里和一些博客文章中阅读了它Parse,但我不完全理解如何将它与我已有的方法一起使用,以及如何同步要一个接一个地执行的查询。

如果有人使用此库,请指导我如何执行此操作或提供一些基本示例,以便我了解工作流程。

谢谢!

4

3 回答 3

1

听起来你有比赛条件。有很多不同的方法可以解决这个问题。这是一个非螺栓替代品。

主要问题是搜索查询几乎同时发生,因此它们在数据库中找不到重复项。在这种情况下,我们解决它的方法是一次只搜索和添加一个人,显然不是在主线程上,因为我们不想捆绑 ui 进行搜索。因此,让我们创建一个 List 来做两件事 1) 包含需要添加的项目,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

这是来自 Bolts 文档。

系列任务

当您想要连续执行一系列任务时,任务很方便,每个任务都等待前一个任务完成。例如,假设您想删除博客上的所有评论。

ParseQuery<ParseObject> query = ParseQuery.getQuery("Comments");
query.whereEqualTo("post", 123);

findAsync(query).continueWithTask(new Continuation<List<ParseObject>, Task<Void>>() {
  public Task<Void> then(Task<List<ParseObject>> results) throws Exception {
    // Create a trivial completed task as a base case.
    Task<Void> task = Task.forResult(null);
    for (final ParseObject result : results) {
      // For each item, extend the task with a function to delete the item.
      task = task.continueWithTask(new Continuation<Void, Task<Void>>() {
        public Task<Void> then(Task<Void> ignored) throws Exception {
          // Return a task that will be marked as completed when the delete is finished.
          return deleteAsync(result);
        }
      });
    }
    return task;
  }
}).continueWith(new Continuation<Void, Void>() {
  public Void then(Task<Void> ignored) throws Exception {
    // Every comment was deleted.
    return null;
  }
});

这就是它的完成方式。如果您想了解到底发生了什么,您应该阅读文档,即使它看起来很简单:)

https://github.com/BoltsFramework/Bolts-Android

于 2016-01-04T21:51:08.407 回答
0

您应该在将重复记录保存到数据库之前删除它们。使用HashSet和创建一个覆盖其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方法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 回答