/** 更新列表数据 */
  private void refreshData(final int from, int to) {
    mErrorLayout.setVisibility(View.GONE);
    BUApi.getForumThreads(
        this,
        mFid,
        from,
        to,
        new Response.Listener<JSONObject>() {
          @Override
          public void onResponse(JSONObject response) {
            if (isFinishing()) return;
            try {
              mSwipeRefreshLayout.setRefreshing(false);

              if (BUApi.checkStatus(response)) {
                JSONArray newListJson = response.getJSONArray("threadlist");
                List<me.ihainan.bu.app.models.Thread> newThreads =
                    BUApi.MAPPER.readValue(
                        newListJson.toString(), new TypeReference<List<Thread>>() {});

                // 重新加载
                if (from == 0) {
                  mThreadList.clear();
                  mAdapter.notifyDataSetChanged();
                }

                // 删除 Loading Progress Bar
                if (mThreadList.size() > 0) {
                  mThreadList.remove(mThreadList.size() - 1);
                  mAdapter.notifyItemRemoved(mThreadList.size());
                }

                // 更新 RecyclerView
                if (from == 0) mThreadList.clear();
                mCurrentPosition += BUApplication.LOADING_THREADS_COUNT;
                mThreadList.addAll(newThreads);
                mAdapter.notifyDataSetChanged();

                // 更新标志
                mIsLoading = false;
              } else if ("forum+need+password".equals(response.getString("msg"))) {
                String message = getString(R.string.error_forum_need_password);
                String debugMessage = message + " - " + response;
                Log.w(TAG, debugMessage);
                CommonUtils.debugToast(ThreadListActivity.this, debugMessage);
                showErrorLayout(message);
              } else {
                String message =
                    getString(R.string.error_unknown_msg) + ": " + response.getString("msg");
                String debugMessage = message + " - " + response;
                Log.w(TAG, debugMessage);
                CommonUtils.debugToast(ThreadListActivity.this, debugMessage);
                showErrorLayout(message);
              }
            } catch (Exception e) {
              // 解析失败的话,说明到头了,移除标志,不允许再次更新(mIsLoading 始终为 true)
              if (mThreadList.size() > 0) {
                Log.d(TAG, "refreshData >> 到头了 " + response);
                mThreadList.remove(mThreadList.size() - 1);
                mAdapter.notifyItemRemoved(mThreadList.size());
              }

              mSwipeRefreshLayout.setRefreshing(false);
              Log.e(TAG, getString(R.string.error_parse_json) + "\n" + response, e);
            }
          }
        },
        new Response.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError error) {
            if (isFinishing()) return;
            mSwipeRefreshLayout.setRefreshing(false);

            // 服务器请求失败,说明网络不好,移除标志,运行再次发送请求
            if (mThreadList.size() > 0) {
              mThreadList.remove(mThreadList.size() - 1);
              mAdapter.notifyItemRemoved(mThreadList.size());
            }

            mIsLoading = false;

            if (mThreadList.size() > 0) {
              mThreadList.remove(mThreadList.size() - 1);
              mAdapter.notifyItemRemoved(mThreadList.size());
            }

            String message = getString(R.string.error_network);
            String debugMessage = "getForumThreads >> " + message;
            CommonUtils.debugToast(ThreadListActivity.this, debugMessage);
            showErrorLayout(message);
            Log.e(TAG, debugMessage, error);
          }
        });
  }
  /**
   * 获取用户信息并执行特定操作,如果用户信息已经被缓存,则直接从缓存中获取,否则从服务器拉取并进行缓存
   *
   * @param context 上下文
   * @param userName 用户名
   * @param callback 包含回调函数
   */
  public static void getAndCacheUserInfo(
      final Context context, String userName, final UserInfoAndFillAvatarCallback callback) {

    userName = CommonUtils.decode(userName);

    // 从缓存中获取用户信息
    final Member member =
        (Member)
            BUApplication.getCache(context).getAsObject(BUApplication.CACHE_USER_INFO + userName);

    if (member != null) {
      Log.i(
          TAG, "从缓存 " + BUApplication.CACHE_USER_INFO + userName + " 中获取用户 " + userName + " 的缓存数据");

      // Do something HERE!!!
      callback.doSomethingIfHasCached(member);
    } else {
      Log.i(TAG, "准备拉取用户 " + userName + " 的缓存数据");

      // 从服务器拉取数据并写入到缓存当中
      final String finalUserName = userName;
      BUApi.getUserInfo(
          context,
          -1,
          userName,
          new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
              // if (((Activity) context).isFinishing()) return;
              try {
                if (BUApi.checkStatus(response)) {
                  Member newMember =
                      BUApi.MAPPER.readValue(
                          response.getJSONObject("memberinfo").toString(), Member.class);

                  // Do something HERE!!!
                  callback.doSomethingIfHasNotCached(newMember);

                  // 将用户信息放入到缓存当中
                  Log.i(
                      TAG,
                      "拉取得到用户 "
                          + finalUserName
                          + " 的数据,放入缓存 "
                          + BUApplication.CACHE_USER_INFO
                          + finalUserName
                          + " 中:"
                          + newMember);
                  BUApplication.getCache(context)
                      .put(
                          BUApplication.CACHE_USER_INFO + finalUserName,
                          newMember,
                          BUApplication.USER_INFO_CACHE_DAYS * ACache.TIME_DAY);
                } else if ("member_nonexistence".equals(response.getString("msg"))) {
                  String message =
                      context.getString(R.string.error_user_not_exists)
                          + ": "
                          + CommonUtils.decode(finalUserName);
                  String debugMessage = message + " - " + response;
                  Log.w(TAG, debugMessage);
                  CommonUtils.debugToast(context, debugMessage);
                } else {
                  String message =
                      context.getString(R.string.error_unknown_msg)
                          + ": "
                          + response.getString("msg");
                  String debugMessage = message + " - " + response;
                  Log.w(TAG, debugMessage);
                  CommonUtils.debugToast(context, debugMessage);
                }
              } catch (Exception e) {
                Log.e(TAG, context.getString(R.string.error_parse_json) + "\n" + response, e);
              }
            }
          },
          new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
              if (((Activity) context).isFinishing()) return;
              String message = context.getString(R.string.error_network);
              String debugMessage = "getAndCacheUserInfo >> " + message;
              CommonUtils.debugToast(context, debugMessage);
              Log.e(TAG, debugMessage, error);
            }
          });
    }
  }