Android 開(kāi)發(fā)藝術(shù)探索讀書(shū)筆記 5 -- 理解 RemoteViews

本篇文章主要介紹以下幾個(gè)知識(shí)點(diǎn):

  • RemoteViews 的應(yīng)用
  • RemoteViews 的內(nèi)部機(jī)制
  • RemoteViews 的意義
hello,夏天 (圖片來(lái)源于網(wǎng)絡(luò))

??RemoteViews 表示的是一種 View 的結(jié)構(gòu),它可以在其他的進(jìn)程中顯示,其使用場(chǎng)景有兩種:通知欄和桌面小部件触菜。

5.1 RemoteViews 的應(yīng)用

5.1.1 RemoteViews 在通知欄上的應(yīng)用

??通知欄除了默認(rèn)效果還支持自定義布局祸轮,使用系統(tǒng)默認(rèn)的樣式彈出一個(gè)通知如下:

   /**
     * 系統(tǒng)默認(rèn)樣式
     */
    private void defaultNotice() {
        Intent intent = new Intent(this, NoticeActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);

        // 1. 獲取 NotificationManager 實(shí)例來(lái)對(duì)通知進(jìn)行管理
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        // 2. 使用 Builder 構(gòu)造器來(lái)創(chuàng)建 Notification 對(duì)象
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("This is content title")
                .setContentText("This is content text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                .setContentIntent(pi) // 傳入pi
                .build();
        // 3. 顯示通知
        manager.notify(1,notification);
    }

??運(yùn)行效果如下:

系統(tǒng)默認(rèn)通知效果

??為了滿(mǎn)足個(gè)性化需求兽埃,需要用到自定義通知,首先提供一個(gè)布局文件适袜,然后通過(guò) RemoteViews 加載這個(gè)布局文件即可柄错,如下:

   /**
     * 自定義通知欄
     */
    private void customizeNotice() {
        Intent intent = new Intent(this, NoticeActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);

        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.chapter05_notice_item_layout);
        remoteViews.setTextViewText(R.id.tv_title, "This is content title"); // 文字
        remoteViews.setTextViewText(R.id.tv_content, "This is content text");// 文字
        remoteViews.setImageViewResource(R.id.iv_notice, R.mipmap.ic_notice);// 圖片
        remoteViews.setOnClickPendingIntent(R.id.ll_open_notice, pi);        // 點(diǎn)擊

        // 1. 獲取 NotificationManager 實(shí)例來(lái)對(duì)通知進(jìn)行管理
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        // 2. 使用 Builder 構(gòu)造器來(lái)創(chuàng)建 Notification 對(duì)象
        Notification notification = new NotificationCompat.Builder(this)
                .setContent(remoteViews)  // 傳入 remoteViews
                .setSmallIcon(R.mipmap.ic_notice)
                .setWhen(System.currentTimeMillis())
                .build();
        // 3. 顯示通知
        manager.notify(2, notification);
    }

??其中布局文件代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_open_notice"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/iv_notice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:padding="5dp">

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/colorAccent" />

        <TextView
            android:id="@+id/tv_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/colorPrimary" />

    </LinearLayout>

</LinearLayout>

??運(yùn)行效果如下:

自定義通知效果

5.1.2 RemoteViews 在桌面小部件的應(yīng)用

??AppWidgetProvider 是 Android 中提供的用于實(shí)現(xiàn)桌面小部件的類(lèi),其本質(zhì)是一個(gè)廣播苦酱,即 BroadcastReceiver售貌,其繼承關(guān)系如下:

AppWidgetProvider 的類(lèi)繼承關(guān)系

??桌面小部件的開(kāi)發(fā)步驟如下:

??1. 定義小部件的界面

??在 res/layout 下新建個(gè) widget.xml (名稱(chēng)和內(nèi)容可自定義)如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">
    
    <ImageView
        android:id="@+id/iv_widget"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_header"/>

    <TextView
        android:id="@+id/tv_widget"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:text="wonderful"/>

</LinearLayout>

??2. 定義小部件配置信息

??在 res/xml 下新建 widget_info.xml (名稱(chēng)可自定義)如下:

<?xml version="1.0" encoding="utf-8"?>
<!-- initialLayout 小工具使用的初始化布局
     minHeight、minWidth 小工具的最小尺寸
     updatePeriodMillis 小工具的自動(dòng)更新周期(毫秒) -->
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/widget"
    android:minHeight="66dp"
    android:minWidth="66dp"
    android:updatePeriodMillis="86400000">

</appwidget-provider>

