Retrofit全攻略——進(jìn)階篇

最近事比較多属划,距離上次寫文章已經(jīng)過(guò)去了一個(gè)月了。上一篇文章Retrofit全攻略——基礎(chǔ)篇 介紹了Retrofit的基礎(chǔ)用法候生,這篇文章介紹點(diǎn)進(jìn)階的用法同眯。

打印網(wǎng)絡(luò)日志

在開(kāi)發(fā)階段,為了方便調(diào)試唯鸭,我們需要查看網(wǎng)絡(luò)日志须蜗。因?yàn)?code>Retrofit2.0+底層是采用的OKHttp請(qǐng)求的∧扛龋可以給OKHttp設(shè)置攔截器明肮,用來(lái)打印日志。
首先可以在app/build.gradle中添加依賴缭付,這是官方的日志攔截器柿估。

compile 'com.squareup.okhttp3:logging-interceptor:3.3.0'

然后在代碼中設(shè)置:

    public static Retrofit getRetrofit() {
        //如果mRetrofit為空  或者服務(wù)器地址改變 重新創(chuàng)建
        if (mRetrofit == null) {
            OkHttpClient httpClient;
            OkHttpClient.Builder builder=new OkHttpClient.Builder();
            
            //階段分為開(kāi)發(fā)和發(fā)布階段,當(dāng)前為開(kāi)發(fā)階段設(shè)置攔截器
            if (BuildConfig.DEBUG) {
                HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
                //設(shè)置攔截器級(jí)別
                logging.setLevel(HttpLoggingInterceptor.Level.BODY);
                builder.addInterceptor(logging);
            }
            httpClient=builder.build();
            //構(gòu)建Retrofit
            mRetrofit = new Retrofit.Builder()
                    //配置服務(wù)器路徑
                    .baseUrl(mServerUrl)
                    //返回的數(shù)據(jù)通過(guò)Gson解析
                    .addConverterFactory(GsonConverterFactory.create())
                    //配置回調(diào)庫(kù)陷猫,采用RxJava
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    //設(shè)置OKHttp模板
                    .client(httpClient)
                    .build();
        }
        return mRetrofit;
    }

當(dāng)處于開(kāi)發(fā)階段的時(shí)候秫舌,設(shè)置監(jiān)聽(tīng)日志的攔截器的妖。攔截有4個(gè)級(jí)別,分別是

  1. BODY
  2. HEADERS
  3. BASIC
  4. NONE

其中BODY輸出的日志是最全的足陨。

添加相同的請(qǐng)求參數(shù)

為了更好的管理迭代版本嫂粟,一般每次發(fā)起請(qǐng)求的時(shí)候都傳輸當(dāng)前程序的版本號(hào)到服務(wù)器。
有些項(xiàng)目我們每次還會(huì)傳用戶id墨缘,token令牌等相同的參數(shù)星虹。
如果在每個(gè)請(qǐng)求的接口都添加這些參數(shù)太繁瑣。Retrofit可以通過(guò)攔截器添加相同的請(qǐng)求參數(shù)镊讼,無(wú)需再每個(gè)接口添加了搁凸。

步驟一,自己攔截器

public class CommonInterceptor implements Interceptor {
    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request oldRequest = chain.request();

        // 添加新的參數(shù)
        HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()
                .newBuilder()
                .scheme(oldRequest.url().scheme())
                .host(oldRequest.url().host())
                .addQueryParameter("device_type", "1")
                .addQueryParameter("version", BuildConfig.VERSION_NAME)
                .addQueryParameter("token", PreUtils.getString(R.string.token))
                .addQueryParameter("userid", PreUtils.getString(R.string.user_id));

        // 新的請(qǐng)求
        Request newRequest = oldRequest.newBuilder()
                .method(oldRequest.method(), oldRequest.body())
                .url(authorizedUrlBuilder.build())
                .build();

        return chain.proceed(newRequest);
    }
}

實(shí)現(xiàn)原理就是攔截之前的請(qǐng)求狠毯,添加完參數(shù)护糖,再傳遞新的請(qǐng)求。這個(gè)位置我添加了四個(gè)公共的參數(shù)嚼松。
然后再Retrofit初始化的時(shí)候配置嫡良。

        if (mRetrofit == null) {
            OkHttpClient httpClient;
            OkHttpClient.Builder builder=new OkHttpClient.Builder();
            //添加公共參數(shù)
            builder.addInterceptor(new CommonInterceptor());
            httpClient=builder.build();
            //構(gòu)建Retrofit
            mRetrofit = new Retrofit.Builder()
                    //....
                    .client(httpClient)
                    .build();
        }

處理約定錯(cuò)誤

