關(guān)于給Android視頻播放器封面加載的一種解決方案

借鑒自這里困鸥,請(qǐng)點(diǎn)擊

總體思路就是開線程獲取第一幀并存到本地澎剥,用數(shù)據(jù)庫(kù)保存播放鏈接和第一幀圖片的本地地址,第二次打開做判斷锈拨,先在數(shù)據(jù)庫(kù)存儲(chǔ)查詢龄坪,看是否存在昭雌,如果存在就把地址取出來加載。

首先你需要寫一個(gè)Thread類健田,用來調(diào)用獲取視頻第一幀的封面烛卧,為什么要建一個(gè)線程類呢,因?yàn)樵讷@取封面過程中調(diào)用包括setDataSource(String url)getFrameAtTime(long timeMs,int option)方法都是很耗時(shí)的操作妓局,所以要在子線程中獲取总放,獲取完成之后,在用handler去更新適配器UI好爬。
好了局雄,下面咱們開始吧:
Thread類:

package cn.wangcy.demo.ffcd.thread;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.media.MediaMetadataRetriever;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.widget.ImageView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import cn.wangcy.demo.ffcd.bean.VideoDataBean;
import cn.wangcy.demo.ffcd.db.DbManager;
import cn.wangcy.demo.ffcd.utils.LogUtils;
import cn.wangcy.demo.ffcd.utils.PictureUtils;

/**
 * Created by wangchuanyu on 2018/7/16.
 */

public class CreateFirstFrameBitmapThread extends Thread {

    private List<VideoDataBean> mDatas;
    private int width = 0;
    private int height = 0;
    private ImageView videoCover = null;
    private final String OutPutFileDirPath = Environment.getExternalStorageDirectory() + "/first_frame";
    private Handler handler;
    private DbManager manager;
    private long fileLength;
    private int posIndex = 0;


    public CreateFirstFrameBitmapThread(List<VideoDataBean> mDatas, int width, int height, ImageView videoCover, Handler handler) {
        this.mDatas = mDatas;
        this.width = width;
        this.height = height;
        this.videoCover = videoCover;
        this.handler = handler;
    }

    public CreateFirstFrameBitmapThread(Context context, List<VideoDataBean> mDatas, Handler handler) {
        this.mDatas = mDatas;
        this.handler = handler;
        manager = new DbManager(context);
    }

    public CreateFirstFrameBitmapThread(Context context, List<VideoDataBean> mDatas, Handler handler, int i) {
        this.mDatas = mDatas;
        this.handler = handler;
        this.posIndex = i;
        manager = new DbManager(context);
    }

    public CreateFirstFrameBitmapThread() {

    }

    @Override
    public void run() {
        super.run();
        for (int i = posIndex; i < mDatas.size(); i++) {
            createBitmapFromVideoPath(i, mDatas.get(i).getmVideoUrl());
        }
    }

    /**
     * 獲取第一幀的方法,通過上方for循環(huán)進(jìn)行獲取第一幀
     * @param positon
     * @param url
     */
    public void createBitmapFromVideoPath(int positon, String url) {
        synchronized (this) {
            Bitmap bitmap = null;
            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
            try {
                if (Build.VERSION.SDK_INT >= 12) {
                    retriever.setDataSource(url, new HashMap<String, String>());
                } else {
                    retriever.setDataSource(url);
                }
                bitmap = retriever.getFrameAtTime(1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
                String len = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
                fileLength = TextUtils.isEmpty(len) ? 0 : Long.valueOf(len);

                Bitmap bitmapNew = /*scaleImage(bitmap)*/bitmap;
//                Bitmap bitmapNew = /*scaleImage(bitmap)*/zoomImage(bitmap,100,100);
                String path = PictureUtils.saveImageToSDForEdit(bitmapNew, OutPutFileDirPath, positon + "_FirstFrame_ffcd"  + PictureUtils.POSTFIX);
                VideoDataBean bean = mDatas.get(positon);
                manager.addImage(bean);

//            sendPic(bitmapNew, positon);
                sendPic(path, bitmapNew, positon);
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            } catch (RuntimeException ex) {
                ex.printStackTrace();
            } catch (Exception ex) {

            } finally {
                try {
                    retriever.release();
                } catch (RuntimeException ex) {
                    ex.printStackTrace();
                }
            }
        }

    }

    /**
     * 壓縮圖片
     * @param bitmap
     * @param newWidth
     * @param newHeight
     * @return
     */
    public static Bitmap zoomImage(Bitmap bitmap, int newWidth, int newHeight) {
        // 獲得圖片的寬高
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        // 計(jì)算縮放比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 取得想要縮放的matrix參數(shù)
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        // 得到新的圖片
        return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    }

    /**
     * 發(fā)送圖片到handler存炮,更新UI
     * @param path
     * @param bitmap
     * @param positon
     */
    public void sendPic(String path, Bitmap bitmap, int positon) {
        Message msg = new Message();
        msg.what = 0;
        msg.arg1 = positon;
        msg.obj = path;
        handler.sendMessage(msg);
    }

    /**
     * 發(fā)送圖片到handler炬搭,更新UI(以list形式傳遞數(shù)據(jù),主要用于更新bitmap類型的數(shù)據(jù))
     * @param bitmap
     * @param positon
     */
    public void sendPic(Bitmap bitmap, int positon) {
        Message msg = new Message();
        msg.what = 0;
        List list = new ArrayList();
        list.add(bitmap);
        msg.obj = list;  //handler傳遞對(duì)象
        msg.arg1 = positon;
        handler.sendMessage(msg);
    }
}

有了這個(gè)線程穆桂,就可以在適當(dāng)?shù)臅r(shí)候不耗時(shí)的狀態(tài)下進(jìn)行獲取第一幀宫盔。

