Android——Service 服务

描述

Service通常总是称之为“后台服务”,其中“后台”一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面;

因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件:
1、并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的);
2、具有较长时间的运行特性。

Service特性

1、Service本身都是运行在其所在进程的主线程(如果Service与Clinet同属于一个进程,则是运行于UI线程),但Service一般都是需要进行”长期“操作,所以经常写法是在自定义Service中处理”长期“操作时需要新建线程,以免阻塞UI线程或导致ANR;

2、Service一旦创建,需要停止时都需要显示调用相应的方法(startService需要调用stopService()或Service本身调用stopSelf(..);
bindService需要调用unbindService(),否则对于startService将处于一直运行状态,对于bindService,当Client生命周期结束时也将因此问题。也就是说,Service执行完毕后,必须人为的去停止它。

startService

startService()启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的;
使用步骤如下:
1、创建Service子类,继承自Service

2、在AndroidManifest文件中注册Service:
项目中的每一个Service都必须在AndroidManifest.xml中注册才能生效。

3、启动Service:
当第一次启动Service的时候,会调用该Service中的onCreate()和onStartCommand(Intent intent, int flags, int startId)方法。若再次启动Service,onCreate()不会被调用,只有onStartCommand(Intent intent, int flags, int startId)方法才会调用。其中参数flags默认情况下是0,对应的常量名为START_STICKY_COMPATIBILITY。startId是一个唯一的整型,用于表示此次Client执行startService(...)的请求请求标识,在多次startService(...)的情况下,呈现0,1,2....递增。

4、销毁Service:
无论多少次的startService,只需要一次stopService()即可将此Service终止,执行onDestroy()函数(其实很好理解,因为onDestroy()与onCreate()回调是相对的)。

5、注意点:
5.1、当用户强制kill掉进程时,onDestroy()是不会执行的。
5.2、对于同一个Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。
5.3、Service通过startService(..)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(..)或Service本身调用stopSelf(..)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。
5.4、Client A 通过startService()启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService()结束此Service。
5.5、Client调用stopService()时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService()无需做当前Service是否有效的判断。
5.6、当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称,当此Service需要对其他App开放时,android:exported属性值需要设置为true(当然,在有intent-filter时默认值就是true)。

自定义Service
public class MyService extends Service {

    public static final String TAG = "MyService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate() executed");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand() executed");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy() executed");
    }

    //返回具体的IBind对象
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

在AndroidManifest文件中注册Service
<service
      android:name=".MyService"
      android:exported="false">
</service>
startService
public class ServiceTestOneActivity extends BaseActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_test);

        Log.e("ServiceTestOneActivity",
                "ServiceTestOneActivity thread id is " + Thread.currentThread().getId());

        findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent startIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                startService(startIntent);
            }
        });

        findViewById(R.id.bt_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent stopIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                stopService(stopIntent);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

}

bindService

bindService的主要特性在于Service的生命周期是依附于Client的生命周期的,当Client销毁时,bindService将执行onDestroy。

同时通过Service中的Binder对象可以较为方便进行Client-Service通信。bindService一般使用过程如下:
1、创建Service子类,继承自Service,并重写onBind(Intent intent)方法,此方法中需要返回具体的Binder对象。

2、Client通过实现ServiceConnection接口来自定义ServiceConnection,并通过bindService (Intent service, ServiceConnection sc, int flags)方法将Service绑定到此Client上;

3、自定义的 ServiceConnection 中实现 onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例;

4、通过获取的Binder实例进行Service端其他公共方法的调用,以完成Client-Service通信;

5、当Client在恰当的生命周期(如onDestroy等)时,此时需要解绑之前已经绑定的Service,通过调用函数unbindService(ServiceConnection sc)。