除了常見(jiàn)的404,500等異常献酗,網(wǎng)絡(luò)請(qǐng)求中我們往往還會(huì)約定些異常寝受,比如token失效,賬號(hào)異常等等罕偎。

以token失效為例很澄,每次請(qǐng)求我們都需要驗(yàn)證是否失效,如果在每個(gè)接口都處理一遍錯(cuò)誤就有點(diǎn)太繁瑣了颜及。

我們可以統(tǒng)一處理下錯(cuò)誤甩苛。

步驟一,Retrofit初始化時(shí)添加自定義轉(zhuǎn)化器

mRetrofit = new Retrofit.Builder()
        //配置服務(wù)器路徑
      baseUrl(mServerUrl)
      //配置回調(diào)庫(kù)俏站,采用RxJava
     .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
     //配置轉(zhuǎn)化庫(kù)讯蒲,默認(rèn)是Gson,這里修改了肄扎。
     .addConverterFactory(ResponseConverterFactory.create())
     .client(httpClient)
     .build();

步驟二 創(chuàng)建ResponseConverterFactory

步驟一 ResponseConverterFactory這個(gè)類是需要我們自己創(chuàng)建的墨林。

public class ResponseConverterFactory extends Converter.Factory {
    /**
     * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static ResponseConverterFactory create() {
        return create(new Gson());
    }

    /**
     * Create an instance using {@code gson} for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static ResponseConverterFactory create(Gson gson) {
        return new ResponseConverterFactory(gson);
    }

    private final Gson gson;

    private ResponseConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
      //  TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonResponseBodyConverter<>(gson, type);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonRequestBodyConverter<>(gson, adapter);
    }
}

這里面我們自定義了請(qǐng)求和響應(yīng)時(shí)解析JSON的轉(zhuǎn)換器——GsonRequestBodyConverterGsonResponseBodyConverter

其中GsonRequestBodyConverter 負(fù)責(zé)處理請(qǐng)求時(shí)傳遞JSON對(duì)象的格式犯祠,不需要額外處理任何事旭等,直接使用默認(rèn)的GSON解析。代碼我直接貼出來(lái):

final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private final Gson gson;
    private final TypeAdapter<T> adapter;

    GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override public RequestBody convert(T value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}

GsonResponseBodyConverter負(fù)責(zé)把響應(yīng)的數(shù)據(jù)轉(zhuǎn)換成JSON格式衡载,這個(gè)我們需要處理一下搔耕。


public class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final Type type;

    GsonResponseBodyConverter(Gson gson, Type type) {
        this.gson = gson;
        this.type = type;
    }

    @Override
    public T convert(ResponseBody value) throws IOException {
        String response = value.string();
        try {
            Log.i("YLlibrary", "response>>> "+response);
            //ResultResponse 只解析result字段
            BaseInfo baseInfo = gson.fromJson(response, BaseInfo.class);
            if (baseInfo.getHeader().getCode().equals("1")) {
                //正確
                return gson.fromJson(response, type);
            } else {
                //ErrResponse 將msg解析為異常消息文本 錯(cuò)誤碼可以自己指定.
                throw new ResultException(-1024, baseInfo,response);
            }
        } finally {
        }
    }

}

這種情況只是應(yīng)用于后臺(tái)接口數(shù)據(jù)統(tǒng)一的情況。比如我們項(xiàng)目的格式是這樣的

      {
          header : {"message":"token失效","code":"99"}
          data : {}
      }

當(dāng)code值是1的時(shí)候月劈,表示正確度迂,其它數(shù)字表示錯(cuò)誤。只有正確的時(shí)候data才會(huì)有內(nèi)容猜揪。

這里我用BaseInfo解析這個(gè)JSON:

public class BaseInfo {

    /**
     * header : {"message":"用戶名或密碼錯(cuò)誤","code":"0"}
     * data : {}
     */

    private HeaderBean header;

    public HeaderBean getHeader() {
        return header;
    }

    public void setHeader(HeaderBean header) {
        this.header = header;
    }


    public static class HeaderBean {
        /**
         * message : 用戶名或密碼錯(cuò)誤
         * code : 0
         */

        private String message;
        private String code;

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }
    }
}

服務(wù)器返回的數(shù)據(jù)實(shí)體對(duì)象全部繼承BaseInfo 只是data內(nèi)容不一樣惭墓。

ResultException這個(gè)類用于捕獲服務(wù)器約定的錯(cuò)誤類型

/**
 * 這個(gè)類用于捕獲服務(wù)器約定的錯(cuò)誤類型
 */
public class ResultException extends RuntimeException {

    private int errCode = 0;
    private BaseInfo info;
    private String response;
    public ResultException(int errCode, BaseInfo info,String response) {
        super(info.getHeader().getMessage());
        this.info=info;
        this.errCode = errCode;
        this.response=response;
    }

