仿京東商城系列6------下拉刷新上拉加載的商品列表

本項目來自菜鳥窩,有興趣者點擊http://www.cniao5.com/course/

項目已經做完,
https://github.com/15829238397/CN5E-shop


仿京東商城系列0------項目簡介
仿京東商城系列1------fragmentTabHost實現底部導航欄
仿京東商城系列2------自定義toolbar
仿京東商城系列3------封裝Okhttp
仿京東商城系列4------輪播廣告條
仿京東商城系列5------商品推薦欄
仿京東商城系列6------下拉刷新上拉加載的商品列表
仿京東商城系列7------商品分類頁面
仿京東商城系列8------自定義的數量控制器
仿京東商城系列9------購物車數據存儲器實現
仿京東商城系列10------添加購物車,管理購物車功能實現
仿京東商城系列11------商品排序功能以及布局切換實現(Tablayout)
仿京東商城系列12------商品詳細信息展示(nativie與html交互)
仿京東商城系列13------商品分享(shareSDK)
仿京東商城系列14------用戶登錄以及app登錄攔截
仿京東長城系列15------用戶注冊,SMSSDK集成
仿京東商城系列16------支付SDK集成
仿京東商城系列17------支付功能實現
仿京東商城系列18------xml文件讀取(地址選擇器)
仿京東商城系列19------九宮格訂單展示
仿京東商城系列20------終章


前言

本篇文章所設計的效果,將用到前文講述到的Okhttp封裝工具,adapter封裝工具,以及本文新涉及到的,新的圖片加載工具,緩沖框架等等。廢話少說,來看效果。

內容

Fresco簡介

Fresco 的詳細介紹

  1. Fresco 是什么

首先,Fresco 是一款開源的圖片加載組件,也是目前最強大的圖片加載組件。
其次,Fresco 中設計有一個叫做 image pipeline 的模塊。它負責從網絡,從本地文件系統,本地資源加載圖片。 為了最大限度節省空間和CPU時間,它含有3級緩存設計(2級內存,1級文件)。
另外,還有一個特別的地方,Fresco 中設計有一個叫做 Drawees 模塊, 方便地顯示 loading 圖,當圖片不再顯示在屏幕上時,及時地釋放內存和空間占用。
同時,Fresco 支持 Android 2.3(API level 9)及其以上版本。

  1. Fresco 的獨特之處

Fresco 作為眾多開源圖片加載組件之一,可以受到廣大開發者的喜愛,自然有著它的獨特之處。

2.1 內存管理

一個沒有未壓縮的圖片,即 Android 中的 Bitmap,占用大量的內存。大的內存占用勢必引發更加頻繁的GC。 在5.0以下,GC 將會顯著地引發界面卡頓。
在5.0以下系統,Fresco 將圖片放到一個特別的內存區域,也就是 Ashmem (系統匿名共享內存)。當然,在圖片不顯示的時候,占用的內存會自動被釋放。 這會使得 APP 更加流暢,減少因圖片內存占用而引發的 OOM。

2.2 漸進式呈現圖片

Fresco 加載圖片時,可以實現漸進式呈現圖片,漸進式的 JPEG 圖片格式已經流行數年了,漸進式圖片格式先呈現大致的圖片輪廓,然后隨著圖片下載的繼續, 呈現逐漸清晰的圖片,這對于移動設備,尤其是慢網絡有極大的利好,可帶來更好的用戶體驗。

2.3 支持Gif圖和WebP格式

作為加載組件,Fresco 不僅支持簡單的 JPG、PNG 格式的圖片加載,還同時支持 Gif 和 WebP 格式的圖片加載,非常強大。

2.4 圖像的呈現方式

Fresco 的圖像呈現方式也很特別,可以自定義居中焦點(對人臉等圖片顯示非常有幫助),支持圓角圖,當然圓圈也行,并且下載失敗之后,點擊可以重新下載,特別是可以自定義占位圖,自定義 overlay, 或者進度條,同時可以指定用戶按壓時的 overlay。

2.5 圖像的加載

圖像的加載時很重要的一部分,Fresco 可以為同一個圖片指定不同的遠程路徑,或者使用已經存在本地緩存中的圖片,加載時先顯示一個低解析度的圖片,等高清圖下載完之后再顯示高清圖,等到加載完成時回調通知,并且對于本地圖,如有 EXIF 縮略圖,在大圖加載完成之前,可先顯示縮略圖。至于縮放或者旋轉圖片和處理已下載的圖片,Fresco 都是可以做到的。

