@Override
 public Observable<VoteResult> voteCommonItem(Long commentId, VoteType voteType) {
   return this.picService
       .voteCommonItem(voteType == VoteType.OO ? 1 : 0, commentId)
       .map(
           responseBody -> {
             try {
               return VoteResult.fromString(responseBody.string(), voteType);
             } catch (IOException e) {
               return VoteResult.Voted;
             }
           })
       .doOnNext(
           voteResult -> {
             if (voteResult == VoteResult.Thanks) {
               PicItem picItem =
                   CloudPicDataStore.this
                       .picItemDao
                       .queryBuilder()
                       .where(PicItemDao.Properties.PicId.eq(commentId))
                       .build()
                       .forCurrentThread()
                       .unique();
               if (picItem != null) {
                 if (voteType == VoteType.OO) {
                   picItem.setVotePositive(picItem.getVotePositive() + 1);
                   CloudPicDataStore.this.picItemDao.update(picItem);
                 } else if (voteType == VoteType.XX) {
                   picItem.setVoteNegative(picItem.getVoteNegative() + 1);
                   CloudPicDataStore.this.picItemDao.update(picItem);
                 }
               }
             }
           });
 }
  public CloudPicDataStore(
      ICommonItemService picService,
      ICommentService commentService,
      PicItemDao picItemDao,
      MetaDao metaDao) {
    this.picService = picService;
    this.commentService = commentService;
    this.picItemDao = picItemDao;
    this.metaDao = metaDao;

    this.refreshComment =
        picItems -> {
          CloudPicDataStore.this
              .commentService
              .getDuoshuoCommentList(
                  Joiner.on(",")
                      .join(
                          Lists.transform(
                              picItems, picItem -> Constants.THREAD_PREFIX + picItem.getPicId())))
              .subscribeOn(Schedulers.io())
              .observeOn(Schedulers.io())
              .subscribe(
                  commentCountResponse -> {
                    // TODO: optimize this with tx
                    List<PicItem> picItemList = new ArrayList<PicItem>();
                    for (String key : commentCountResponse.getResponse().keySet()) {
                      CommentCountResponse.CommentCount commentCount =
                          commentCountResponse.getResponse().get(key);
                      Long picId = commentCount.getCommonItemId();
                      logger.info("{}:{}", commentCount.getThreadKey(), commentCount.getCount());
                      PicItem picItem =
                          CloudPicDataStore.this
                              .picItemDao
                              .queryBuilder()
                              .where(PicItemDao.Properties.PicId.eq(picId))
                              .unique();
                      if (picItem != null) {
                        picItem.setCommentCount(commentCount.getCount());
                        picItem.setThreadId(commentCount.getThreadId());
                        picItemList.add(picItem);
                      }
                    }
                    if (picItemList.size() > 0)
                      CloudPicDataStore.this.picItemDao.updateInTx(picItemList);
                  },
                  throwable -> {});
        };
  }