??3. 定義小部件的實(shí)現(xiàn)類(lèi)

??這個(gè)類(lèi)需繼承 AppWidgetProvider 如下:


/**
 * Function:小部件的實(shí)現(xiàn)類(lèi)
 * Author:Wonderful on 2017/8/16 10:50
 * Email:KXwonder@163.com
 */

public class MyWidgetProvider extends AppWidgetProvider{

    public static final String CLICK_ACTION = "com.wonderful.androidartexplore.chapter05.action.CLICK";

    public MyWidgetProvider() {
        super();
    }

    @Override
    public void onReceive(final Context context, final Intent intent) {
        super.onReceive(context, intent);
        // 判斷是自己的 action疫萤,做自己的事情颂跨,如小部件被單擊了要干什么,
        // 這里是做一個(gè)動(dòng)畫(huà)效果
        if (intent.getAction().equals(CLICK_ACTION)) {
            ToastUtils.show("clicked it");

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_header);
                    AppWidgetManager appWidgetManage = AppWidgetManager.getInstance(context);
                    for (int i = 0; i < 37; i++) {
                        float degree = (i * 10) % 360;
                        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
                        remoteViews.setImageViewBitmap(R.id.iv_widget, rotateBitmap(bitmap, degree));
                        Intent intentClick = new Intent(CLICK_ACTION);
                        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intentClick, 0);
                        remoteViews.setOnClickPendingIntent(R.id.iv_widget, pendingIntent);
                        appWidgetManage.updateAppWidget(new ComponentName(context, MyWidgetProvider.class), remoteViews);
                        SystemClock.sleep(30);
                    }
                }
            }).start();
        }
    }

    /**
     * 每次桌面小部件更新時(shí)都會(huì)調(diào)用一次該方法
     */
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);

        for (int appWidgetId : appWidgetIds) {
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
            // 點(diǎn)擊桌面小部件發(fā)送廣播
            Intent intentClick = new Intent(CLICK_ACTION);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intentClick, 0);
            remoteViews.setOnClickPendingIntent(R.id.iv_widget, pendingIntent);
            appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
        }
    }

    /**
     * 動(dòng)畫(huà)
     */
    private Bitmap rotateBitmap(Bitmap bitmap, float degree) {
        Matrix matrix = new Matrix();
        matrix.reset();
        matrix.setRotate(degree);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }
}

??上述代碼實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的桌面小部件扯饶,小部件上顯示一張圖片恒削,點(diǎn)擊后旋轉(zhuǎn)一周。

??4. 在 AndroidManifest.xml 中聲明小部件

??桌面小部件本質(zhì)是一個(gè)廣播組件尾序,必須要注冊(cè)钓丰,如下:

<receiver android:name=".chapter05.MyWidgetProvider">
     <intent-filter >
          <!-- 用于識(shí)別小部件的點(diǎn)擊行為 -->
          <action android:name="com.wonderful.androidartexplore.chapter05.action.CLICK"/>
          <!-- 小部件的標(biāo)識(shí),必須存在 -->
          <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
     </intent-filter>

     <meta-data
          android:name="android.appwidget.provider"
          android:resource="@xml/widget_info" />
 </receiver>

??運(yùn)行效果如下:

桌面小部件運(yùn)行效果

??上面描述了一個(gè)開(kāi)發(fā)桌面小部件的完整過(guò)程每币,實(shí)際開(kāi)發(fā)流程都是一樣的携丁。 不管小部件的界面初始化還是界面的更新,在界面上的操作都是通過(guò) RemoteViews兰怠。

??AppWidgetProvider 除了最常用的 onUpdate 方法梦鉴,還有 onEnableonDisabled揭保,onDeleted以及onReceiver 方法肥橙,這些方法會(huì)自動(dòng)的被 onReceiver 在合適的時(shí)間調(diào)用,其含義如下:

  • onEnable 當(dāng)該窗口小部件第一次添加到桌面的時(shí)候調(diào)用該方法掖举,可添加多次但是只在第一次調(diào)用

  • onUpdate 小部件被添加或每次更新時(shí)都會(huì)調(diào)用一次該方法快骗,更新機(jī)制由 updatePeriodMillis 來(lái)指定

  • onDeleted 每刪除一次小部件就調(diào)用一次

  • onDisabled 當(dāng)最后一個(gè)該類(lèi)型的小部件被刪除時(shí)調(diào)用

  • onReceiver 廣播內(nèi)置的方法

5.1.3 PendingIntent 概述

