【从 0 开始开发一款直播 APP】4.4 网络封装之 OkHttp -- 网络请求实现直播登录

本文为菜鸟窝作者蒋志碧的连载。“从 0 开始开发一款直播 APP ”系列来聊聊时下最火的直播 APP,如何完整的实现一个类"腾讯直播"的商业化项目
视频地址:http://www.cniao5.com/course/10121


【从 0 开始开发一款直播 APP】4.1 网络封装之 Okhttp -- 基础回顾
【从 0 开始开发一款直播 APP】4.2 网络封装之 OkHttp -- GET,POST,前后端交互
【从 0 开始开发一款直播 APP】4.3 网络封装之 OkHttp -- 封装 GET,POST FORM,POST JSON
【从 0 开始开发一款直播 APP】4.4 网络封装之 OkHttp -- 网络请求实现直播登录


上一章讲了 OkHttp 的封装,现在来使用一下封装吧。

网络请求进行手机登录和用户名登录。


先来介绍一个请求工具 postman,Google 浏览器上的一个插件,也有对应的应用程序,亲测很好用,推荐给大家。

好了,开始讲解网络请求,测试一下封装的 Okhttp 框架。
讲解之前添加依赖以及相关权限

compile 'com.google.code.gson:gson:2.3.1'
compile 'com.zhy:okhttputils:2.6.2'

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

一、界面布局

里面用到了一个控件,很漂亮,看到输入框的文字会跳动对吧,就是这个控件。android.support.design.widget.TextInputLayout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/bg_dark"
    android:id="@+id/rl_login_root"
    tools:context="com.dali.admin.livestreaming.activity.LoginActivity">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="19dp"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="100dp">

        //验证码
        <Button
            android:id="@+id/btn_verify_code"
            android:layout_width="90dp"
            android:layout_height="35dp"
            android:layout_alignEnd="@+id/til_login"
            android:layout_alignRight="@+id/til_login"
            android:layout_below="@+id/til_login"
            android:layout_marginRight="5dp"
            android:layout_marginTop="2dp"
            android:background="@drawable/btn_login"
            android:clickable="true"
            android:minWidth="0dp"
            android:padding="4dp"
            android:text="@string/activity_login_verify_code"
            android:textSize="12sp"
            style="@style/loginButton"
            />
        <android.support.design.widget.TextInputLayout
            android:id="@+id/til_login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            >
            //用户名
            <AutoCompleteTextView
                android:id="@+id/et_username"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:hint="@string/activity_login_username"
                android:inputType="textEmailAddress"
                android:maxLength="24"
                android:maxLines="1"
                android:singleLine="true"
                android:textColor="@drawable/tv_selector"
                android:textColorHint="@color/white"
                />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:id="@+id/til_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/til_login">
            //密码
            <EditText
                android:id="@+id/et_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/et_login"
                android:ellipsize="end"
                android:hint="@string/activity_login_password"
                android:imeActionId="@+id/login"
                android:imeOptions="actionUnspecified"
                android:inputType="textPassword"
                android:maxLength="24"
                android:maxLines="1"
                android:singleLine="true"
                android:textColor="@color/white"
                android:textColorHint="@color/white"/>
        </android.support.design.widget.TextInputLayout>

        //登录
        <Button
            android:id="@+id/btn_login"
            android:layout_alignParentEnd="true"
            android:layout_below="@+id/til_password"
            android:background="@drawable/btn_login"
            android:clickable="true"
            android:padding="0dp"
            android:text="@string/activity_login_btnlogin"
            style="@style/loginButton"/>

        //手机号登录
        <Button
            android:id="@+id/btn_phone_login"
            android:layout_width="wrap_content"
            android:layout_below="@+id/btn_login"
            android:layout_marginTop="10dp"
            android:text="@string/activity_login_btnphone"
            android:background="?attr/selectableItemBackground"
            style="@style/loginButton"
            />

        //注册新用户
        <Button
            android:id="@+id/btn_register"
            android:layout_width="wrap_content"
            android:layout_alignEnd="@+id/btn_login"
            android:layout_alignRight="@+id/btn_login"
            android:layout_below="@+id/btn_login"
            android:background="?attr/selectableItemBackground"
            android:layout_marginTop="10dp"
            android:text="@string/activity_login_register"
            style="@style/loginButton"
            />

        <ProgressBar
            android:id="@+id/progressbar"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_alignTop="@+id/btn_login"
            android:layout_centerHorizontal="true"
            android:visibility="gone"/>
    </RelativeLayout>