接下來就是數(shù)據(jù)庫(kù)的創(chuàng)建

/**
* 數(shù)據(jù)庫(kù)基礎(chǔ)類,用于創(chuàng)建數(shù)據(jù)庫(kù)
**/
public class DbHelper extends SQLiteOpenHelper {
    private static final String name = "your dbName"; //數(shù)據(jù)庫(kù)名稱
    private static final int version = 1; //數(shù)據(jù)庫(kù)版本

    public DbHelper(Context context) {
        super(context, name, null, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS "+ "your table name"+" (id integer primary key autoincrement, name text, imgurl text, videourl text)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}



/**
 * 數(shù)據(jù)庫(kù)工具類
 */
public class DbManager {
    private BaisongDbHelper dbHelper;
    private SQLiteDatabase db;
    public static int dbSize = 0;

    public DbManager(Context context) {
        dbHelper = new BaisongDbHelper(context);
        db = dbHelper.getReadableDatabase();
    }

    /**
     * 添加圖片到數(shù)據(jù)庫(kù)
     */
    public void addMustImage(String video_url, String image_url) {
        if (find_video_url(video_url)!=null){
            updateMustVideo(video_url);
            return;
        }
        if (find_image_url(image_url)!=null){
            updateMustImage(video_url,image_url);
            return;
        }
        ContentValues cv = new ContentValues();
        cv.put("videourl", video_url);
        cv.put("imgurl", image_url);
        long id = db.insert(ConfigYibaisong.MUST_IMAGE, null, cv);//插入數(shù)據(jù)庫(kù)

      //--------以下是利用數(shù)組打印插入數(shù)據(jù)的代碼--------------
        Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, null, "videourl=?" + " and " + "imgurl=?", new String[]{video_url, image_url}, null, null, null);
        ArrayList<HashMap<String, String>> AL = new ArrayList<HashMap<String, String>>();
        if (cursor.moveToNext()) {
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                HashMap<String, String> hm = new HashMap<>();
                hm.put("videourl", cursor.getString(cursor.getColumnIndex("videourl")));
                hm.put("imgurl", cursor.getString(cursor.getColumnIndex("imgurl")));
                AL.add(hm);
            }
            cursor.close();
        }
        if (id != -1) Log.d("zzzzzzzzz", "插入成功  " + AL.toString());
        else Log.d("zzzzzzzzz", "插入失敗");
//        db.close();
//        db.insert(ConfigYibaisong.MUST_IMAGE, null, cv);
    }
   /**
     * 更新圖片
     */
    public void updateMustVideo(String video_url){
        ContentValues cv = new ContentValues();
        cv.put("videourl", video_url);
        long id = db.update(ConfigYibaisong.MUST_IMAGE,  cv,"videourl=?",new String[]{video_url});//插入數(shù)據(jù)庫(kù)
        if (id != -1) LogHelper.d("zzzzzzzzz", "更新成功  ");
        else LogHelper.d("zzzzzzzzz", "更新失敗");
    }
   /**
     * 更新圖片
     */
    public void updateMustImage(String video_url,String image_url){
        ContentValues cv = new ContentValues();
        cv.put("imgurl", image_url);
        long id = db.update(ConfigYibaisong.MUST_IMAGE,  cv,"videourl=?",new String[]{video_url});//插入數(shù)據(jù)庫(kù)
        if (id != -1) Log.d("zzzzzzzzz", "更新成功  ");
        else Log.d("zzzzzzzzz", "更新失敗");
    }