??PendingIntent 表示一種處于待定娜庇、等待塔次、即將發(fā)生的意思,它與 Intent 的區(qū)別在于名秀,PendingIntent 是在將來(lái)某個(gè)不確定的時(shí)刻發(fā)生励负,Intent 是立刻發(fā)生。(給 RemoteViews 設(shè)置點(diǎn)擊事件必須使用 PendingIntent)

??PendingIntent 支持三種待定意圖:?jiǎn)?dòng)Activity匕得、啟動(dòng)Service继榆、發(fā)送廣播巾表,具體如下:

PendingIntent 的主要方法

??上圖中三個(gè)方法的參數(shù)都是一樣的,其中第二個(gè)參數(shù) requstCode 表示 PendingIntent 發(fā)送方的請(qǐng)求碼略吨,多數(shù)情況設(shè)為 0集币,它也會(huì)影響到參數(shù) flags 的效果。


??PendingIntent 的匹配規(guī)則:若兩個(gè) PendingIntent 內(nèi)部的 Intent 相同并且 requstCode 也相同翠忠,那么這兩個(gè) PendingIntent 就是相同的鞠苟。

??Intent 的匹配規(guī)則:若兩個(gè) Intent 的 ComponentNameintent-filter 都相同,那么這兩個(gè) intent 就是相同的秽之。(注:Extras 不參與匹配過(guò)程)


??下面介紹參數(shù) flags 的含義:

  • FLAG_ONE_SHOT
    當(dāng)前 PendingIntent 只能被使用一次当娱,然后被 cancel,若后續(xù)還有相同的 PendingIntent考榨,則無(wú)效跨细。通知欄,同類(lèi)的通知只能使用一次河质,后續(xù)的無(wú)法打開(kāi)冀惭。

  • FLAG_NO_CREATE
    當(dāng)前 PendingIntent 不會(huì)主動(dòng)去創(chuàng)建,若之前不存在掀鹅,則獲取 PendingIntent 失斣仆贰(實(shí)際中無(wú)意義)。

  • FLAG_CANCEL_CURRENT
    當(dāng)前 PendingIntent 若已存在淫半,則會(huì)被 cancel溃槐,然后系統(tǒng)會(huì)創(chuàng)建一個(gè)新的 PendingIntent。通知欄科吭,那些被 cancel 的消息將無(wú)法被打開(kāi)昏滴。

  • FLAG_UPDATE_CURRENT
    當(dāng)前 PendingIntent 若已存在,則會(huì)被更新对人,即它們的 intent 中的 Extras 會(huì)被替換成最新的谣殊。

??下面結(jié)合通知欄信息描述這四個(gè)標(biāo)記位,如下代碼:

// 若 notify 的第一個(gè)參數(shù) id 是常量牺弄,多次調(diào)用 notify 只彈出一個(gè)通知姻几,后續(xù)的會(huì)把前面的替換掉
// 若每次 id 都不同,多次調(diào)用 notify 會(huì)彈出多個(gè)通知
manager.notify(1, notification);

??若 notify 的 id 是常量势告,不管 PendingIntent 是否匹配蛇捌,后面的通知會(huì)替換前面的通知。

??若 notify 的 id 每次都不同咱台,當(dāng) PendingIntent不匹配時(shí)络拌,通知之間不互相干擾。PendingIntent 處于匹配狀態(tài)時(shí)回溺,分如下情況:

  • FLAG_ONE_SHOT 后續(xù)通知中的 PendingIntent 會(huì)和第一條通知保持一致春贸,包括其中的 Extras混萝,單擊任何一條通知后,剩余的都無(wú)法打開(kāi)萍恕,當(dāng)所有通知被清除后逸嘀,會(huì)重復(fù)此過(guò)程
  • FLAG_CANCEL_CURRENT 只有最新的通知可以打開(kāi),之前彈出均無(wú)法打開(kāi)
  • FLAG_UPDATE_CURRENT 之前彈出的通知中的 PendingIntent 會(huì)被更新允粤,最終它們和最新的一條通知保持一致厘熟,包括其中的Extras,這些通知都可以被打開(kāi)

5.2 RemoteViews 的內(nèi)部機(jī)制

??RemoteViews 的作用在其他進(jìn)程中顯示并且更新 View 的界面维哈,其最常用的構(gòu)造方法:

// 兩個(gè)參數(shù):第一個(gè)表示當(dāng)前的包名绳姨,第二個(gè)是待加載的布局文件
public RemoteViews(String packageName, int layoutId) {
    this(getApplicationInfo(packageName, UserHandle.myUserId()), layoutId);
}

??RemoteViews 支持的所有 View 類(lèi)型如下:

RemoteViews 所支持的 View 類(lèi)型

??RemoteViews 中不能使用除了上述列表中以外的 View,也無(wú)法使用自定義 View阔挠。

??RemoteViews 沒(méi)有提供 findViewById 方法飘庄,無(wú)法直接訪問(wèn)里面的 View 元素,必須通過(guò)它所提供的一系列 set 方法來(lái)完成购撼。其部分 set 方法如下:

RemoteViews 的部分 set 方法

??關(guān)于 RemoteViews 的內(nèi)部機(jī)制跪削,有興趣的可以去看看書(shū)或源碼,這里提供一張圖迂求,不多做介紹了:

RemoteViews 的內(nèi)部機(jī)制

5.3 RemoteViews 的意義

??下面打造一個(gè)模擬的通知欄效果并且實(shí)現(xiàn)跨進(jìn)程的 UI 更新碾盐。

??有兩個(gè) Activity 分別運(yùn)行在兩個(gè)不同的進(jìn)程,一個(gè)是A揩局,一個(gè)是B毫玖,其中A扮演著通知欄的角色,而B(niǎo)則可以不停地發(fā)送通知欄消息凌盯。為了模擬通知欄的效果付枫,修改A的 process 屬性使其運(yùn)行在單獨(dú)的進(jìn)程中,這樣A和B就構(gòu)成了多進(jìn)程通信的情形驰怎。在B中創(chuàng)建 Remoteviews 對(duì)象阐滩,然后通知A顯示這個(gè) RemoteViews 對(duì)象。

??B每發(fā)送一次模擬通知县忌,就會(huì)發(fā)送一個(gè)特定的廣播掂榔,然后A接收到廣播后就開(kāi)始顯示B中定義的 RemoteViews 對(duì)象,此過(guò)程和系統(tǒng)的通知欄消息的顯示過(guò)程幾乎一致症杏。

??首先看B的實(shí)現(xiàn)装获,B只要構(gòu)造 RemoteViews 對(duì)象并將其傳輸給A即可,代碼如下:

/**
 * Function:模擬通知效果 B activity
 * Author:Wonderful on 2017/8/9 10:30
 * Email:KXwonder@163.com
 */

public class B_Activity extends BaseActivity {
    @Override
    protected int initLayoutId() {
        return R.layout.activity_chapter05_b;
    }

    @Override
    protected void initView() {

    }

    @OnClick(R.id.btn_send)
    public void onViewClicked() {
        ToastUtils.show("發(fā)送廣播");
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.chapter05_notice_item_layout);
        remoteViews.setTextViewText(R.id.tv_title, "發(fā)送給 A 的通知");
        remoteViews.setTextViewText(R.id.tv_content, "mag from process:" + Process.myPid());
        //remoteViews.setImageViewResource(R.id.iv_notice, R.mipmap.ic_notice);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, A_Activity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        PendingIntent pendingIntent2 = PendingIntent.getActivity(this, 0, new Intent(this, NoticeActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.iv_notice, pendingIntent);
        remoteViews.setOnClickPendingIntent(R.id.ll_open_notice, pendingIntent2);
        Intent intent = new Intent(Constants.REMOTE_ACTION);
        // 將RemoteViews 對(duì)象通過(guò)Intent傳輸?shù)紸中
        intent.putExtra(Constants.EXTRA_REMOTE_VIEWS, remoteViews);
        sendBroadcast(intent);
    }
}

??A中只需接收B中的廣播并顯示 RemoteViews 即可鸳慈,代碼如下:

/**
 * Function:模擬通知效果 A activity
 * Author:Wonderful on 2017/8/9 10:30
 * Email:KXwonder@163.com
 */

public class A_Activity extends BaseActivity {

    @BindView(R.id.ll_remoteViews)
    LinearLayout llRemoteViews;

    @Override
    protected int initLayoutId() {
        return R.layout.activity_chapter05_a;
    }

    @Override
    protected void initView() {
        // 注冊(cè)廣播
        IntentFilter intent = new IntentFilter(Constants.REMOTE_ACTION);
        registerReceiver(mBroadcastReceiver, intent);
    }

    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            LogUtils.e("A_activity", "接收廣播成功");
            // 1. 當(dāng)收到廣播后饱溢,從Intent中取出RemoteViews對(duì)象
            RemoteViews remoteViews = intent.getParcelableExtra(Constants.EXTRA_REMOTE_VIEWS);
            if (remoteViews != null) {
                // 2. 通過(guò)apply方法加載布局并且執(zhí)行更新操作喧伞,
                View view = remoteViews.apply(context, llRemoteViews);
                // 3. 將得到的 View 添加到A的布局中
                llRemoteViews.addView(view);
            }
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 解除廣播
        unregisterReceiver(mBroadcastReceiver);
    }

    @OnClick(R.id.btn_to_b)
    public void onViewClicked() {
        // 跳轉(zhuǎn)到 B activity
        IntentUtils.to(this, B_Activity.class);
    }
}