</RelativeLayout>

二、登录界面逻辑实现

2.1、类的初始化

创建 LoginActivity 类,继承 BaseActivity,实现其抽象方法。实例化控件。

public class LoginActivity extends BaseActivity implements View.OnClickListener{
    //控件
    private ProgressBar progressBar;
    private EditText etPassword;
    private EditText etLogin;
    private Button btnLogin;
    private Button btnPhoneLogin;
    private TextInputLayout tilLogin, tilPassword;
    private Button btnRegister;
    private TextView tvVerifyCode;
    //是否是手机号登录
    private boolean isPhoneLogin = false;
  
    @Override
    protected void setActionBar() {
    }

    @Override
    protected void setListener() {
    }

    @Override
    protected void initData() {
    }

    @Override
    protected void initView() {
        etLogin = obtainView(R.id.et_username);
        etPassword = obtainView(R.id.et_password);
        btnRegister = obtainView(R.id.btn_register);
        btnPhoneLogin = obtainView(R.id.btn_phone_login);
        btnLogin = obtainView(R.id.btn_login);
        progressBar = obtainView(R.id.progressbar);
        tilLogin = obtainView(til_login);
        tilPassword = obtainView(R.id.til_password);
        tvVerifyCode = obtainView(R.id.btn_verify_code);
        //第一次进入系统默认是用户名登录
        userNameLoginViewInit();
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_login;
    }
  
    @Override
    public void onClick(View v) {
    }
}

2.2、用户名登录实现

这里实现逻辑,解释一下实现思路,而登录请求网络后面介绍。

//用户名登录方法
public void userNameLoginViewInit() {
    //用户名登录控件初始化
    userLoginTrans();

    //注册监听
    btnRegister.setOnClickListener(this);
    //这里只是用做切换界面,用户名登录情况下点击按钮显示到手机号登录,显示获取验证码按钮
    btnPhoneLogin.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //手机号登录切换
            phoneLoginViewinit();
        }
    });
    //登录按钮监听
    btnLogin.setOnClickListener(this);
}
//用户名登录界面控件显示
private void userLoginTrans() {
        //将手机号登录设置为 false
        isPhoneLogin = false;
        //隐藏获取验证码按钮
        tvVerifyCode.setVisibility(View.GONE);
        AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
        alphaAnimation.setDuration(250);
        tvVerifyCode.setAnimation(alphaAnimation);
        //设置输入框输入类型为 文本输入
        etLogin.setInputType(EditorInfo.TYPE_CLASS_TEXT);
        //清空输入框内容
        etLogin.setText("");
        etPassword.setText("");
        //设置用户名登录按钮文字为 手机号登录
        btnPhoneLogin.setText("手机号登录");
        //设置 TextInputLayout 文字为 用户名和密码
        tilLogin.setHint("用户名");
        tilPassword.setHint("密码");
}

2.3、手机号登录实现

如上,实现逻辑,登录请求网络接下来介绍。

//手机号登录方法
public void phoneLoginViewinit() {
    //用户名登录控件初始化
    phoneLoginTrans();
    //这里只是用做切换界面,用户名登录情况下点击按钮显示到手机号登录,显示获取验证码按钮
    btnPhoneLogin.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //转换为用户名登录界面
            userNameLoginViewInit();
        }
    });
    //登录按钮监听
    btnLogin.setOnClickListener(this);
}
//手机号登录控件显示
private void phoneLoginTrans() {
    //将手机号登录设置为 true
    isPhoneLogin = true;
    //显示获取验证码按钮
    tvVerifyCode.setVisibility(View.VISIBLE);
    AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f, 1.0f);
    alphaAnimation.setDuration(250);
    tvVerifyCode.setAnimation(alphaAnimation);
    //设定点击优先级于最前(避免被EditText遮挡的情况)
    tvVerifyCode.bringToFront();
    //设置输入框输入类型为 手机号
    etLogin.setInputType(EditorInfo.TYPE_CLASS_PHONE);
    //清空输入框内容
    etLogin.setText("");
    etPassword.setText("");
    //手机号登录按钮文字改为 用户名登录
    btnPhoneLogin.setText("用户名登录");
    //设置 TextInputLayout 文字为 手机号和密码
    tilLogin.setHint("手机号");
    tilPassword.setHint("密码");
}

2.4、请求网络实现登录