Fresco 的基本使用

前面已經對 Fresco 做了非常詳細的介紹了,對于 Fresco 一定很感興趣吧,下面就開始使用它吧。

  1. 添加 Gradle 依賴

在使用 Fresco 之前,一定要記得先使用 Gradle 添加對 Fresco 的依賴,代碼如下。、

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:25.0.1'
    compile 'com.facebook.fresco:fresco:0.12.0'
}
  1. 添加權限

加載網絡圖片時,需要一定的網絡權限,所以必須添加網絡權限。

<uses-permission android:name="android.permission.INTERNET"/>
  1. 初始化 Fresco

在加載圖片之前,你必須初始化 Fresco 類。你只需要調用 Fresco.initialize() 一次即可完成初始化,在 Application 里面做這件事再適合不過了(如下面的代碼),注意多次的調用初始化是無意義的。

public class CniaoApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Fresco.initialize(this,config);
    }
}

下面就是需要在 AndroidManifest.xml 中指定相應的 Application 類。

<application
        android:name=".CniaoApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
     .......
</application>
  1. 添加 SimpleDraweeView

首先,在 xml 布局文件 Layout 中, 加入命名空間。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fresco="http://schemas.android.com/apk/res-auto"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
   ......
</LinearLayout>

然后在布局中加入 SimpleDraweeView。

<com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/image_view"
        android:layout_width="500dp"
        android:layout_height="300dp"
        fresco:placeholderImage="@drawable/default_loading"
/>
  1. 加載圖片

在 Activity/Fragment 中寫入圖片加載即可。

public class MainActivity extends AppCompatActivity {
    private  String img_url="http://img4q.duitang.com/uploads/item/201411/20/20141120132318_3eAuc.thumb.700_0.jpeg";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Uri uri = Uri.parse(img_url);
        SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.image_view);
        draweeView.setImageURI(uri);
     }
}

MaterialRefreshLayout簡介

MaterialRefreshLayout是github上的一個開源控件,這款組件在原本官方的控件 SwipeRefreshLayout 上做了擴展,不僅可以支持下拉刷新,還可以支持加載更多。

  • 使用方式
  1. 添加依賴
 compile 'com.cjj.materialrefeshlayout:library:1.3.0'
  1. 在布局文件中使用,本例使用了MaterialRefreshLayout+RecyclerView組合的方式,實現下拉刷新,加載更多功能,具體代碼如下:
<com.cjj.MaterialRefreshLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/materialRefreshLayout">

    <android.support.v7.widget.RecyclerView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/resyclerView"></android.support.v7.widget.RecyclerView>

    </com.cjj.MaterialRefreshLayout>
  1. 在Activity或者Fragment中進行使用。
    3.1.實例化MaterialRefreshLayout和 RecyclerView
@ViewInject(R.id.recycler_view_hot)
private RecyclerView mRecyclerView;

@ViewInject(R.id.refresh)
private MaterialRefreshLayout materialRefreshLayout;

3.2.獲得數據,計算當前頁,總頁數和每頁的數目,用于MaterialRefreshLayout進行分頁處理

private int totlaPage = 1;
private int curPage = 1;
private int pageSize = 10;
private OkHttpHelper httpHelper = OkHttpHelper.getInstance();
private List<Wares> waresList = new ArrayList<>();
private void getData( ){
    httpHelper.get(url, new SpotsCallBack<Page<Wares>>(getContext()) {
        @Override
        public void onSuccess(Response response, Page<Wares> waresPage) {
            waresList = waresPage.getList();
            curPage = waresPage.getCurrentPage();
            pageSize = waresPage.getPageSize();
            totlaPage = waresPage.getTotalPage();
            showData();
        }
        @Override
        public void onError(Response response, int code, Exception e) {
        }
    });
}

3.3.RecyclerView顯示數據,此時RecyclerView不知是按照之前的方式(設置適配器)來顯示數據了,而是按照不同的狀態來顯示數據