   /**
     * 查找video地址
     */
    public String find_video_url(String video_url){
        Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, null, "videourl=?" , new String[]{video_url}, null, null, null);
        if (cursor.moveToNext()) {
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                return cursor.getString(cursor.getColumnIndex("videourl"));
            }
            cursor.close();
        }
        return null;
    }
   /**
     * 查找圖片地址
     */
    public String find_image_url(String image_url){
        Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, null, "imgurl=?" , new String[]{image_url}, null, null, null);
        if (cursor.moveToNext()) {
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                return cursor.getString(cursor.getColumnIndex("imgurl"));
            }
            cursor.close();
        }
        return null;
    }

    public void DbClose() {
        db.close();
    }

    public long getCount() {
        return db.getMaximumSize();
    }

     /**
     * 根據(jù)給定video地址查詢本地圖片地址
     */
    public String findMustImage(int position, String video_url, String image_url) {
        if (TextUtils.isEmpty(video_url) || TextUtils.isEmpty(image_url))
            return "";
        if (tabbleIsExist(db, ConfigYibaisong.MUST_IMAGE)) {
            Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, null, "videourl=?" + " and " + "imgurl=?", new String[]{video_url, image_url}, null, null, null);
            String cursorStr = "";
            try {
                cursorStr = cursor.getString(cursor.getColumnIndex("imgurl"));
                cursor.close();
            } catch (CursorIndexOutOfBoundsException e) {
                cursorStr = null;
            }
            return cursorStr;
//            }

        }
        return null;
    }

   /**
     * 根據(jù)給定video地址查詢本地圖片地址
     */
    public String findMustImage(String video_url) {
        if (TextUtils.isEmpty(video_url))
            return "";
        if (tabbleIsExist(db, ConfigYibaisong.MUST_IMAGE)) {
            Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, new String[]{"imgurl"}, "videourl=?", new String[]{video_url}, null, null, null);
            String cursorStr = "";
            if(cursor.moveToNext()){
                try {
                    cursorStr = cursor.getString(0);
                    cursor.close();
                    return cursorStr;
                } catch (CursorIndexOutOfBoundsException e) {
                    cursorStr = null;
                   
                }
                return cursorStr;
            }

//            }

        }
        return null;
    }

    public List<NewMustClassBean.DataBean> findAllImageForMustCover(List<NewMustClassBean.DataBean> mDatas) {
        for (int i = 0; i < mDatas.size(); i++) {
            try {
                Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, new String[]{"imgurl"}, "videourl=?", new String[]{mDatas.get(i).getVideo()}, null, null, null);
                mDatas.get(i).setVideoCover(cursor.getString(cursor.getColumnIndex("imgurl")));
            } catch (CursorIndexOutOfBoundsException e) {
                return mDatas;
            }

        }
        return mDatas;
    }
   /**
     * 根據(jù)給定video地址查詢本地圖片地址
     */
    public void findImageMustCover(String videourl,List<NewMustClassBean.DataBean> mDatas,int position) {
        try {
            List<NewMustClassBean.DataBean> mMusts = new ArrayList<>();
                Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, new String[]{"imgurl"}, "videourl=?", new String[]{videourl}, null, null, null);
                while (cursor.moveToNext()) {
                    NewMustClassBean.DataBean bean = new NewMustClassBean.DataBean();
                    bean.setVideoCover(cursor.getString(cursor.getColumnIndex("imgurl")));
                    mMusts.add(bean);
            }

            mDatas.get(position).setVideoCover(mMusts.get(position).getVideoCover());
       
            
        } catch (CursorIndexOutOfBoundsException e) {
          

        }
    }


    //刪除某一個(gè)表
    public void dropTable() {
        db.delete(ConfigYibaisong.MUST_IMAGE, null, null);
    }

    //判斷一個(gè)表是否存在
    public boolean tabbleIsExist(SQLiteDatabase db, String tableName) {
        boolean result = false;
        if (tableName == null) {
            return false;
        }
        Cursor cursor = null;
        try {
            String sql = "select count(*) as c from Sqlite_master  where type ='table' and name ='" + tableName.trim() + "' ";
            cursor = db.rawQuery(sql, null);
            if (cursor.moveToNext()) {
                int count = cursor.getInt(0);
                if (count > 0) {
                    result = true;
                }
            }

        } catch (Exception e) {
            // TODO: handle exception
        }
        return result;
    }

}


創(chuàng)建完數(shù)據(jù)庫(kù)享完,接下來就是把圖片存入內(nèi)存灼芭,拿到地址,放到數(shù)據(jù)庫(kù)般又,以方便對(duì)本地圖片的取出加載彼绷。

/**
* 保存圖片到本地
**/
public class PictureUtils {
    public static final String POSTFIX = ".jpeg";

    public static String saveImageToSD(Bitmap bmp, String dirPath) {
        if (bmp == null) {
            return "";
        }
        File appDir = new File(dirPath);
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        String fileName = System.currentTimeMillis() + ".jpg";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file.getAbsolutePath();
    }



