图片缓存和显示能力 -- Picasso

一、基本使用

//添加依赖(build.gradle)
implementation 'com.squareup.picasso:picasso:2.5.2'

//添加网络权限(AndroidManifest.xml)
<uses-permission android:name="android.permission.INTERNET"/>

//加载网络图片(MainActivity)
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .into(imageView);
    }
}

//加载Uri路径的图片(MainActivity)
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        ImageView imageView = findViewById(R.id.imageview);
        Uri uri = Uri.parse("android.resource://" + getPackageName() + "/" + R.mipmap.ic_launcher);
        Picasso.with(this)
                .load(uri)
                .into(imageView);
    }
}

//加载本地资源图片(MainActivity)
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(R.mipmap.ic_launcher)
                .into(imageView);
    }
}

//加载File中的图片(MainActivity)
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String path = getExternalCacheDir().getAbsoluteFile() + File.separator + "ic_launcher.png";
        Log.d(TAG, "zwm, path: " + path);
        File file = new File(path);
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(file)
                .into(imageView);
    }
}

二、placeholder & error & noPlaceholder & noFade

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                //.noPlaceholder() //不显示占位图
                .error(R.mipmap.ic_launcher_round) //加载出错时显示的图片
                .noFade() //不显示渐入效果
                .into(imageView);
    }
}

三、Resize(设置图片尺寸) & Scale(缩放) & Crop(裁剪)

resize(int targetWidth, int targetHeight),以px为单位

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resize(200,200)
                .into(imageView);
    }
}

resizeDimen(int targetWidthResId, int targetHeightResId),以dp为单位

//dimens.xml
<resources>
    <dimen name="image_width">200dp</dimen>
    <dimen name="image_height">200dp</dimen>
</resources>

//MainActivity
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resizeDimen(R.dimen.image_width, R.dimen.image_height)
                .into(imageView);
    }
}

onlyScaleDown()

当调用resize方法重新设置图片尺寸,并调用了onlyScaleDown方法,只有当原始图片的尺寸大于我们指定的尺寸时,resize才起作用。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resize(200,200)
                .onlyScaleDown()
                .into(imageView);
    }
}

centerCrop()

充满View边界,居中裁剪。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resize(200,200)
                .centerCrop()
                .into(imageView);
    }
}

centerInside()

centerCrop是可能看不到全部图片的,如果想让View将图片完全展示,可以用centerInside。但是如果图片尺寸小于View尺寸的话,是不能充满View边界的。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resize(200,200)
                .centerInside()
                .into(imageView);
    }
}

fit()

充满View边界,有可能会出现拉伸扭曲的情况。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .fit()
                .into(imageView);
    }
}

四、Rotate(旋转)

rotate(float degrees)

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .rotate(180)
                .into(imageView);
    }
}

rotate(float degrees, float pivotX, float pivotY)

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .rotate(90, 200, 100)
                .into(imageView);
    }
}

五、Transformation(转换器)

Transformation是Picasso的一个非常强大的功能,它允许在加载图片的过程中对图片做一系列的变换,如高斯模糊、添加圆角、度灰处理、圆形图片等。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .transform(new BlurTransformation(this))
                .transform(new GrayTransformation())
                .into(imageView);
    }

    //高斯模糊
    private static class BlurTransformation implements Transformation {
        RenderScript rs;

        public BlurTransformation(Context context) {
            super();
            rs = RenderScript.create(context);
        }

        @Override
        public Bitmap transform(Bitmap bitmap) {
            // Create another bitmap that will hold the results of the filter.
            Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

            // Allocate memory for Renderscript to work with
            Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
            Allocation output = Allocation.createTyped(rs, input.getType());

            // Load up an instance of the specific script that we want to use.
            ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            script.setInput(input);

            // Set the blur radius
            script.setRadius(25);

            // Start the ScriptIntrinisicBlur
            script.forEach(output);

            // Copy the output to the blurred bitmap
            output.copyTo(blurredBitmap);

            bitmap.recycle();

            return blurredBitmap;
        }

        @Override
        public String key() {
            return "blur";
        }
    }

    //度灰
    private static class GrayTransformation implements Transformation{

        @Override
        public Bitmap transform(Bitmap source) {
            int width, height;
            height = source.getHeight();
            width = source.getWidth();

            Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
            Canvas c = new Canvas(bmpGrayscale);
            Paint paint = new Paint();
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);
            ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
            paint.setColorFilter(f);
            c.drawBitmap(source, 0, 0, paint);

            if(source!=null && source!=bmpGrayscale){
                source.recycle();
            }
            return bmpGrayscale;
        }

        @Override
        public String key() {
            return "gray";
        }
    }
}

或者:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        List<Transformation> transformations = new ArrayList<>();
        transformations.add(new GrayTransformation());
        transformations.add(new BlurTransformation(this));
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .transform(transformations)
                .into(imageView);
    }

    //高斯模糊
    private static class BlurTransformation implements Transformation {
        RenderScript rs;

        public BlurTransformation(Context context) {
            super();
            rs = RenderScript.create(context);
        }

        @Override
        public Bitmap transform(Bitmap bitmap) {
            // Create another bitmap that will hold the results of the filter.
            Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

            // Allocate memory for Renderscript to work with
            Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
            Allocation output = Allocation.createTyped(rs, input.getType());

            // Load up an instance of the specific script that we want to use.
            ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            script.setInput(input);

            // Set the blur radius
            script.setRadius(25);

            // Start the ScriptIntrinisicBlur
            script.forEach(output);

            // Copy the output to the blurred bitmap
            output.copyTo(blurredBitmap);

            bitmap.recycle();

            return blurredBitmap;
        }

        @Override
        public String key() {
            return "blur";
        }
    }

    //度灰
    private static class GrayTransformation implements Transformation{

        @Override
        public Bitmap transform(Bitmap source) {
            int width, height;
            height = source.getHeight();
            width = source.getWidth();

            Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
            Canvas c = new Canvas(bmpGrayscale);
            Paint paint = new Paint();
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);
            ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
            paint.setColorFilter(f);
            c.drawBitmap(source, 0, 0, paint);

            if(source!=null && source!=bmpGrayscale){
                source.recycle();
            }
            return bmpGrayscale;
        }

        @Override
        public String key() {
            return "gray";
        }
    }
}