6、注意点
6.1、bindService()会调用Service的与onCreate()和 onBind()方法,不会调用onStartCommand()方法,但是会调用ServiceConnection中的onServiceConnected()方法。
6.2、unbindService()销毁服务会调用Service的onUnBind()方法。
6.3、如果关闭当前Activity,必须在Activity的 onDestroy()中取消绑定Service。
6.4、不可重复调用unbindService()取消绑定,否则会出现 Service not registered 异常。
6.5、当Activity关闭后,如果没有调用unbindService()取消绑定服务,此Service会自动调用 onDestroy()方法,但是这种方式是不安全的,建议主动取消绑定。

自定义BinderService
public class MyService extends Service {

    public static final String TAG = "MyService";
    public boolean isServiceBind = false;

    public MyBinder myBind = new MyBinder();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "MyService thread id is " + Thread.currentThread().getId());
        Log.e(TAG, "onCreate() executed");
        createForegroundService();
    }

    //创建前台服务
    private void createForegroundService() {
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
        Notification.Builder builder = new Notification.Builder(getApplicationContext());
        builder.setContentTitle("***服务");
        builder.setContentText("请勿关闭,***");
        builder.setSmallIcon(R.mipmap.service_icon);
        builder.setContentIntent(pendingIntent);
        Notification notification = builder.build();

        //启动前台服务
        startForeground(1,notification);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand() executed");
        return super.onStartCommand(intent, flags, startId);
    }

    // 返回具体的IBind对象
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind() executed");
        isServiceBind = true;
        return myBind;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        isServiceBind = false;
        Log.e(TAG, "onUnbind() executed");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //停止前台服务
        stopForeground(true);
        Log.e(TAG, "onDestroy() executed");
    }

    public void doSomeThing() {
        Log.e(TAG, "doSomeThing() executed");
    }

    public class MyBinder extends Binder {

        public MyService getService() {
            return MyService.this;
        }

        public void doWork() {
            Log.e("MyBind", "doWork() executed");
        }
    }
}

使用bindService启动
public class ServiceTestOneActivity extends BaseActivity {

    private MyService myService;
    private MyService.MyBinder myBinder;

    private MyReceiver myReceiver;
    private ServiceConnection connection = new ServiceConnection() {

        public static final String TAG = "ServiceConnection";

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // 服务断开连接
            Log.e(TAG, "onServiceDisconnected() executed");
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 服务连接成功,可得到IBinder对象,也可以通过IBinder得到Service实例
            Log.e(TAG, "onServiceConnected() executed");
            myBinder = (MyService.MyBinder) service;
            myService = myBinder.getService();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_test);

        Log.e("ServiceTestOneActivity",
                "ServiceTestOneActivity thread id is " + Thread.currentThread().getId());

        initBroadcast();

        findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent startIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                startService(startIntent);
            }
        });

        findViewById(R.id.bt_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent stopIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                stopService(stopIntent);
            }
        });

        findViewById(R.id.bt_bind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service,
                // 这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。
                Intent bindIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
                bindService(bindIntent, connection, Context.BIND_AUTO_CREATE);
            }
        });

        findViewById(R.id.bt_unbind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkServiceIsBind();
            }
        });

        findViewById(R.id.bt_do_work).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != myService && null != myBinder) {
                    myService.doSomeThing();
                    myBinder.doWork();
                }
            }
        });
    }

    private void checkServiceIsBind() {
        if (null != myService && myService.isServiceBind) {
            myService = null;
            myBinder = null;
            unbindService(connection);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        checkServiceIsBind();
    }
}

startService和bindService交叉使用

如果既点击了Start Service按钮,又点击了Bind Service按钮会怎么样呢?

这个时候你会发现,不管你是单独点击Stop Service按钮还是Unbind Service按钮,Service都不会被销毁,必需将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联, 一个Service必须要在既没有和任何Activity关联又处于停止状态的时候才会被销毁。

Service和Thread

实际上Service和Thread是没有任何关系的,Service实际上就运行在主线程上。

1、Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。
比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。

2、Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。 因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

