教你如何實現(xiàn) Splash 頁面三秒跳轉(zhuǎn)和動態(tài)下載最新背景圖

本文已授權(quán)公眾號hongyangAndroid原創(chuàng)首發(fā)

最近公司產(chǎn)品大大說我們需要一個動態(tài)替換的閃屏頁面茂嗓,like 某貓,某東一樣庶柿,可以動態(tài)替換挤巡。
產(chǎn)品大大就是厲害,說一句話我們就需要實現(xiàn)好幾個功能:

  1. 創(chuàng)建一個冷啟動后的閃屏頁面(Splash 頁面)
  1. 這個頁面默認 3s 倒計時盛末,點擊倒計時按鈕可以跳轉(zhuǎn)并結(jié)束倒計時
  1. 點擊圖片如果有外鏈弹惦,則跳轉(zhuǎn)應(yīng)用的 web 頁面用來作為活動頁面(沒錯這點和某貓很像)
  1. 動態(tài)替換厲害了否淤,我們需要在進入這個頁面后去后臺請求一下是否有新的圖片,如果是新的圖片則下載到本地棠隐,替換掉原來的圖片石抡,下次用戶在進入 Splash 就會看到一個嶄新的圖片。
效果圖

一助泽、布局實現(xiàn)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent">
    <ImageView
        android:id="@+id/sp_bg"
        android:src="@mipmap/icon_splash"
        android:scaleType="centerCrop"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <Button
        android:visibility="invisible"
        android:gravity="center"
        android:textSize="10sp"
        android:textColor="@color/white"
        android:id="@+id/sp_jump_btn"
        android:background="@drawable/btn_splash_shape"
        android:layout_width="60dp"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="20dp"
        android:layout_marginTop="20dp"/>

</RelativeLayout>

布局文件文件相對來說還是比較簡單啰扛,就需要一個 ImageView 和 Button 即可,Button 的背景是一個自定義的 shape嗡贺,透明度顏色啥的,根據(jù)UI妹砸說的算就好了侠讯。

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <solid android:color="#99c4c4c4"/>
    <corners android:radius="20dp"/>
    <stroke
        android:width="0.7dp"
        android:color="#7fffffff"/>

</shape>

二、倒計時功能實現(xiàn)

實現(xiàn)倒計時的功能方法有很多暑刃,最基本的你可以使用 Handler 來實現(xiàn)吧厢漩,還可以是用 Timer 吧。

但是由于之前寫驗證碼倒計時的時候發(fā)現(xiàn) android.os 中有一個神奇的類叫 CountDownTimer 的類岩臣,此類神奇之處就在于你完全不需要理會那些線程交互他都給你處理好了溜嗜,你只管在回調(diào)中處理時間設(shè)置跳轉(zhuǎn)邏輯就好了。

但是有一個不足的地方就它的第一秒的倒計時有時候會不可見架谎,所以我們將倒計時總時間設(shè)置為 3200ms 炸宵。

  private CountDownTimer countDownTimer = new CountDownTimer(3200, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {
            mSpJumpBtn.setText("跳過(" + millisUntilFinished / 1000 + "s)");
        }

        @Override
        public void onFinish() {
            mSpJumpBtn.setText("跳過(" + 0 + "s)");
            gotoLoginOrMainActivity();
        }
    };

最后需要在有閃屏頁面的情況下,進入開啟倒計時:

    private void startClock() {
        mSpJumpBtn.setVisibility(View.VISIBLE);
        countDownTimer.start();
    }

三谷扣、下載功能實現(xiàn)點擊跳轉(zhuǎn)功能實現(xiàn)

上邊說了我們 APP 點擊圖片需要可以跳轉(zhuǎn)土全,下面代碼給出了背景點擊跳轉(zhuǎn)的邏輯:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        ButterKnife.bind(this);
        checkSDCardPermission();
    }


    @OnClick({R.id.sp_bg, R.id.sp_jump_btn})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.sp_bg:
                gotoWebActivity();
                break;
            case R.id.sp_jump_btn:
                gotoLoginOrMainActivity();
                break;
        }
    }

跳轉(zhuǎn)邏輯可以根據(jù)實際的項目需求來規(guī)定,下面的代碼中 Splash 為本地序列化的 model 用來存儲網(wǎng)絡(luò)下載的閃屏頁面信息会涎,稍后會有詳細的序列化過程裹匙,此刻我們只需要關(guān)注跳轉(zhuǎn)邏輯:

   private Splash mSplash;
   private void gotoWebActivity() {
        if (mSplash != null && mSplash.click_url != null) {
            Intent intent = new Intent(this, BannerActivity.class);
            intent.putExtra("url", mSplash.click_url);
            intent.putExtra("title", mSplash.title);
            intent.putExtra("fromSplash", true);
            intent.putExtra("needShare", false);
            startActivity(intent);
            finish();
        }
    }
    