2.4.1、用户名登录

之前介绍的工具还没用上呢,现在来请求网络,看看需要那些数据,请求参数有登录方式 action,用户名 userName 和 密码 password。


2.4.2、为如上数据创建一个请求实体类。

public class LoginRequest extends IRequest {
   public LoginRequest(int requestId, String userName, String password) {
      mRequestId = requestId;
      mParams.put("action", "login");
      mParams.put("userName", userName);
      mParams.put("password", password);
   }

   //getHost():返回的 API,这里在封装 OkHttp 框架的时候有的,HOST_PUBLIC = "http://live.demo.cniao5.com/Api/";
   @Override
   public String getUrl() {
      return getHost() + "User";
   }

   @Override
   public Type getParserType() {
      return new TypeToken<Response<UserInfo>>() {
      }.getType();
   }
}

2.4.3、网络请求实现用户名登录

public void usernameLogin(final String userName, final String password) {
    //检查网络状态,需要添加网络使用权限:ACCESS_NETWORK_STATE
    if (checkUserNameLogin(userName, password)) {
        // RequestComm.login 是 requestId:值是120,后台提供
        LoginRequest req = new LoginRequest(RequestComm.login, userName, password);
        AsyncHttp.instance().postJson(req, new AsyncHttp.IHttpListener() {
            @Override//请求网络之前调用
            public void onStart(int requestId) {
                //显示环形进度条
                showOnLoading(true);
            }

            @Override
            public void onSuccess(int requestId, Response response) {
                //RequestComm.SUCCESS 状态验证:值是0,上面请求网络有显示
                if (response.status == RequestComm.SUCCESS) {
                    Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                }
                //隐藏环形进度条
                showOnLoading(false);
            }

            @Override
            public void onFailure(int requestId, int httpStatus, Throwable error) {
                showOnLoading(false);//隐藏环形进度条
                Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

2.5、手机登录实现

手机号登录先来测试网络数据API,看看实体类需要的数据。请求参数有登录方式 action,手机号 mobile 和 验证码 verifyCode。


2.5.1、创建手机登录请求实体类

public class PhoneLoginRequest extends IRequest {
   public PhoneLoginRequest(int requestId, String mobile, String verifyCode) {
      mRequestId = requestId;
      mParams.put("action", "phoneLogin");
      mParams.put("mobile", mobile);
      mParams.put("verifyCode", verifyCode);
   }

  //getHost():返回的 API,这里在封装 OkHttp 框架的时候有的,HOST_PUBLIC = "http://live.demo.cniao5.com/Api/";
   @Override
   public String getUrl() {
      return getHost() + "User";
   }

   @Override
   public Type getParserType() {
      return new TypeToken<Response>() {
      }.getType();
   }
}

2.5.2、网络请求实现手机号登录

public void phoneLogin(final String mobile, String verifyCode) {
    //检查网络状态,需要添加网络使用权限:ACCESS_NETWORK_STATE
    if (checkPhoneLogin(mobile, verifyCode)) {//requestId = 1200,后台提供
        PhoneLoginRequest req = new PhoneLoginRequest(1200, mobile, verifyCode);
        AsyncHttp.instance().postJson(req, new AsyncHttp.IHttpListener() {
            @Override//请求网络之前调用
            public void onStart(int requestId) {
                showOnLoading(true);//显示环形进度条
            }

            @Override
            public void onSuccess(int requestId, Response response) {
                //RequestComm.SUCCESS 状态验证:值是0,上面请求网络有显示
                if (response.status == RequestComm.SUCCESS) {
                    Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                }
                showOnLoading(false);//隐藏环形进度条
            }

            @Override
            public void onFailure(int requestId, int httpStatus, Throwable error) {
                showOnLoading(false);//隐藏环形进度条
                Toast.makeText(LoginActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

检查用户名登录、手机登录、环形进度条显示或隐藏代码

//监测用户名登录
public boolean checkUserNameLogin(String userName, String password) {
    if (OtherUtils.isUsernameVaild(userName)) {
        if (OtherUtils.isPasswordValid(password)) {
            if (OtherUtils.isNetworkAvailable(this)) {
                return true;
            } else {
                ToastUtils.showShort(this, "当前无网络连接");
            }
        } else {
            ToastUtils.showShort(this, "密码过短");
        }
    } else {
        ToastUtils.showShort(this, "用户名不符合规范");
    }
    return false;
}
//监测手机号登录
public boolean checkPhoneLogin(String phone, String verifyCode) {
        if (OtherUtils.isPhoneNumValid(phone)) {
            if (OtherUtils.isVerifyCodeValid(verifyCode)) {
                if (OtherUtils.isNetworkAvailable(this)) {
                    return true;
                } else {
                    ToastUtils.showShort(this, "当前无网络连接");
                }
            } else {
                ToastUtils.showShort(this, "验证码错误");
            }
        } else {
            ToastUtils.showShort(this, "手机格式错误");
        }
        return false;
}
//进度条显示与隐藏
public void showOnLoading(boolean active) {
        if (active) {
            //显示进度条
            progressBar.setVisibility(View.VISIBLE);
            //显示登录按钮
            btnLogin.setVisibility(View.INVISIBLE);
            //输入框设置不可用
            etLogin.setEnabled(false);
            etPassword.setEnabled(false);
            //手机号按钮和按钮设置为不可点击
            btnPhoneLogin.setClickable(false);
            btnRegister.setClickable(false);
 btnRegister.setTextColor(getResources().getColor(R.color.colorTransparentGray));          btnPhoneLogin.setTextColor(getResources().getColor(R.color.colorTransparentGray));
            
        } else {
            //隐藏进度条
            progressBar.setVisibility(View.GONE);
            //隐藏登录按钮
            btnLogin.setVisibility(View.VISIBLE);
            //输入框设置可用
            etLogin.setEnabled(true);
            etPassword.setEnabled(true);
            //手机号按钮和按钮设置为可点击
            btnPhoneLogin.setClickable(true);
            btnRegister.setClickable(true);
            btnRegister.setTextColor(getResources().getColor(R.color.white));
            btnPhoneLogin.setTextColor(getResources().getColor(R.color.white));
        }
}

2.6、手机号登录和用户名登录切换

@Override
public void onClick(View v) {
    if (isPhoneLogin){
        phoneLogin(etLogin.getText().toString(), etPassword.getText().toString());
    }else {
        usernameLogin(etLogin.getText().toString(), etPassword.getText().toString());
    }

}

三、完整的代码实现

public class LoginActivity extends BaseActivity implements View.OnClickListener {
    private ProgressBar progressBar;
    private EditText etPassword;
    private EditText etLogin;
    private Button btnLogin;
    private Button btnPhoneLogin;
    private TextInputLayout tilLogin, tilPassword;
    private Button btnRegister;
    private TextView tvVerifyCode;
    private boolean isPhoneLogin = false;

    @Override
    protected void setActionBar() {
    }

    @Override
    protected void setListener() {
    }

    @Override
    protected void initData() {
    }

    @Override
    protected void initView() {
        etLogin = obtainView(R.id.et_username);
        etPassword = obtainView(R.id.et_password);
        btnRegister = obtainView(R.id.btn_register);
        btnPhoneLogin = obtainView(R.id.btn_phone_login);
        btnLogin = obtainView(R.id.btn_login);
        progressBar = obtainView(R.id.progressbar);
        tilLogin = obtainView(til_login);
        tilPassword = obtainView(R.id.til_password);
        tvVerifyCode = obtainView(R.id.btn_verify_code);
        userNameLoginViewInit();
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_login;
    }

    /**
     * 用户名密码登录界面
     */
    public void userNameLoginViewInit() {
        userLoginTrans();
        btnRegister.setOnClickListener(this);
        btnPhoneLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //手机号登录
                phoneLoginViewinit();
            }
        });
        //用户名登录
        btnLogin.setOnClickListener(this);

    }

    public void phoneLoginViewinit() {
        phoneLoginTrans();
                //转换为用户名登录界面
                userNameLoginViewInit();
            }
        });
        btnLogin.setOnClickListener(this);
    }

    private void phoneLoginTrans() {
        isPhoneLogin = true;
        tvVerifyCode.setVisibility(View.VISIBLE);
        AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f, 1.0f);
        alphaAnimation.setDuration(250);
        tvVerifyCode.setAnimation(alphaAnimation);
        tvVerifyCode.bringToFront();
        etLogin.setInputType(EditorInfo.TYPE_CLASS_PHONE);
        etLogin.setText("");
        etPassword.setText("");
        btnPhoneLogin.setText("用户名登录");
        tilLogin.setHint("手机号");
        tilPassword.setHint("密码");
    }

    private void userLoginTrans() {
        isPhoneLogin = false;
        tvVerifyCode.setVisibility(View.GONE);
        AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
        alphaAnimation.setDuration(250);
        tvVerifyCode.setAnimation(alphaAnimation);
        etLogin.setInputType(EditorInfo.TYPE_CLASS_TEXT);
        etLogin.setText("");
        etPassword.setText("");
        btnPhoneLogin.setText("手机号登录");
        tilLogin.setHint("用户名");
        tilPassword.setHint("密码");
    }

    /**
     * 手机登录和用户名登录界面显示或隐藏
     */
    public void showOnLoading(boolean active) {
        if (active) {
            progressBar.setVisibility(View.VISIBLE);
            btnLogin.setVisibility(View.INVISIBLE);
            etLogin.setEnabled(false);
            etPassword.setEnabled(false);
            btnPhoneLogin.setClickable(false);
 btnRegister.setTextColor(getResources().getColor(R.color.colorTransparentGray));         btnPhoneLogin.setTextColor(getResources().getColor(R.color.colorTransparentGray));
            btnRegister.setClickable(false);
        } else {
            progressBar.setVisibility(View.GONE);
            btnLogin.setVisibility(View.VISIBLE);
            etLogin.setEnabled(true);
            etPassword.setEnabled(true);
            btnPhoneLogin.setClickable(true);
            btnRegister.setClickable(true);
            btnRegister.setTextColor(getResources().getColor(R.color.white));
            btnPhoneLogin.setTextColor(getResources().getColor(R.color.white));
        }
    }

    public void phoneLogin(final String mobile, String verifyCode) {
        if (checkPhoneLogin(mobile, verifyCode)) {
            PhoneLoginRequest req = new PhoneLoginRequest(1200, mobile, verifyCode);
            AsyncHttp.instance().postJson(req, new AsyncHttp.IHttpListener() {
                @Override
                public void onStart(int requestId) {
                    showOnLoading(true);
                }

                @Override
                public void onSuccess(int requestId, Response response) {
                    if (response.status == RequestComm.SUCCESS) {
                        Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                    }
                    showOnLoading(false);
                }
                @Override
                public void onFailure(int requestId, int httpStatus, Throwable error) {
                    showOnLoading(false);
                    Toast.makeText(LoginActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    public boolean checkPhoneLogin(String phone, String verifyCode) {
        if (OtherUtils.isPhoneNumValid(phone)) {
            if (OtherUtils.isVerifyCodeValid(verifyCode)) {
                if (OtherUtils.isNetworkAvailable(this)) {
                    return true;
                } else {
                    ToastUtils.showShort(this, "当前无网络连接");
                }
            } else {
                ToastUtils.showShort(this, "验证码错误");
            }
        } else {
            ToastUtils.showShort(this, "手机格式错误");
        }
        return false;
    }

    public void usernameLogin(final String userName, final String password) {
        if (checkUserNameLogin(userName, password)) {
            LoginRequest req = new LoginRequest(RequestComm.login, userName, password);
            AsyncHttp.instance().postJson(req, new AsyncHttp.IHttpListener() {
                @Override
                public void onStart(int requestId) {
                    showOnLoading(true);
                }

                @Override
                public void onSuccess(int requestId, Response response) {
                    if (response.status == RequestComm.SUCCESS) {
                        Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                    }
                    showOnLoading(false);
                }

                @Override
                public void onFailure(int requestId, int httpStatus, Throwable error) {
                    showOnLoading(false);
                    Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    public boolean checkUserNameLogin(String userName, String password) {
        if (OtherUtils.isUsernameVaild(userName)) {
            if (OtherUtils.isPasswordValid(password)) {
                if (OtherUtils.isNetworkAvailable(this)) {
                    return true;
                } else {
                    ToastUtils.showShort(this, "当前无网络连接");
                }
            } else {
                ToastUtils.showShort(this, "密码过短");
            }
        } else {
            ToastUtils.showShort(this, "用户名不符合规范");
        }
        return false;
    }

    @Override
    public void onClick(View v) {
        if (isPhoneLogin){
            phoneLogin(etLogin.getText().toString(), etPassword.getText().toString());
        }else {
            usernameLogin(etLogin.getText().toString(), etPassword.getText().toString());
        }
    }
}

140套Android优秀开源项目源码,领取地址:http://mp.weixin.qq.com/s/afPGHqfdiApALZqHsXbw-A

写得不到位的地方还望大家指正。

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

推荐阅读更多精彩内容