    public String getResponse() {
        return response;
    }

    public void setResponse(String response) {
        this.response = response;
    }

    public int getErrCode() {
        return errCode;
    }

    public BaseInfo getBaseInfo(){
        return info;
    }
}

最后定義Retrofit處理異常的代碼

public abstract class AbsAPICallback<T> extends Subscriber<T> {

    //對(duì)應(yīng)HTTP的狀態(tài)碼
    private static final int UNAUTHORIZED = 401;
    private static final int FORBIDDEN = 403;
    private static final int NOT_FOUND = 404;
    private static final int REQUEST_TIMEOUT = 408;
    private static final int INTERNAL_SERVER_ERROR = 500;
    private static final int BAD_GATEWAY = 502;
    private static final int SERVICE_UNAVAILABLE = 503;
    private static final int GATEWAY_TIMEOUT = 504;
    //出錯(cuò)提示
    private final String networkMsg;
    private final String parseMsg;
    private final String unknownMsg;

    protected AbsAPICallback(String networkMsg, String parseMsg, String unknownMsg) {
        this.networkMsg = networkMsg;
        this.parseMsg = parseMsg;
        this.unknownMsg = unknownMsg;
    }
    public  AbsAPICallback(){
        networkMsg="net error(聯(lián)網(wǎng)失敗)";
        parseMsg="json parser error(JSON解析失敗)";
        unknownMsg="unknown error(未知錯(cuò)誤)";
    }
    ProgressBar progressBar;
    public  AbsAPICallback(ProgressBar progressBar){
        this();
        this.progressBar=progressBar;
    }
    @Override
    public void onError(Throwable e) {
        Throwable throwable = e;
        //獲取最根源的異常
        while(throwable.getCause() != null){
            e = throwable;
            throwable = throwable.getCause();
        }

        ApiException ex;
        if (e instanceof HttpException){             //HTTP錯(cuò)誤
            HttpException httpException = (HttpException) e;
            ex = new ApiException(e, httpException.code());
            switch(httpException.code()){
                case UNAUTHORIZED:
                case FORBIDDEN:
                  //  onPermissionError(ex);          //權(quán)限錯(cuò)誤,需要實(shí)現(xiàn)
                   // break;
                case NOT_FOUND:
                case REQUEST_TIMEOUT:
                case GATEWAY_TIMEOUT:
                case INTERNAL_SERVER_ERROR:
                case BAD_GATEWAY:
                case SERVICE_UNAVAILABLE:
                default:
                    ex.setDisplayMessage(networkMsg);  //均視為網(wǎng)絡(luò)錯(cuò)誤
                    onNetError(ex);
                    break;
            }
        } else if (e instanceof ResultException){    //服務(wù)器返回的錯(cuò)誤
            ResultException resultException = (ResultException) e;
            onResultError(resultException);
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException){
            ex = new ApiException(e, ApiException.PARSE_ERROR);
            ex.setDisplayMessage(parseMsg);            //均視為解析錯(cuò)誤
            onNetError(ex);
        } else {
            ex = new ApiException(e, ApiException.UNKNOWN);
            ex.setDisplayMessage(unknownMsg);          //未知錯(cuò)誤
            onNetError(ex);
        }
    }
    static long time;
    protected  void onNetError(ApiException e){
        long currentTime=System.currentTimeMillis();
        if(currentTime-time>3000){  //防止連續(xù)反饋
            time=currentTime;
            UIUtils.showToast("網(wǎng)絡(luò)加載失敗");
        }
        e.printStackTrace();
        onApiError(e);
    }
    /**
     * 錯(cuò)誤回調(diào)
     */
    protected  void onApiError(ApiException ex){
        Log.i("YLLibrary","onApiError");
        if(progressBar!=null)
            UIUtils.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    progressBar.setVisibility(View.GONE);
                    progressBar=null;
                }
            });
    }