3、一个比较标准的Service就可以写成:

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 开始执行后台任务
                }
            }).start();
            return super.onStartCommand(intent, flags, startId);
        }

        //或者
        class MyBinder extends Binder {
            public void startDownload() {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // 执行具体的下载任务
                    }
                }).start();
            }
        }

创建前台Service

前台服务是那些被认为用户知道(用户所认可的)且在系统内存不足的时候不允许系统杀死的服务。前台服务必须给状态栏提供一个通知,它被放到正在运行(Ongoing)标题之下——这就意味着通知只有在这个服务被终止或从前台主动移除通知后才能被解除。

Service几乎都是在后台运行的,Service的系统优先级还是比较低的,当系统出现内存不足情况时,就有可能会回收掉正在后台运行的Service。

如果你希望Service可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service。

前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。

ex:App中的音乐播放服务应被设置在前台运行(前台服务)——在App后台运行时,便于用户明确知道它的当前操作、在状态栏中指明当前歌曲信息、提供对应操作。

            //创建前台服务
            private void createForegroundService() {
                Intent notificationIntent = new Intent(this, MainActivity.class);
                PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
                Notification.Builder builder = new Notification.Builder(getApplicationContext());
                builder.setContentTitle("***服务");
                builder.setContentText("请勿关闭,***");
                builder.setSmallIcon(R.mipmap.service_icon);
                builder.setContentIntent(pendingIntent);
                Notification notification = builder.build();

                //启动前台服务
                startForeground(1,notification);
            }

            @Override
            public void onDestroy() {
                super.onDestroy();
                //停止前台服务
                stopForeground(true);
            }

IntentService

1、IntentService是继承于Service并处理异步请求的一个类。
注意这句话——“继承于Service”和“处理异步请求”。
“继承于Service”表示他是一个服务,我们知道Service是存在于主线程的,它之中不能存在耗时操作,否则的话回应起ANR,因此便有了IntentService——这个封装了HandlerThread和Handler的特殊Service。

2、特性:
2.1、IntentService中只有“一个”默认的HandlerThread线程用来处理异步任务;
2.2、默认直接实现了onBind()方法,直接返回null,并定义了抽象方法onHandlerIntent(),用户自定义子类时,需要实现此方法;
2.3、onHandlerIntent()主要就是用来处于相应的“长期”任务的,并且已经自动在新的线程中,用户无语自定义新线程;
2.4、当“长期”任务执行完毕后(也就是onHandlerIntent()执行完毕后),此IntentService将自动结束,无需人为调用方法使其结束;
2.5、IntentService处理任务时,也是按照队列的方式一个个去处理,而非真正意义上的多线程并发方式。
2.6、onHandleIntent(Intent)发生在子线程,不能直接更新UI,需要先把结果发到Activity中
2.7、提交的任务顺序执行,如果一个任务A正在IntentService中执行,此时发送另一个异步任务B到IntentService中,那么必须等到任务A执行完之后任务B才会开始执行

3、使用IntentService的好处:
3.1、我们省去了在 Service 中手动开线程的麻烦,
3.2、当操作完成时,我们不用手动停止 Service。

自定义IntentService
public class MyIntentService extends IntentService {

    public static final String TAG = "MyIntentService";

    public static final String ACTION_ONE = "action_one";
    public static final String ACTION_TWO = "action_two";
    public static final String ACTION_BROADCAST = "action_broad";
    private int progressOne, progressTwo;