??運(yùn)行效果如下:

模擬通知效果

??現(xiàn)有兩應(yīng)用走芋,一個(gè)應(yīng)用能更新另一個(gè)應(yīng)用中的某個(gè)界面绩郎,這時(shí)可選擇以下兩種方式實(shí)現(xiàn):

  • AIDL 缺點(diǎn):當(dāng)對(duì)界面的更新頻繁時(shí),會(huì)有效率問(wèn)題翁逞,同時(shí) AIDL 接口會(huì)變得復(fù)雜肋杖。
  • RemoteViews 缺點(diǎn):只支持一些常見(jiàn)的View,不支持自定義 View挖函。

??面對(duì)這種問(wèn)題状植,若界面中的 View 是一些簡(jiǎn)單的且被 RemoteViews 支持的 View,可考慮采用 RemoteViews怨喘,否則就不適合用 RemoteViews津畸。


??采用 RemoteViews 來(lái)實(shí)現(xiàn)兩應(yīng)用間的界面更新,還有一個(gè)布局文件的加載問(wèn)題必怜。在上面的代碼中肉拓,直接通過(guò) RemoteViews 的 apply 方法來(lái)加載并更新界面:

// 2. 通過(guò)apply方法加載布局并且執(zhí)行更新操作,
View view = remoteViews.apply(context, llRemoteViews);
// 3. 將得到的 View 添加到A的布局中
llRemoteViews.addView(view);

??這種寫(xiě)法在同一個(gè)應(yīng)用的多進(jìn)程情形下是適用的梳庆,但若A和B屬于不同應(yīng)用暖途,由于資源id不可能剛好一樣,B中的布局文件的資源id傳輸?shù)紸中后可能無(wú)效膏执。

??面對(duì)這種情況驻售,可通過(guò)資源名稱(chēng)來(lái)加載布局文件。

??首先兩個(gè)應(yīng)用要提前約定好 RemoteViews 中的布局的文件名稱(chēng)更米,然后在A中根據(jù)名稱(chēng)找到并加載欺栗,接著再調(diào)用 Remoteviews 的 reapply 方法即可將B中對(duì)View所做的一系列更新操作全作用到A中加載的View上。修改后的代碼如下:

int layoutId = getResources().getIdentifier("layout_simulated_notification","layout",getPackageName());
View view = getLayoutInflater().inflate(layoutId,llRemoteViews,false);
remoteViews.reapply(this,view);
llRemoteViews.addView(view);

??本篇文章就介紹到這征峦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纸巷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子眶痰,更是在濱河造成了極大的恐慌瘤旨,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竖伯,死亡現(xiàn)場(chǎng)離奇詭異存哲,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)七婴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)祟偷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人打厘,你說(shuō)我怎么就攤上這事修肠。” “怎么了户盯?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵嵌施,是天一觀的道長(zhǎng)饲化。 經(jīng)常有香客問(wèn)我,道長(zhǎng)吗伤,這世上最難降的妖魔是什么吃靠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮足淆,結(jié)果婚禮上巢块,老公的妹妹穿的比我還像新娘。我一直安慰自己巧号,他們只是感情好族奢,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著丹鸿,像睡著了一般歹鱼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卜高,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天弥姻,我揣著相機(jī)與錄音,去河邊找鬼掺涛。 笑死庭敦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的薪缆。 我是一名探鬼主播秧廉,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拣帽!你這毒婦竟也來(lái)了疼电?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤减拭,失蹤者是張志新(化名)和其女友劉穎蔽豺,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拧粪,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡修陡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了可霎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魄鸦。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖癣朗,靈堂內(nèi)的尸體忽然破棺而出拾因,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布绢记,位于F島的核電站扁达,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏庭惜。R本人自食惡果不足惜罩驻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一穗酥、第九天 我趴在偏房一處隱蔽的房頂上張望护赊。 院中可真熱鬧,春花似錦砾跃、人聲如沸骏啰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)判耕。三九已至,卻和暖如春翘骂,著一層夾襖步出監(jiān)牢的瞬間壁熄,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工碳竟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留草丧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓莹桅,卻偏偏與公主長(zhǎng)得像昌执,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诈泼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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