//    /**
//     * 權(quán)限錯(cuò)誤而姐,需要實(shí)現(xiàn)重新登錄操作
//     */
//    protected void  onPermissionError(ApiException ex){
//        ex.printStackTrace();
//    }

    /**
     * 服務(wù)器返回的錯(cuò)誤
     */
    protected  synchronized  void onResultError(ResultException ex){
//        if(ex.getErrCode()== XApplication.API_ERROR){
//            UIUtils.getContext().onApiError(); //可以用來(lái)處理Token失效
//            return ;
//        }
        if(ConstantValue.TOKEN_ERROR.equals(ex.getBaseInfo().getHeader().getCode())
                &&!TextUtils.isEmpty(PreUtils.getString(R.string.token))){ //驗(yàn)證token是否為空是為了防止連續(xù)兩次請(qǐng)求
            PreUtils.putString(R.string.user_id,null);
            PreUtils.putString(R.string.token,null);
            PreUtils.putString(R.string.orgDistrict,null);
            if(BaseActivity.runActivity!=null){
                Intent intent = new Intent(UIUtils.getContext(), LoginActivity.class);
                if(BaseActivity.runActivity instanceof MainActivity){
                    MainActivity activity= (MainActivity) BaseActivity.runActivity;
                    int tabIndex=activity.getCurrentTab();
                    //activity.switchCurrentTab(0);
                    activity.startActivityForResult(intent,tabIndex+10);
                }else {
                    BaseActivity.runActivity.startActivity(intent);
                }
            }
        }


        Log.i("YLLibrary","resultError");
        if(ex.getBaseInfo()!=null&&!TextUtils.isEmpty(ex.getBaseInfo().getHeader().getMessage()))
            UIUtils.showToast(ex.getBaseInfo().getHeader().getMessage());

        ApiException apiException = new ApiException(ex, ex.getErrCode());
        onApiError(apiException);
    }

    @Override
    public void onCompleted() {
        Log.i("YLLibrary","onCompleted");
        if(progressBar!=null)
            UIUtils.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    progressBar.setVisibility(View.GONE);
                    progressBar=null;
                }
            });
    }

}

實(shí)際接口請(qǐng)求的代碼腊凶,使用自定義異常回調(diào)的類——AbsAPICallback就可以統(tǒng)一處理異常:

        ApiRequestManager.createApi().problemDetail(dataBean.getId())
                .compose(ApiRequestManager.<QuestionDetailInfo>applySchedulers())
                .subscribe(new AbsAPICallback<QuestionDetailInfo>() {
                    @Override
                    public void onNext(QuestionDetailInfo baseInfo) {
                        fillData(baseInfo);
                    }
                });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拴念,一起剝皮案震驚了整個(gè)濱河市钧萍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌政鼠,老刑警劉巖风瘦,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異公般,居然都是意外死亡万搔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門官帘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瞬雹,“玉大人,你說(shuō)我怎么就攤上這事刽虹⌒锇疲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵涌哲,是天一觀的道長(zhǎng)胖缤。 經(jīng)常有香客問(wèn)我,道長(zhǎng)阀圾,這世上最難降的妖魔是什么草姻? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮稍刀,結(jié)果婚禮上撩独,老公的妹妹穿的比我還像新娘。我一直安慰自己账月,他們只是感情好综膀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著局齿,像睡著了一般剧劝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抓歼,一...
    開(kāi)封第一講書(shū)人閱讀 51,208評(píng)論 1 299
  • 那天讥此,我揣著相機(jī)與錄音拢锹,去河邊找鬼。 笑死萄喳,一個(gè)胖子當(dāng)著我的面吹牛卒稳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播他巨,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼充坑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了染突?” 一聲冷哼從身側(cè)響起捻爷,我...
    開(kāi)封第一講書(shū)人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎份企,沒(méi)想到半個(gè)月后也榄,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡司志,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年手蝎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俐芯。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡棵介,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吧史,到底是詐尸還是另有隱情邮辽,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布贸营,位于F島的核電站吨述,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏钞脂。R本人自食惡果不足惜揣云,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冰啃。 院中可真熱鬧邓夕,春花似錦、人聲如沸阎毅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)扇调。三九已至矿咕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碳柱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工捡絮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人莲镣。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓福稳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親剥悟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子灵寺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理曼库,服務(wù)發(fā)現(xiàn)区岗,斷路器,智...
    卡卡羅2017閱讀 134,652評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,081評(píng)論 25 707
  • 又是一年中秋佳節(jié)毁枯,祝各位中秋節(jié)快樂(lè)慈缔。 今天我們來(lái)聊聊這個(gè)最近很火的網(wǎng)絡(luò)請(qǐng)求庫(kù)retrofit,在此基礎(chǔ)上會(huì)延伸出一...
    涅槃1992閱讀 7,784評(píng)論 13 133
  • 昨天過(guò)來(lái)一直打點(diǎn)滴,到現(xiàn)在還沒(méi)有打完赂韵。朋友回去了娱节,老公還沒(méi)有回來(lái),女兒她干媽帶著祭示,聽(tīng)干媽說(shuō)肄满,女兒昨天要把媽媽找回來(lái)...
    嘉俐閱讀 220評(píng)論 0 0
  • ——閱讀感覺(jué)之六 熊老師您好,我是大二的學(xué)生质涛,每天心里都有著許多要做的事稠歉,但是我卻從來(lái)沒(méi)有完成過(guò),我每天都活在自責(zé)...
    熊玲心理咨詢閱讀 743評(píng)論 0 1