機智的你可能看出來我們并沒有在離開頁面的時候結(jié)束掉 timer,其實我們是復(fù)寫了 onDestroy 方法末秃。

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (countDownTimer != null)
            countDownTimer.cancel();
    }

其實跳轉(zhuǎn)以后還有一個坑就是概页,從 web 頁面返回的時候,因為閃屏頁面是你應(yīng)用的第一個頁面练慕,而跳轉(zhuǎn)到 web 頁面的是你 finish 掉了該頁面惰匙,那么從 web 頁返回的時候不做處理,用戶就直接退出了 app 這樣當(dāng)然是不允許的铃将。

所以請在 web 頁面中添加以下邏輯:

    //此方法是toolbar 的返回事件調(diào)用的方法 mFromSplash 為啟動頁面?zhèn)鬟f過來的參數(shù)
    @Override
    protected void onLeftClick(View view) {
        if (mFromSplash) {
            gotoLoginOrMainActivity();
        } else {
            super.onLeftClick(view);
        }
    }

    // 此方法為系統(tǒng)返回鍵的監(jiān)聽
    @Override
    public void onBackPressed() {
        if (mWebView.canGoBack()) {
            mWebView.goBack();
        } else if (mFromSplash) {
            gotoLoginOrMainActivity();
        } else {
            super.onBackPressed();
        }
    }
     // 下面是跳轉(zhuǎn)邏輯 
     private void gotoLoginOrMainActivity() {
        if (UserCenter.getInstance().getToken() == null) {
            gotoLoginActivity();
        } else {
            gotoMainActivity();
        }
    }

    .... gotoLoginActivity项鬼,gotoMainActivity 太長了,不給了自己寫 (*^__^*) 嘻嘻…… 

四劲阎、下載網(wǎng)絡(luò)圖片以及序列化本地

上邊說了我們有這樣一個需求绘盟,就是如果后臺的接口返回的圖片與本地序列化的圖片不同,我們需要將新的圖片下載到本地,然后下次進入 Splash 的時候就展示的新的圖片了奥此。

這里你需要知道知識有下邊幾個:

  1. java bean 序列化與反序列化的知識
  2. IntentService 服務(wù)的知識
  3. AsycTask 的使用
  4. 6.0 以上權(quán)限申請 EasyPermissions 的使用弧哎。

以上不熟悉的同學(xué),看到下邊的代碼可能會引起適量身體不適


其實這里更好的操作稚虎,我們可以將圖片下載到內(nèi)存中撤嫩,這樣并不需要申請sdk權(quán)限。這里當(dāng)時實現(xiàn)的時候有點欠考慮了蠢终。如果您們保存圖片的地址在內(nèi)存中序攘,就可以跳過這一步。

1. 權(quán)限管理

首先我們注意到已進入 Splash 頁面我們就進行權(quán)限檢查寻拂,因為我們需要下載最新的閃屏到本地程奠,并取出序列化的對象,來展示對應(yīng)的內(nèi)容祭钉。