private static final int STATE_NORMAL = 0;
private static final int STATE_REFREN = 1;
private static final int STATE_MORE = 2;
private int state = STATE_NORMAL;
private void showData(){
    switch (state){
        case STATE_NORMAL:
         //此處完成正常加載操作
            break;

        case STATE_REFREN:
           //此處完成刷新操作
            materialRefreshLayout.finishRefresh();
            break;

        case STATE_MORE:
           //此處完成加載更多操作
            materialRefreshLayout.finishRefreshLoadMore();
            break;
    }
}

3.4為MaterialRefreshLayout添加監聽器,來實現下拉刷新和上拉加載時的邏輯

private void initMaterialRefreshLayout(){
    materialRefreshLayout.setLoadMore(true);
    materialRefreshLayout.setMaterialRefreshListener(new MaterialRefreshListener() {
           @Override
           public void onRefresh(final MaterialRefreshLayout materialRefreshLayout) {
                   //refreshing...
               refreshData();
           }
           @Override
           public void onRefreshLoadMore(MaterialRefreshLayout materialRefreshLayout) {
               //load more refreshing...
               if(curPage <= totlaPage)
                     loadMore();
               else {
                   Toast.makeText(getContext(), "沒有更多了...", Toast.LENGTH_LONG).show();
                   materialRefreshLayout.finishRefreshLoadMore();
               }
           }
    });
}
public void refreshData(){
    curPage = 1;
    state = STATE_REFREN;
    getData();
}
private void loadMore(){
    curPage = curPage + 1;
    state = STATE_MORE;
    getData();
}

3.5適配器,用Fresco來加載圖片

public class HotWaresAdapter extends RecyclerView.Adapter<HotWaresAdapter.ViewHolder>  {
    private List<Wares> mDatas;
    private LayoutInflater mInflater;
    public HotWaresAdapter(List<Wares> wares){
        mDatas = wares;
    }
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        mInflater = LayoutInflater.from(parent.getContext());
        View view = mInflater.inflate(R.layout.template_hot_wares,null);
        return new ViewHolder(view);
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Wares wares = getData(position);
        holder.draweeView.setImageURI(Uri.parse(wares.getImgUrl()));
        holder.textTitle.setText(wares.getName());
        holder.textPrice.setText("¥"+wares.getPrice());
    }
    public Wares getData(int position){
        return mDatas.get(position);
    }
    public List<Wares> getDatas(){
        return  mDatas;
    }
    public void clearData(){
        mDatas.clear();
        notifyItemRangeRemoved(0,mDatas.size());
    }
    public void addData(List<Wares> datas){

        addData(0,datas);
    }
    public void addData(int position,List<Wares> datas){
        if(datas !=null && datas.size()>0) {
            mDatas.addAll(datas);
            notifyItemRangeChanged(position, mDatas.size());
        }
    }
    @Override
    public int getItemCount() {
        if(mDatas!=null && mDatas.size()>0)
            return mDatas.size();
        return 0;
    }
    class ViewHolder extends RecyclerView.ViewHolder{
        SimpleDraweeView draweeView;
        TextView textTitle;
        TextView textPrice;
        public ViewHolder(View itemView) {
            super(itemView);
            draweeView = (SimpleDraweeView) itemView.findViewById(R.id.drawee_view);
            textTitle= (TextView) itemView.findViewById(R.id.text_title);
            textPrice= (TextView) itemView.findViewById(R.id.text_price);
        }
    }
}

封裝下拉刷新頁面功能

  • 將分頁所需信息,封裝在一個數據類中
package com.example.shoppingstore.Bean;

import java.util.List;

/**
 * Created by 博 on 2017/7/13.
 */

public class Page<T> {

    private int totalCount ;
    private int currentPage ;
    private int totalPage ;
    private int pageSize ;
    private List<Ware> list ;

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public List<Ware> getList() {
        return list;
    }

    public void setList(List<Ware> list) {
        this.list = list;
    }
}

  • 對分頁功能進行封裝,我們來先看一下代碼,我們再逐步分析。
package com.example.cne_shop.utils;

import android.content.Context;
import android.widget.Toast;

import com.cjj.MaterialRefreshLayout;
import com.cjj.MaterialRefreshListener;
import com.example.cne_shop.bean.Page;
import com.example.cne_shop.bean.Ware;
import com.example.cne_shop.okhttp.OkhttpHelper;
import com.example.cne_shop.okhttp.loadingSpotsDialog;
import com.squareup.okhttp.Response;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by 博 on 2017/7/15.
 */