六、请求优先级

Picasso为请求设置有优先级,有三种优先级:LOW、NORMAL、HIGH,默认情况下都是NORMAL,但是fetch方法除外,fetch方法的优先级是LOW。
可以通过priority方法设置请求的优先级,这会影响请求的执行顺序,但是这是不能保证的,它只会往高的优先级靠拢。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher)
                .priority(Picasso.Priority.HIGH)
                .into(imageView);
    }
}

七、Tag管理请求

Picasso#

  • cancelTag(Object tag):取消设置了给定tag的所有请求。
  • pauseTag(Object tag):暂停设置了给定tag的所有请求。
  • resumeTag(Object tag):resume被暂停的给定tag的所有请求。

RequestCreator#

  • tag(Object tag):为请求设置tag。
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher)
                .tag("PhotoTag")
                .into(imageView);
    }
}

使用场景1:快速滑动列表时暂停请求

//Adapter
Picasso.with(this).load(mData.get(position))
        .placeholder(R.drawable.default_bg)
        .error(R.drawable.error_iamge)
        .tag("PhotoTag")
        .into(holder.mImageView);

//Activity
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        final Picasso picasso = Picasso.with(MainActivity.this);

        if (newState == SCROLL_STATE_IDLE) {
            picasso.resumeTag("PhotoTag");
        } else {
            picasso.pauseTag("PhotoTag");
        }
    }
});

使用场景2:退出界面取消请求

@Override
protected void onDestroy() {
    super.onDestroy();
    Picasso.with(this).cancelTag("PhotoTag");
}

八、同步/异步加载图片

同步:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        final String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Bitmap bitmap = Picasso.with(MainActivity.this).load(url).get();
                    Log.d(TAG, "zwm, bitmap: " + bitmap);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

异步:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        //Picasso.with(MainActivity.this).load(url).fetch();
        Picasso.with(MainActivity.this).load(url).fetch(new Callback() {
            @Override
            public void onSuccess() {
                Log.d(TAG, "zwm, onSuccess");
            }

            @Override
            public void onError() {
                Log.d(TAG, "zwm, onError");
            }
        });
    }
}

九、缓存

内存缓存是使用LRU策略的缓存实现,它的大小是内存大小的15%。磁盘缓存的大小是磁盘容量的2%,并且不超过50M、不少于5M。
处理一个请求时,按照顺序检查:memory -> disk -> network。
默认情况下,Picasso内存缓存和磁盘缓存都是开启了的,但是有些时候,我们并不需要缓存,比如加载一张大图片的时候,如果在内存中保存一份,很容易造成OOM,这时候我们只希望有磁盘缓存,而不希望缓存到内存,因此就需要我们设置缓存策略了。

设置内存缓存策略:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        ImageView imageView = findViewById(R.id.imageview);
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        Picasso.with(MainActivity.this)
                .load(url)
                .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
                .into(imageView);
    }
}

设置磁盘缓存策略:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        ImageView imageView = findViewById(R.id.imageview);
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        Picasso.with(MainActivity.this)
                .load(url)
                .networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE) //注意:NetworkPolicy.NO_STORE只对OkHttp有效
                //.networkPolicy(NetworkPolicy.OFFLINE) //只从缓存获取结果,不发起网络请求
                .into(imageView);
    }
}

十、Debug和日志

缓存指示器:
在图片的左上角出现一个带色块的三角形标示,有3种颜色,绿色表示从内存加载、蓝色表示从磁盘加载、红色表示从网络加载。

Picasso.with(this).setIndicatorsEnabled(true);

日志:
Picasso可以打印一些日志,比如一些关键方法的执行时间等。

Picasso.with(this).setLoggingEnabled(true);

十一、Picasso扩展

  • 用Builder自己构造一个Picasso实例。
  • 配置自定义下载器DownLoader。
  • 配置缓存。
  • 配置线程池。
  • 配置全局的Picasso实例。
//Application
@Override
public void onCreate() {
    super.onCreate();
    
    //配置全局的Picasso实例
    Picasso.Builder builder = new Picasso.Builder(this);
    //配置下载器
    builder.downloader(new CustomDownloader());
    //配置缓存
    LruCache cache = new LruCache(5*1024*1024); //设置缓存大小
    builder.memoryCache(cache);
    //配置线程池
    ExecutorService executorService = Executors.newFixedThreadPool(8);
    builder.executor(executorService);

    //构造一个Picasso
    Picasso picasso = builder.build();
    //设置全局的Picasso实例
    Picasso.setSingletonInstance(picasso);
}

//Activity
Picasso.with(MainActivity.this)
        .load(url)
        .into(imageView);

十二、源码解析

Picasso源码解析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容