其中 checkSDCardPermission 涉及到 6.0 以上下載最新圖片的邏輯瞄沙,這里采用的是 官方的 EasyPermissions 來處理,關(guān)于 EasyPermissions 的使用這里就不多說了慌核,需要了解的請移步 EasyPermissions距境;

    public static final int RC_PERMISSION = 123;

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @AfterPermissionGranted(RC_PERMISSION)
    private void checkSDCardPermission() {
        if (EasyPermissions.hasPermissions(this, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)) {
            initSplashImage();
            startImageDownLoad();
        } else {
            EasyPermissions.requestPermissions(this, "需要您提供【**】App 讀寫內(nèi)存卡權(quán)限來確保應(yīng)用更好的運行", RC_PERMISSION, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
    }

簡單來說在 EasyPermissions.hasPermissions 的回調(diào)中我們就可以正確的做我們下載圖片的工作了。

    private void initSplashImage() {
        mSplash = getLocalSplash();  
        //如果取出本地序列化的對象成功 則進行圖片加載和倒計時
        if (mSplash != null && !TextUtils.isEmpty(mSplash.savePath)) {
            Logcat.d("SplashActivity 獲取本地序列化成功" + mSplash);
            Glide.with(this).load(mSplash.savePath).dontAnimate().into(mSpBgImage);
            startClock();//加載成功 開啟倒計時
        } else {
        // 如果本地沒有 直接跳轉(zhuǎn)
            mSpJumpBtn.setVisibility(View.INVISIBLE);
            mSpJumpBtn.postDelayed(new Runnable() {
                @Override
                public void run() {
                    gotoLoginOrMainActivity();
                }
            }, 400);
        }
    }
    
    // 取出本地序列化的 Splash 
    private Splash getLocalSplash() {
        Splash splash = null;
        try {
            File serializableFile = SerializableUtils.getSerializableFile(Constants.SPLASH_PATH, Constants.SPLASH_FILE_NAME);
            splash = (Splash) SerializableUtils.readObject(serializableFile);
        } catch (IOException e) {
            Logcat.e("SplashActivity 獲取本地序列化閃屏失敗" + e.getMessage());
        }
        return splash;
    }
    

2. 創(chuàng)建本地序列化對象 Splash Entity

Splash 內(nèi)容如下:

public class Splash implements Serializable {

    private static final long serialVersionUID = 7382351359868556980L;//這里需要寫死 序列化Id
    public int id;
    public String burl;//大圖 url
    public String surl;//小圖url
    public int type;//圖片類型 Android 1 IOS 2
    public String click_url; // 點擊跳轉(zhuǎn) URl
    public String savePath;//圖片的存儲地址
    public String title;//圖片的存儲地址

    public Splash(String burl, String surl, String click_url, String savePath) {
        this.burl = burl;
        this.surl = surl;
        this.click_url = click_url;
        this.savePath = savePath;
    }

    @Override
    public String toString() {
        return "Splash{" +
                "id=" + id +
                ", burl='" + burl + '\'' +
                ", surl='" + surl + '\'' +
                ", type=" + type +
                ", click_url='" + click_url + '\'' +
                ", savePath='" + savePath + '\'' +
                '}';
    }
}

3. 序列化反序列話的工具類 SerializableUtils

由于項目用到序列化地方還有挺多的垮卓,所以這里封裝了一個序列化工具類SerializableUtils

public class SerializableUtils {

    public static <T extends Serializable> Object readObject(File file) {
        ObjectInputStream in = null;
        T t = null;
        try {
            in = new ObjectInputStream(new FileInputStream(file));
            t = (T) in.readObject();
        } catch (EOFException e) {
            // ... this is fine
        } catch (IOException e) {
            Logcat.e("e " + e.getMessage());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return t;
    }

    public static <T extends Serializable> boolean writeObject(T t, String fileName) {
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(new FileOutputStream(fileName));
            out.writeObject(t);
            Logcat.d("序列化成功 " + t.toString());
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            Logcat.d("序列化失敗 " + e.getMessage());
            return false;
        } finally {
            try {
                if (out != null) out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static File getSerializableFile(String rootPath, String fileName) throws IOException {
        File file = new File(rootPath);
        if (!file.exists()) file.mkdirs();
        File serializable = new File(file, fileName);
        if (!serializable.exists()) serializable.createNewFile();
        return serializable;
    }
}

經(jīng)過上邊的努力我們已經(jīng)完成了從本地反序列化內(nèi)容垫桂,然后加載圖片的工作了,剩下的需要做的就是下載最新圖片的工作粟按。

4. 請求接口下載最新的閃屏信息和圖片

這里經(jīng)過考慮诬滩,我決定采用服務(wù)去下載,因為這樣可以少很多麻煩灭将,也不影響程序的正常運行疼鸟。但是絕不是你們要采用這樣的方法,你們也可以單獨寫個工具類內(nèi)部去開線程做這件事宗侦。

項目中使用開啟 IntentServie 來下載圖片愚臀,關(guān)于這中服務(wù)的最大的好處就是,我們不需要關(guān)注服務(wù)是否執(zhí)行完任務(wù)矾利,當(dāng)他執(zhí)行完 onHandleIntent 方法后他就自己挑用 stop 方法了。我們只需要關(guān)注下載邏輯和序列化邏輯就好馋袜。

checkSDCardPermission 中調(diào)用的 startImageDownLoad() 方法:

 private void startImageDownLoad() {
    SplashDownLoadService.startDownLoadSplashImage(this, Constants.DOWNLOAD_SPLASH);
 }

SplashDownLoadService 內(nèi)容男旗,IntentService 在調(diào)用了 startService 后會執(zhí)行 onHandleIntent 方法,在這方法中我們?nèi)フ埱蠓?wù)器最新的數(shù)據(jù)即 loadSplashNetDate

    public SplashDownLoadService() {
        super("SplashDownLoad");
    }

    public static void startDownLoadSplashImage(Context context, String action) {
        Intent intent = new Intent(context, SplashDownLoadService.class);
        intent.putExtra(Constants.EXTRA_DOWNLOAD, action);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent != null) {
            String action = intent.getStringExtra(Constants.EXTRA_DOWNLOAD);
            if (action.equals(Constants.DOWNLOAD_SPLASH)) {
                loadSplashNetDate();
            }
        }
    }

由于是公司項目欣鳖,請求方法就不給出了察皇,但是需要講下請求數(shù)據(jù)后如何判斷是否需要執(zhí)行下載任務(wù):

   mScreen = common.attachment.flashScreen;
           Splash splashLocal = getSplashLocal();
           if (mScreen != null) {
               if (splashLocal == null) {
                  Logcat.d("splashLocal 為空導(dǎo)致下載");
                  startDownLoadSplash(Constants.SPLASH_PATH, mScreen.burl);
                } else if (isNeedDownLoad(splashLocal.savePath, mScreen.burl)) {
                      Logcat.d("isNeedDownLoad 導(dǎo)致下載");
                      startDownLoadSplash(Constants.SPLASH_PATH, mScreen.burl);
               }
           } else {//由于活動是一段時間,等活動結(jié)束后我們并不需要在進入閃屏頁面,這個時候我們就需要將本地文件刪除什荣,下次在進來矾缓,本地文件為空,就會直接 finish 掉 Splash 頁面稻爬,進入主頁面嗜闻。
              if (splashLocal != null) {
                    File splashFile = SerializableUtils.getSerializableFile(Constants.SPLASH_PATH, SPLASH_FILE_NAME);
                     if (splashFile.exists()) {
                             splashFile.delete();
                             Logcat.d("mScreen為空刪除本地文件");
                       }
                }
           }

由于活動是一段時間,等活動結(jié)束后我們并不需要在進入閃屏頁面桅锄,這個時候我們就需要將本地文件刪除琉雳,下次在進來,本地文件為空友瘤,就會直接 finish 掉 Splash 頁面翠肘,進入主頁面。

getSplashLocal 方法即反序列話本地存儲的 Splash Entity 的過程辫秧,上邊已經(jīng)給出這里就不細說束倍,主要講一下判斷邏輯 isNeedDownLoad

    /**
     * @param path 本地存儲的圖片絕對路徑
     * @param url  網(wǎng)絡(luò)獲取url
     * @return 比較儲存的 圖片名稱的哈希值與 網(wǎng)絡(luò)獲取的哈希值是否相同
     */
    private boolean isNeedDownLoad(String path, String url) {
        // 如果本地存儲的內(nèi)容為空則進行下載
        if (TextUtils.isEmpty(path)) {
            return true;
        }
        // 如果本地文件不存在則進行下載,這里主要防止用戶誤刪操作
        File file = new File(path);
        if (!file.exists()) {
            return true;
        }
        // 如果兩者都存在則判斷圖片名稱的 hashCode 是否相同盟戏,不相同則下載
        if (getImageName(path).hashCode() != getImageName(url).hashCode()) {
            return true;
        }
        return false;
    }

分隔 uri 取圖片名稱的方法:

private String getImageName(String url) {
        if (TextUtils.isEmpty(url)) {
            return "";
        }
        String[] split = url.split("/");
        String nameWith_ = split[split.length - 1];
        String[] split1 = nameWith_.split("\\.");
        return split1[0];
    }

滿足下載條件后則調(diào)用 DownLoadTask 下載绪妹。

public class DownLoadUtils {

    public interface DownLoadInterFace {
        void afterDownLoad(ArrayList<String> savePaths);
    }

    public static void downLoad(String savePath, DownLoadInterFace downLoadInterFace, String... download) {
        new DownLoadTask(savePath, downLoadInterFace).execute(download);
    }

    private static class DownLoadTask extends AsyncTask<String, Integer, ArrayList<String>> {
        private String mSavePath;
        private DownLoadInterFace mDownLoadInterFace;

        private DownLoadTask(String savePath, DownLoadInterFace downLoadTask) {
            this.mSavePath = savePath;
            this.mDownLoadInterFace = downLoadTask;
        }

        @Override
        protected ArrayList<String> doInBackground(String... params) {
            ArrayList<String> names = new ArrayList<>();
            for (String url : params) {
                if (!TextUtils.isEmpty(url)) {
                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                        // 獲得存儲卡的路徑
                        FileOutputStream fos = null;
                        InputStream is = null;
                        try {
                            URL downUrl = new URL(url);
                            // 創(chuàng)建連接
                            HttpURLConnection conn = (HttpURLConnection) downUrl.openConnection();
                            conn.connect();
                            // 創(chuàng)建輸入流
                            is = conn.getInputStream();
                            File file = new File(mSavePath);
                            // 判斷文件目錄是否存在
                            if (!file.exists()) {
                                file.mkdirs();
                            }

                            String[] split = url.split("/");
                            String fileName = split[split.length - 1];
                            File mApkFile = new File(mSavePath, fileName);
                            names.add(mApkFile.getAbsolutePath());
                            fos = new FileOutputStream(mApkFile, false);
                            int count = 0;
                            // 緩存
                            byte buf[] = new byte[1024];
                            while (true) {
                                int read = is.read(buf);
                                if (read == -1) {
                                    break;
                                }
                                fos.write(buf, 0, read);
                                count += read;
                                publishProgress(count);
                            }
                            fos.flush();

                        } catch (Exception e) {
                            Logcat.e(e.getMessage());
                        } finally {
                            try {
                                if (is != null) {
                                    is.close();
                                }
                                if (fos != null) {
                                    fos.close();
                                }
                            } catch (IOException e1) {
                                e1.printStackTrace();
                            }
                        }
                    }
                }
            }
            return names;
        }

        @Override
        protected void onPostExecute(ArrayList<String> strings) {
            super.onPostExecute(strings);
            if (mDownLoadInterFace != null) {
                mDownLoadInterFace.afterDownLoad(strings);
            }
        }
    }
}

由于下載完成后需要拿到文件存儲地址這里寫了一個 mDownLoadInterFace.afterDownLoad 的回調(diào)在 service 拿到回調(diào)后:

public void afterDownLoad(ArrayList<String> savePaths) {
                if (savePaths.size() == 1) {
                    Logcat.d("閃屏頁面下載完成" + savePaths);
                    if (mScreen != null) {
                        mScreen.savePath = savePaths.get(0);
                    }
                    // 序列化 Splash 到本地
                    SerializableUtils.writeObject(mScreen, Constants.SPLASH_PATH + "/" + SPLASH_FILE_NAME);
                } else {
                    Logcat.d("閃屏頁面下載失敗" + savePaths);
                }
            }

寫在最后

上邊 bb 這么多,我們可以看出產(chǎn)品一句話抓半,我們程序員可能就需要工作一天了喂急,所以我們需要將這個常見的功能記錄下,下個公司產(chǎn)品再說實現(xiàn)一個閃屏功能笛求,然后我們就可以說 這功能可能需要 1天時間廊移,然后等他答應(yīng)了,copy 一下探入,其他的時間你就可以學(xué)習(xí)下 Rxjava2 狡孔,kotlin, js 之類的了蜂嗽。哈哈哈哈 我真tm機智苗膝。

后記:

這篇文章投稿到掘金和鴻洋大神的公眾號后,大家對我的代碼提出了許多建議植旧,我感謝大家能幫助我成長辱揭。大家普遍要求一個Demo,花了幾個小時時間病附,將其從項目中抽出來问窃。希望大家賞臉 star 或者fork:

項目地址:SplashActivityDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市完沪,隨后出現(xiàn)的幾起案子域庇,更是在濱河造成了極大的恐慌嵌戈,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件听皿,死亡現(xiàn)場離奇詭異熟呛,居然都是意外死亡,警方通過查閱死者的電腦和手機尉姨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門庵朝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人啊送,你說我怎么就攤上這事偿短。” “怎么了馋没?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵昔逗,是天一觀的道長。 經(jīng)常有香客問我篷朵,道長勾怒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任声旺,我火速辦了婚禮笔链,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腮猖。我一直安慰自己鉴扫,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布澈缺。 她就那樣靜靜地躺著坪创,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姐赡。 梳的紋絲不亂的頭發(fā)上莱预,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音项滑,去河邊找鬼依沮。 笑死,一個胖子當(dāng)著我的面吹牛枪狂,可吹牛的內(nèi)容都是我干的危喉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼州疾,長吁一口氣:“原來是場噩夢啊……” “哼姥饰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起孝治,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谈飒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岂座,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年杭措,在試婚紗的時候發(fā)現(xiàn)自己被綠了费什。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡手素,死狀恐怖鸳址,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情泉懦,我是刑警寧澤稿黍,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站崩哩,受9級特大地震影響巡球,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜邓嘹,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一酣栈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汹押,春花似錦矿筝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鸟悴,卻和暖如春陈辱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背细诸。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工沛贪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人震贵。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓利赋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親猩系。 傳聞我的和親對象是個殘疾皇子媚送,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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