public class Pager {

    private List<Ware> mData ;
    private static final int STATUS_NORMAL = 0 ;
    private static final int STATUS_FRESH = 1 ;
    private static final int STATUS_LOADMARE = 2 ;

    private int status = STATUS_NORMAL ;

    //定義一個靜態實例,接收數據,生成一個Pager實例對象
    private static Pager.Builder builder ;

    private OkhttpHelper okhttpHelper;

    private Pager(){

        okhttpHelper = OkhttpHelper.getOkhttpHelper() ;
        getData() ;
        setMaterialRefreshLayoutListener(builder.materialRefreshLayout) ;

    }

    public void changeParamsInUri(String key , Integer value){

        builder.params.put(key , value+"") ;

    }

    public int getTotalCount (){
        return this.builder.totalCount ;
    }

    //對MaterialRefreshLayout添加事件。實現上滑和下拉。
    public void setMaterialRefreshLayoutListener (MaterialRefreshLayout materialRefreshLayout ){
        materialRefreshLayout.setLoadMore(true);
        materialRefreshLayout.setMaterialRefreshListener(new MaterialRefreshListener() {
            @Override
            public void onRefresh(MaterialRefreshLayout materialRefreshLayout) {

                Toast.makeText(materialRefreshLayout.getContext() , "刷新" , Toast.LENGTH_SHORT).show();
                freshData() ;
            }

            @Override
            public void onRefreshLoadMore(MaterialRefreshLayout materialRefreshLayout) {

                if( builder.curPage*builder.pageSize < builder.totalCount ){
                    Toast.makeText(materialRefreshLayout.getContext() , "加載更多" , Toast.LENGTH_SHORT).show();
                    loadMore() ;
                }else {
                    materialRefreshLayout.finishRefreshLoadMore();
                    Toast.makeText(materialRefreshLayout.getContext() , "已經到底啦" , Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    //實現刷新數據功能
    public void freshData(){
        status = STATUS_FRESH ;
        builder.curPage = 1 ;

        builder.putParams("curPage" , builder.curPage) ;
        getData();

    }

    //實現加載更多功能
    public void loadMore(){
        status = STATUS_LOADMARE ;
        builder.curPage = builder.curPage + 1 ;

        builder.putParams("curPage" , builder.curPage) ;
        getData();
    }

    //從服務器獲得數據
    public void getData(){
        okhttpHelper.doGet(builder.uri , new PageCallBack(builder.context) , builder.params);
    }

    //展示得到的數據
    public <T> void showData(List<T> mData , int totalPage , int pageSize){

        switch (status){
            case STATUS_NORMAL :

                if (builder.onPageListener !=null ){
                    builder.onPageListener.loadNormal(mData , totalPage ,pageSize);
                }

                break;
            case STATUS_LOADMARE :

                if (builder.onPageListener !=null ){
                    builder.onPageListener.loadMoreData(mData , totalPage ,pageSize);
                }
                builder.materialRefreshLayout.finishRefreshLoadMore();
                status = STATUS_NORMAL ;
                break;
            case STATUS_FRESH :

                if (builder.onPageListener !=null ){
                    builder.onPageListener.refData(mData , totalPage ,pageSize);
                }
                builder.materialRefreshLayout.finishRefresh();
                status = STATUS_NORMAL ;
                break;
        }
    }

    public static Pager.Builder getBuilder(){

        return  builder = new Builder() ;
    }

    public interface OnPageListener<T>{
        void loadNormal(List<T> mData , int totalPage , int pageSize) ;
        void loadMoreData(List<T> mData , int totalPage , int pageSize);
        void refData(List<T> mData , int totalPage , int pageSize) ;
    }

    /**
     * 用來盛放所需要的所有數據。只涉及到數據的存取
     */
    public static class Builder {

        public int curPage = 1 ;
        private int pageSize = 10 ;
        public int totalCount = 1 ;
        private String uri ;
        private MaterialRefreshLayout materialRefreshLayout ;
        private Type type ;
        private Context context ;
        private OnPageListener onPageListener ;
        private List<Ware> mData ;
        public Map<String, String> params ;

        public Map<String, String> getParams() {
            return params;
        }

        public Builder (){
            params = new HashMap<>();
        }

        public Builder setOnPageListener(OnPageListener onPageListener){
            builder.onPageListener = onPageListener ;
            return builder;
        }

        public Builder setMaterialRefreshLayout(MaterialRefreshLayout materialRefreshLayout){

            builder.materialRefreshLayout = materialRefreshLayout ;
            return builder ;

        }

        public Builder setUri(String uri){

            builder.uri = uri ;
            return builder ;

        }

        public Pager build(Context context , Type type) throws Exception {

            builder.type = type ;
            builder.context = context ;

            isVisible() ;

            return new Pager() ;
        }

        public void isVisible() throws Exception {
            if(builder.uri == null || builder.curPage==0 && builder.pageSize==0){
                throw new Exception("uri 為空") ;
            }
        }

        public Builder putParams(String Key , Object value){
            builder.params.put(Key , value+"") ;
            return builder ;
        }


    }

    /**
     * 繼承loadingSpotsDialog<Page<T>>實現對網絡加載攔截處理。
     * @param <T>
     */
    class PageCallBack<T> extends loadingSpotsDialog<Page<T>> {

        public PageCallBack(Context context){
            super(context);
            this.type = builder.type ;
        }

        @Override
        public void onErroe(Response response, int responseCode, Exception e) throws IOException {
            this.closeSpotsDialog();
        }

        @Override
        public void callBackSucces(Response response, Page<T> page) throws IOException {

            builder.curPage = page.getCurrentPage() ;
            builder.totalCount = page.getTotalCount() ;

            showData(page.getList() , page.getTotalPage() , page.getPageSize());
            this.closeSpotsDialog();
        }
    }

}

簡單陳述:

  • 定義了一個靜態內部類Builder,Builder類用來盛放分頁刷新處理所需要的所有對象。

  • 定義了一個內部類繼承了loadingSpotsDialog<Page<T>>實現了對網絡請求的攔截處理,在這部分完成將從服務器獲得的新的數據賦值給Builder,更新curPage , totalCount 。并將得到的商品信息展示到頁面。

  • 定義了一個接口,將具體處理展示數據的過程交給調用者實現。

  • 給MaterialRefreshLayout添加事件監聽。

  • 上述為Page所做的事情。我們來大概理一遍執行順序,首先,調用靜態方法得到Builder類的對象,然后向對象添加curPage,pageSize, uri,MaterialRefreshLayout實例,OnPageListener接口實例等所需要的初始值,最后調用build方法。在build方法中調用了new page()方法,間接調用了setMaterialRefreshLayoutListener方法,對MaterialRefreshLayout添加監聽事件,一旦監聽到有上滑或者下拉動作時,將會立即執行相關方法,即更新uri(如果還有數據可供加載),調用getdata方法,通過okhttp對服務器發出請求,獲得新的數據,在我們新定義的類PageCallBack中處理了,請求結果。如果成功則調用showData()方法,對得到的數據進行展示。而showData()調用了,我們自定義接口的方法。這些方法需要調用者自行實現。

  • 上面已經講述了封裝的page執行的大概過程,下面給出使用封裝的代碼

  public void initMaterialRefreshLayout() throws Exception {

        String uri = Contents.API.HOT ;

        Pager.Builder builder = Pager.getBuilder()
                .setMaterialRefreshLayout(materialRefreshLayout)
                .putParams("curPage" , 1)
                .putParams("pageSize" , 10)
                .setUri(uri)
                .setOnPageListener(new Pager.OnPageListener<Ware>() {
                    @Override
                    public void loadNormal(List<Ware> mData, int totalPage, int pageSize) {
                        mHotAdapter =new HotAdapter(mContext , mData ) ;
//                        setItemlistenler() ;
                        recyclerView.setAdapter(mHotAdapter);
                        recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
                        recyclerView.addItemDecoration(new MyDivider());
                    }

                    @Override
                    public void loadMoreData(List<Ware> mData, int totalPage, int pageSize) {
                        mHotAdapter.addData(mData);
                    }

                    @Override
                    public void refData(List<Ware> mData, int totalPage, int pageSize) {
                        mHotAdapter.cleanData();
                        mHotAdapter.addData(mData);
                        recyclerView.scrollToPosition(0);
                    }
                }) ;

        pager = builder.build(mContext , Page.class) ;

    }

我們的封裝已經結束,大家快去使用吧。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容