    //无参的构造方法,指定线程名称
    public MyIntentService() {
        // 线程的名称
        super("MyIntentService");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate() executed");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand() executed");
        return super.onStartCommand(intent, flags, startId);
    }

    //实现此方法,处理异步任务,此方法运行在子线程(即HandlerThread)
    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null && intent.getAction() != null) {
            switch (intent.getAction()) {
                case ACTION_ONE:
                    while (progressOne < 100) {
                        progressOne++;
                        //发送广播通知UI线程更新UI
                        sendBroadcast(getUpdateIntent(0, progressOne));
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case ACTION_TWO:
                    while (progressTwo < 100) {
                        progressTwo++;
                        //发送广播通知UI线程更新UI
                        sendBroadcast(getUpdateIntent(1, progressTwo));
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy() executed");
    }

    private Intent getUpdateIntent(int i, int progress) {
        Intent intent = new Intent(ACTION_BROADCAST);
        intent.putExtra("type", i);
        intent.putExtra("progress", progress);
        return intent;
    }

}

启动IntentService
public class ServiceTestOneActivity extends BaseActivity {

    private TextView textViewOne;
    private TextView textViewTwo;

    private MyReceiver myReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service_test);

        textViewOne = findViewById(R.id.tv_one);
        textViewTwo = findViewById(R.id.tv_two);

        initBroadcast();

        findViewById(R.id.bt_intent_one).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(ServiceTestOneActivity.this, MyIntentService.class);
                intent.setAction(MyIntentService.ACTION_ONE);
                startService(intent);
            }
        });

        findViewById(R.id.bt_intent_two).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(ServiceTestOneActivity.this, MyIntentService.class);
                intent.setAction(MyIntentService.ACTION_TWO);
                startService(intent);
            }
        });
    }

    // 注册广播
    private void initBroadcast() {
        myReceiver = new MyReceiver();
        registerReceiver(myReceiver, new IntentFilter(MyIntentService.ACTION_BROADCAST));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    public class MyReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            switch (action) {
                case MyIntentService.ACTION_BROADCAST:
                    if (intent.getIntExtra("type", 0) == 0) {
                        textViewOne.setText(intent.getIntExtra("progress", 0) + "");
                    } else {
                        textViewTwo.setText(intent.getIntExtra("progress", 0) + "");
                    }
                    break;
            }
        }
    }

}

远程服务,即AIDL实现进程间通信

Android Interface Definition Language,也就是Android接口定义语言。是的,首先我们知道的第一点就是:AIDL是一种语言。
实现步骤:
1、创建AIDL文件,会自动生成aidl文件。创建成功后再/main目录下自动创建aidl文件夹。


图片.png
// IMyAIDLService.aidl
package com.android.pkqup.androidnote.service_test;

// Declare any non-default types here with import statements

interface IMyAIDLService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    int plus(int a, int b);

    String toUpperCase(String str);
}

2、创建Service,以IMyAIDLService.Stub()实例作为IBinder对象在onBind()方法中返回。

public class RemoteService extends Service {
    
    public static final String TAG = "RemoteService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate() executed");
        Log.e(TAG, "ServiceTestOneActivity process id is " + Process.myPid());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand() executed");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy() executed");
    }

    // 返回具体的IBind对象
    @Override
    public IBinder onBind(Intent intent) {
       //以AIDL的Stub作为IBinder返回
        return binder;
    }

    IMyAIDLService.Stub binder = new IMyAIDLService.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString) throws RemoteException {
        }

        // 相加
        @Override
        public int plus(int a, int b) throws RemoteException {
            return a + b;
        }

        // 转大写
        @Override
        public String toUpperCase(String str) throws RemoteException {
            if (str != null) {
                return str.toUpperCase();
            }
            return null;
        }
    };
}

3、在AndroidManifest文件中注册远程Service。
注意:android:process=":remote"

       <service
            android:exported="true"
            android:name=".service_test.RemoteService"
            android:process=":remote">
            <!--给远程service创建一个意图过滤器 提供给其他应用做隐式意图-->
            <intent-filter>
                <action android:name="com.android.pkqup.androidnote.remote.service" />
            </intent-filter>
       </service>

4、复制整个aidl文件夹到第三方工程的 /main 目录下。

5、在第三方应用中bindService。

private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IMyAIDLService myAIDLService = IMyAIDLService.Stub.asInterface(service);
            try {
                int result = myAIDLService.plus(50, 50);
                String upperStr = myAIDLService.toUpperCase("comes from ClientTest");
                Log.d("TAG", "result is " + result);
                Log.d("TAG", "upperStr is " + upperStr);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

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