    public static String saveImageToSDForEdit(Bitmap bmp, String dirPath, String fileName) {
        if (bmp == null) {
            return "";
        }
        File appDir = new File(dirPath);
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        File file = new File(appDir, fileName);
        if (file.exists()){
            return file.getAbsolutePath();
        }
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bmp.compress(Bitmap.CompressFormat.JPEG, 80, fos);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
            return "null";
        }
        return file.getAbsolutePath();
    }

    public static void deleteFile(File f) {
        if (f.isDirectory()) {
            File[] files = f.listFiles();
            if (files != null && files.length > 0) {
                for (int i = 0; i < files.length; ++i) {
                    deleteFile(files[i]);
                }
            }
        }
        f.delete();
    }

}

保存完圖片了,也建立了數(shù)據(jù)庫(kù)了倒源,那接下來就是把圖片地址存到數(shù)據(jù)庫(kù)苛预,并在第二次開啟時(shí)取出本地圖片,利用glide加載到界面上就行了笋熬。再貼一個(gè)handler吧热某,用于更新獲取完第一幀,實(shí)時(shí)更新UI的過程。

/**
     * 在更新UI的方法
     */
    private Handler handler = new Handler() {

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:  //接到從線程內(nèi)傳來的圖片bitmap和imageView.
                    //這里只是將bitmap傳到imageView中就行了昔馋。只所以不在線程中做是考慮到線程的安全性
                    mDatas.get(msg.arg1).setmVideoCover("file://" + msg.obj);
                try {
                    if (!TextUtils.equals(mDatas.get(msg.arg1).getmVideoCover(), "file://null"))
                        manager.addImage(mDatas.get(msg.arg1));

                }catch (Exception ex){
                }
                    notifyItemChanged(msg.arg1);
//                    notifyDataSetChanged();


                    break;

                default:
                    super.handleMessage(msg);
                    break;
            }
        }

        ;
    };

當(dāng)然別忘了添加網(wǎng)絡(luò)請(qǐng)求和動(dòng)態(tài)請(qǐng)求讀寫的使用權(quán)限~筹吐。
希望這個(gè)思路能對(duì)大家有所幫助。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秘遏,一起剝皮案震驚了整個(gè)濱河市丘薛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌邦危,老刑警劉巖洋侨,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異倦蚪,居然都是意外死亡希坚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門陵且,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裁僧,“玉大人,你說我怎么就攤上這事慕购×钠#” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵沪悲,是天一觀的道長(zhǎng)获洲。 經(jīng)常有香客問我,道長(zhǎng)可训,這世上最難降的妖魔是什么昌妹? 我笑而不...
    開封第一講書人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮握截,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烂叔。我一直安慰自己谨胞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開白布蒜鸡。 她就那樣靜靜地躺著胯努,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逢防。 梳的紋絲不亂的頭發(fā)上叶沛,一...
    開封第一講書人閱讀 52,337評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音忘朝,去河邊找鬼灰署。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溉箕。 我是一名探鬼主播晦墙,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼肴茄!你這毒婦竟也來了晌畅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤寡痰,失蹤者是張志新(化名)和其女友劉穎抗楔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拦坠,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谓谦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贪婉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片反粥。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖疲迂,靈堂內(nèi)的尸體忽然破棺而出才顿,到底是詐尸還是另有隱情,我是刑警寧澤尤蒿,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布郑气,位于F島的核電站,受9級(jí)特大地震影響腰池,放射性物質(zhì)發(fā)生泄漏尾组。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一示弓、第九天 我趴在偏房一處隱蔽的房頂上張望讳侨。 院中可真熱鬧,春花似錦奏属、人聲如沸跨跨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)勇婴。三九已至,卻和暖如春嘱腥,著一層夾襖步出監(jiān)牢的瞬間耕渴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工齿兔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橱脸,地道東北人础米。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像慰技,于是被迫代替她去往敵國(guó)和親椭盏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,298評(píng)論 25 707
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,417評(píng)論 8 265
  • 當(dāng)晚地震發(fā)生時(shí)我邊做平板支撐邊看劇吻商,后面回想可能是地震的瞬間就是我以為是我肌肉抽動(dòng)的那會(huì)兒掏颊。 后面臨睡前打開微信,...
    羊木子閱讀 149評(píng)論 0 1
  • 這世上沒有誰(shuí)會(huì)永遠(yuǎn)是誰(shuí)的誰(shuí)艾帐,有的人注定只能被傷害乌叶,有的人注定只能錯(cuò)過,有的人永遠(yuǎn)只適合活在另一個(gè)人的心里……
    傻白甜的2018閱讀 353評(píng)論 2 3
  • 2017年11月18日 隨州*洛陽(yáng)古鎮(zhèn) 已是深秋柒爸,陽(yáng)光正好准浴。開車行走在群山之中,滿眼盡是秋色捎稚,山連...
    日色漸慢閱讀 862評(píng)論 3 5