Android網(wǎng)絡(luò)狀態(tài)變化監(jiān)聽

Android網(wǎng)絡(luò)狀態(tài)監(jiān)聽實(shí)現(xiàn)

功能分析

背景介紹

為了給用戶一個(gè)好的使用體驗(yàn),尤其是一些視頻嘁扼、圖片類型的app趁啸,我們經(jīng)常需要在用戶網(wǎng)絡(luò)狀態(tài)發(fā)生變化的時(shí)候給用戶一些及時(shí)的提示督惰,比如當(dāng)前從Wi-Fi切換到GPRS,那么就需要給用戶提示是否需要繼續(xù)播放并會產(chǎn)生多少流量访娶。對于網(wǎng)絡(luò)狀態(tài)變化的監(jiān)聽方法很簡單崖疤,不管是用廣播還是NetworkCallback都可以很好實(shí)現(xiàn)。本文從一個(gè)小架構(gòu)的角度劫哼,嘗試把網(wǎng)絡(luò)狀態(tài)的監(jiān)聽功能抽出封裝成一個(gè)lib庫权烧,便于任何一個(gè)項(xiàng)目、版本使用妻率。

功能分析

要監(jiān)聽網(wǎng)絡(luò)狀態(tài)發(fā)生變化板祝,以及對于Android不同版本的支持,站在一個(gè)lib角度來實(shí)現(xiàn)該功能的話囊嘉,我們就需要做到以下幾點(diǎn):

  • 定義好網(wǎng)絡(luò)的狀態(tài)
  • 根據(jù)不同版本使用不同的網(wǎng)絡(luò)監(jiān)聽方法
  • 讓使用的地方盡可能的少集成即可使用該功能

網(wǎng)絡(luò)狀態(tài)定義

對于手機(jī)而言扭粱,我們關(guān)注的網(wǎng)絡(luò)狀態(tài)大體有三種:沒網(wǎng)情況震檩、Wi-Fi情況、移動(dòng)蜂窩GPRS博其,對于狀態(tài)的定義迂猴,我們要用到j(luò)ava的枚舉類型來定義這些類型。

網(wǎng)絡(luò)狀態(tài)變化監(jiān)聽方法

  • BroadcastReceiver

一開始的時(shí)候峰髓,我們可能都習(xí)慣于用BroadcastReceiver來監(jiān)聽網(wǎng)絡(luò)狀態(tài)的變化息尺,BroadcastReceiver的注冊分為靜態(tài)manifest注冊和動(dòng)態(tài)注冊搂誉,雖然通過manifest注冊比較簡單,但是在Android 7.0(targetSdkVersion >= 24)以后并级,新版本移除了一些隱式的廣播,意味著7.0及以上版本無法通過manifest注冊廣播來監(jiān)聽網(wǎng)絡(luò)狀態(tài)變化广恢,所以通過BroadcastReceiver的方式我們只能在代碼中動(dòng)態(tài)注冊廣播了钉迷。

  • NetworkCallback

我們要做的功能時(shí)監(jiān)聽網(wǎng)絡(luò)狀態(tài)的變化糠聪,Android 21版本時(shí)增加了NetworkCallback類來監(jiān)聽網(wǎng)絡(luò)狀態(tài)的變化谐鼎,源碼如下:

public static class NetworkCallback {
    public NetworkCallback() {
        throw new RuntimeException("Stub!");
    }

    public void onAvailable(Network network) {//網(wǎng)絡(luò)可用的時(shí)候調(diào)用
        throw new RuntimeException("Stub!");
    }

    public void onLosing(Network network, int maxMsToLive) {//網(wǎng)絡(luò)正在減弱狸棍,鏈接會丟失數(shù)據(jù)草戈,即將斷開網(wǎng)絡(luò)時(shí)調(diào)用
        throw new RuntimeException("Stub!");
    }

    public void onLost(Network network) {//網(wǎng)絡(luò)斷開時(shí)調(diào)用
        throw new RuntimeException("Stub!");
    }

    public void onUnavailable() {//網(wǎng)絡(luò)缺失network時(shí)調(diào)用
        throw new RuntimeException("Stub!");
    }

    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {//網(wǎng)絡(luò)功能發(fā)生改變時(shí)調(diào)用
        throw new RuntimeException("Stub!");
    }

   //網(wǎng)絡(luò)連接屬性發(fā)生改變時(shí)調(diào)用
    public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
        throw new RuntimeException("Stub!");
    }
}

NetworkCallback的監(jiān)聽有兩種方法:

  • registerDefaultNetworkCallback(NetworkCallback callback) //Android API 26時(shí)加入

  • registerNetworkCallback(NetworkRequest request,NetworkCallback callback) //Android API 21時(shí)加入

Android 官方建議API 28及以上通過NetworkCallback的方式來監(jiān)聽網(wǎng)絡(luò)狀態(tài)的變化

其他功能考慮

接收到消息變化了唐片,接下來我們需要實(shí)現(xiàn)將變化的狀態(tài)消息傳遞到使用的地方,這里就用到消息分發(fā)通信的機(jī)制了茧球,我們有兩個(gè)方案供選擇:

  • 通過接口

定義一個(gè)接口抢埋,每一個(gè)是用到的地方實(shí)現(xiàn)接口對象钉汗,并將該對象注冊保存起來,在網(wǎng)絡(luò)狀態(tài)變化時(shí)調(diào)用即可。

  • 通過EventBus那樣的消息分發(fā)機(jī)制

像EventBus那樣酒来,通過消息分發(fā)機(jī)制,通過注解的標(biāo)注伟墙,收集起需要接受狀態(tài)變化的方法滴铅,在網(wǎng)絡(luò)狀態(tài)變化時(shí)通過反射調(diào)用執(zhí)行汉匙。

網(wǎng)絡(luò)狀態(tài)有多個(gè),可能在某些場景下戏自,我們只需要關(guān)注切換到某一個(gè)狀態(tài)的情況伤锚,以及對于代碼書寫和耦合性考慮屯援,這里采用第二種方案。

代碼實(shí)現(xiàn)

根據(jù)上面的分析弯淘,我們創(chuàng)建一個(gè)Android lib的module之后耳胎,有以下幾個(gè)類元素需要寫:

網(wǎng)絡(luò)狀態(tài)枚舉

網(wǎng)絡(luò)狀態(tài)簡單來說惕它,可分為沒網(wǎng)情況淹魄、Wi-Fi情況、移動(dòng)蜂窩GPRS兆蕉,詳細(xì)分類的話虎韵,當(dāng)然缸废,詳細(xì)分的話還可以分2G、3G测萎、Wi-Fi沒網(wǎng)情況,我們先知考慮簡單的情況:

package com.anonyper.networkmonitor.bean;

/**
 * 網(wǎng)絡(luò)狀態(tài)枚舉
 * AnnotationApplication
 * Created by anonyper on 2019/6/10.
 */
public enum NetWorkState {
    WIFI,//Wi-Fi網(wǎng)絡(luò)
    GPRS,//移動(dòng)蜂窩網(wǎng)絡(luò)
    NONE//沒有網(wǎng)絡(luò)

}

標(biāo)注注解

該注解是運(yùn)行時(shí)份乒,標(biāo)注在方法上的:

@Retention(RetentionPolicy.RUNTIME)//運(yùn)行時(shí)注解
@Target(ElementType.METHOD)//標(biāo)記在方法上
public @interface NetWorkMonitor {
    //監(jiān)聽的網(wǎng)絡(luò)狀態(tài)變化 默認(rèn)全部監(jiān)聽并提示
    NetWorkState[] monitorFilter() default {NetWorkState.GPRS, NetWorkState.WIFI, NetWorkState.NONE};
}

存儲需要運(yùn)行方法的對象

我們要收集起需要接受網(wǎng)絡(luò)狀態(tài)變化的方法對象或辖,通過反射的方式來調(diào)用執(zhí)行孝凌,和我們前面講過的運(yùn)行時(shí)注解一樣月腋,我們定義一個(gè)NetWorkStateReceiverMethod對象榆骚,里面包含:

  • 該方法所屬的對象
  • 該方法的Method對象
  • 該方法需要監(jiān)聽的網(wǎng)絡(luò)狀態(tài)變化類型妓肢,即上面注解的屬性值:monitorFilter

這個(gè)里面我們沒有寫出方法需要的執(zhí)行的參數(shù),是因?yàn)楸O(jiān)聽網(wǎng)絡(luò)狀態(tài)變化接受的方法里面的參數(shù)有且僅有一個(gè)纲缓,就是當(dāng)前的網(wǎng)絡(luò)狀態(tài)祝高,所以我們不需要保存污筷,同時(shí)也可以根據(jù)參數(shù)類型來過濾不必要的方法。

package com.anonyper.networkmonitor.bean;

import java.lang.reflect.Method;

/**
 * 保存接受狀態(tài)變化的方法對象
 * AnnotationApplication
 * Created by anonyper on 2019/6/10.
 */
public class NetWorkStateReceiverMethod {
    /**
     * 網(wǎng)絡(luò)改變執(zhí)行的方法
     */
    Method method;
    /**
     * 網(wǎng)絡(luò)改變執(zhí)行的方法所屬的類
     */
    Object object;
    /**
     * 監(jiān)聽的網(wǎng)絡(luò)改變類型
     */
    NetWorkState[] netWorkState = {NetWorkState.GPRS, NetWorkState.WIFI, NetWorkState.NONE};

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }

    public NetWorkState[] getNetWorkState() {
        return netWorkState;
    }

    public void setNetWorkState(NetWorkState[] netWorkState) {
        this.netWorkState = netWorkState;
    }
}

管理類

對外提供的統(tǒng)一的入口陆蟆,所以我們這個(gè)管理類需要有以下幾點(diǎn)功能:

  • 全局單一
  • 接受傳入Application(注冊廣播叠殷,監(jiān)聽網(wǎng)絡(luò)狀態(tài)用)
  • 提供注冊和反注冊入口
  • 處理好不同版本網(wǎng)絡(luò)監(jiān)聽的方法兼容
  • 存儲所有需要接受網(wǎng)絡(luò)狀態(tài)變化消息的方法
  • 網(wǎng)絡(luò)狀態(tài)變化時(shí)溪猿,根據(jù)狀態(tài)類型纫塌,通知對應(yīng)的方法

源碼如下:

package com.anonyper.networkmonitor;

import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Build;

import com.anonyper.networkmonitor.annotation.NetWorkMonitor;
import com.anonyper.networkmonitor.bean.NetWorkState;
import com.anonyper.networkmonitor.bean.NetWorkStateReceiverMethod;
import com.anonyper.utillibrary.NetStateUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * AnnotationApplication
 * Created by anonyper on 2019/6/10.
 */
public class NetWorkMonitorManager {
    public static final String TAG = "NetWorkMonitor >>> : ";
    private static NetWorkMonitorManager ourInstance;
    private Application application;

    public static NetWorkMonitorManager getInstance() {
        synchronized (NetWorkMonitorManager.class) {
            if (ourInstance == null) {
                ourInstance = new NetWorkMonitorManager();
            }
        }
        return ourInstance;
    }

    /**
     * 存儲接受網(wǎng)絡(luò)狀態(tài)變化消息的方法的map
     */
    Map<Object, NetWorkStateReceiverMethod> netWorkStateChangedMethodMap = new HashMap<>();

    private NetWorkMonitorManager() {
    }

    /**
     * 初始化 傳入application
     *
     * @param application
     */
    public void init(Application application) {
        if (application == null) {
            throw new NullPointerException("application can not be null");
        }
        this.application = application;
        initMonitor();
    }

    /**
     * 初始化網(wǎng)絡(luò)監(jiān)聽 根據(jù)不同版本做不同的處理
     */
    private void initMonitor() {
        ConnectivityManager connectivityManager = (ConnectivityManager) this.application.getSystemService(Context.CONNECTIVITY_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//API 大于26時(shí)
            connectivityManager.registerDefaultNetworkCallback(networkCallback);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//API 大于21時(shí)
            NetworkRequest.Builder builder = new NetworkRequest.Builder();
            NetworkRequest request = builder.build();
            connectivityManager.registerNetworkCallback(request, networkCallback);
        } else {//低版本
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(ANDROID_NET_CHANGE_ACTION);
            this.application.registerReceiver(receiver, intentFilter);
        }
    }

    /**
     * 反注冊廣播
     */
    private void onDestroy() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            this.application.unregisterReceiver(receiver);
        }
    }

    /**
     * 注入
     * @param object
     */
    public void register(Object object) {
        if (this.application == null) {
            throw new NullPointerException("application can not be null,please call the method init(Application application) to add the Application");
        }
        if (object != null) {
            NetWorkStateReceiverMethod netWorkStateReceiverMethod = findMethod(object);
            if (netWorkStateReceiverMethod != null) {
                netWorkStateChangedMethodMap.put(object, netWorkStateReceiverMethod);
            }
        }
    }

    /**
     * 刪除
     *
     * @param object
     */


    public void unregister(Object object) {
        if (object != null && netWorkStateChangedMethodMap != null) {
            netWorkStateChangedMethodMap.remove(object);
        }
    }

    /**
     * 網(wǎng)絡(luò)狀態(tài)發(fā)生變化,需要去通知更改
     * @param netWorkState
     */
    private void postNetState(NetWorkState netWorkState) {
        Set<Object> set = netWorkStateChangedMethodMap.keySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object object = iterator.next();
            NetWorkStateReceiverMethod netWorkStateReceiverMethod = netWorkStateChangedMethodMap.get(object);
            invokeMethod(netWorkStateReceiverMethod, netWorkState);

        }
    }

    /**
     * 具體執(zhí)行方法
     *
     * @param netWorkStateReceiverMethod
     * @param netWorkState
     */
    private void invokeMethod(NetWorkStateReceiverMethod netWorkStateReceiverMethod, NetWorkState netWorkState) {
        if (netWorkStateReceiverMethod != null) {
            try {
                NetWorkState[] netWorkStates = netWorkStateReceiverMethod.getNetWorkState();
                for (NetWorkState myState : netWorkStates) {
                    if (myState == netWorkState) {
                        netWorkStateReceiverMethod.getMethod().invoke(netWorkStateReceiverMethod.getObject(), netWorkState);
                        return;
                    }
                }

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 找到對應(yīng)的方法
     *
     * @param object
     * @return
     */
    private NetWorkStateReceiverMethod findMethod(Object object) {
        NetWorkStateReceiverMethod targetMethod = null;
        if (object != null) {
            Class myClass = object.getClass();
            //獲取所有的方法
            Method[] methods = myClass.getDeclaredMethods();
            for (Method method : methods) {
                //如果參數(shù)個(gè)數(shù)不是1個(gè) 直接忽略
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    if (method.getParameterCount() != 1) {
                        continue;
                    }
                }
                //獲取方法參數(shù)
                Class[] parameters = method.getParameterTypes();
                if (parameters == null || parameters.length != 1) {
                    continue;
                }
                //參數(shù)的類型需要時(shí)NetWorkState類型
                if (parameters[0].getName().equals(NetWorkState.class.getName())) {
                    //是NetWorkState類型的參數(shù)
                    NetWorkMonitor netWorkMonitor = method.getAnnotation(NetWorkMonitor.class);
                    targetMethod = new NetWorkStateReceiverMethod();
                    //如果沒有添加注解,默認(rèn)就是所有網(wǎng)絡(luò)狀態(tài)變化都通知
                    if (netWorkMonitor != null) {
                        NetWorkState[] netWorkStates = netWorkMonitor.monitorFilter();
                        targetMethod.setNetWorkState(netWorkStates);
                    }
                    targetMethod.setMethod(method);
                    targetMethod.setObject(object);
                    //只添加第一個(gè)符合的方法
                    return targetMethod;
                }
            }
        }
        return targetMethod;
    }


    private static final String ANDROID_NET_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
    BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equalsIgnoreCase(ANDROID_NET_CHANGE_ACTION)) {
                //網(wǎng)絡(luò)發(fā)生變化 沒有網(wǎng)絡(luò)-0:WIFI網(wǎng)絡(luò)1:4G網(wǎng)絡(luò)-4:3G網(wǎng)絡(luò)-3:2G網(wǎng)絡(luò)-2
                int netType = NetStateUtils.getAPNType(context);
                NetWorkState netWorkState = NetWorkState.NONE;
                switch (netType) {
                    case 0://None
                        netWorkState = NetWorkState.NONE;
                        break;
                    case 1://Wifi
                        netWorkState = NetWorkState.WIFI;
                        break;
                    default://GPRS
                        netWorkState = NetWorkState.GPRS;
                        break;
                }
                postNetState(netWorkState);
            }
        }
    };


    ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
        /**
         * 網(wǎng)絡(luò)可用的回調(diào)連接成功
         */
        @Override
        public void onAvailable(Network network) {
            super.onAvailable(network);
            int netType = NetStateUtils.getAPNType(NetWorkMonitorManager.this.application);
            NetWorkState netWorkState = NetWorkState.NONE;
            switch (netType) {
                case 0://None
                    netWorkState = NetWorkState.NONE;
                    break;
                case 1://Wifi
                    netWorkState = NetWorkState.WIFI;
                    break;
                default://GPRS
                    netWorkState = NetWorkState.GPRS;
                    break;
            }
            postNetState(netWorkState);
        }

        /**
         * 網(wǎng)絡(luò)不可用時(shí)調(diào)用和onAvailable成對出現(xiàn)
         */
        @Override
        public void onLost(Network network) {
            super.onLost(network);
            postNetState(NetWorkState.NONE);
        }

        /**
         * 在網(wǎng)絡(luò)連接正常的情況下,丟失數(shù)據(jù)會有回調(diào) 即將斷開時(shí)
         */
        @Override
        public void onLosing(Network network, int maxMsToLive) {
            super.onLosing(network, maxMsToLive);
        }

        /**
         * 網(wǎng)絡(luò)功能更改 滿足需求時(shí)調(diào)用
         * @param network
         * @param networkCapabilities
         */
        @Override
        public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
            super.onCapabilitiesChanged(network, networkCapabilities);
        }

        /**
         * 網(wǎng)絡(luò)連接屬性修改時(shí)調(diào)用
         * @param network
         * @param linkProperties
         */
        @Override
        public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
            super.onLinkPropertiesChanged(network, linkProperties);
        }

        /**
         * 網(wǎng)絡(luò)缺失network時(shí)調(diào)用
         */
        @Override
        public void onUnavailable() {
            super.onUnavailable();
        }
    };

}

里面引用的一個(gè)NetStateUtils類是網(wǎng)上找到關(guān)于網(wǎng)絡(luò)的工具類:

/**
 * 獲取當(dāng)前的網(wǎng)絡(luò)狀態(tài) :沒有網(wǎng)絡(luò)-0:WIFI網(wǎng)絡(luò)1:4G網(wǎng)絡(luò)-4:3G網(wǎng)絡(luò)-3:2G網(wǎng)絡(luò)-2
 * 自定義
 *
 * @param context
 * @return
 */
public static int getAPNType(Context context) {
    //結(jié)果返回值
    int netType = 0;
    //獲取手機(jī)所有連接管理對象
    ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context
            .CONNECTIVITY_SERVICE);
    //獲取NetworkInfo對象
    NetworkInfo networkInfo = manager.getActiveNetworkInfo();
    //NetworkInfo對象為空 則代表沒有網(wǎng)絡(luò)
    if (networkInfo == null) {
        return netType;
    }
    //否則 NetworkInfo對象不為空 則獲取該networkInfo的類型
    int nType = networkInfo.getType();
    if (nType == ConnectivityManager.TYPE_WIFI) {
        //WIFI
        netType = 1;
    } else if (nType == ConnectivityManager.TYPE_MOBILE) {
        int nSubType = networkInfo.getSubtype();
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService
                (Context.TELEPHONY_SERVICE);
        //3G   聯(lián)通的3G為UMTS或HSDPA 電信的3G為EVDO
        if (nSubType == TelephonyManager.NETWORK_TYPE_LTE
                && !telephonyManager.isNetworkRoaming()) {
            netType = 4;
        } else if (nSubType == TelephonyManager.NETWORK_TYPE_UMTS
                || nSubType == TelephonyManager.NETWORK_TYPE_HSDPA
                || nSubType == TelephonyManager.NETWORK_TYPE_EVDO_0
                && !telephonyManager.isNetworkRoaming()) {
            netType = 3;
            //2G 移動(dòng)和聯(lián)通的2G為GPRS或EGDE,電信的2G為CDMA
        } else if (nSubType == TelephonyManager.NETWORK_TYPE_GPRS
                || nSubType == TelephonyManager.NETWORK_TYPE_EDGE
                || nSubType == TelephonyManager.NETWORK_TYPE_CDMA
                && !telephonyManager.isNetworkRoaming()) {
            netType = 2;
        } else {
            netType = 2;
        }
    }
    return netType;
}

具體使用

在app的build.gradle中引入上述lib庫酵使,在app的Application中添加:

public class AnonyperApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        NetWorkMonitorManager.getInstance().init(this);
    }


}

然后在使用的地方:

@Override
protected void onStart() {
    super.onStart();
    NetWorkMonitorManager.getInstance().register(this);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    NetWorkMonitorManager.getInstance().unregister(this);
}
//不加注解默認(rèn)監(jiān)聽所有的狀態(tài)口渔,方法名隨意穿撮,只需要參數(shù)是一個(gè)NetWorkState即可
//@NetWorkMonitor(monitorFilter = {NetWorkState.GPRS})//只接受網(wǎng)絡(luò)狀態(tài)變?yōu)镚PRS類型的消息
public void onNetWorkStateChange(NetWorkState netWorkState) {
    Log.i("TAG", "onNetWorkStateChange >>> :" + netWorkState.name());
}

當(dāng)然悦穿,需要在manifest中添加網(wǎng)絡(luò)狀態(tài)變化監(jiān)聽的權(quán)限:

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

關(guān)掉WIfi后log:

2019-06-11 19:45:34.825 13778-13809/com.anonyper.annotationapplication I/Anonyper >>>: onNetWorkStateChange >>> :NONE
2019-06-11 19:45:35.525 13778-13809/com.anonyper.annotationapplication I/Anonyper >>>: onNetWorkStateChange >>> :GPRS

以上咧党,我們就完成了一個(gè)網(wǎng)絡(luò)狀態(tài)變化監(jiān)聽的lib庫。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末深员,一起剝皮案震驚了整個(gè)濱河市蛙埂,隨后出現(xiàn)的幾起案子绣的,更是在濱河造成了極大的恐慌欲账,老刑警劉巖芭概,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罢洲,死亡現(xiàn)場離奇詭異,居然都是意外死亡惹苗,警方通過查閱死者的電腦和手機(jī)桩蓉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洽瞬,“玉大人片任,你說我怎么就攤上這事对供。” “怎么了产场?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵京景,是天一觀的道長骗奖。 經(jīng)常有香客問我确徙,道長,這世上最難降的妖魔是什么执桌? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任鄙皇,我火速辦了婚禮,結(jié)果婚禮上仰挣,老公的妹妹穿的比我還像新娘伴逸。我一直安慰自己,他們只是感情好膘壶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布错蝴。 她就那樣靜靜地躺著洲愤,像睡著了一般顷锰。 火紅的嫁衣襯著肌膚如雪躺率。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音薪丁,去河邊找鬼严嗜。 笑死漫玄,一個(gè)胖子當(dāng)著我的面吹牛睦优,可吹牛的內(nèi)容都是我干的汗盘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼菱阵,長吁一口氣:“原來是場噩夢啊……” “哼段化!你這毒婦竟也來了喉前?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤胰蝠,失蹤者是張志新(化名)和其女友劉穎茸塞,沒想到半個(gè)月后噪窘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體倔监,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弯院。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片听绳。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鼠证,靈堂內(nèi)的尸體忽然破棺而出量九,到底是詐尸還是另有隱情类浪,我是刑警寧澤费就,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站眠蚂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜迈套,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贵白。 院中可真熱鬧禁荒,春花似錦呛伴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽固惯。三九已至葬毫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烂斋,已是汗流浹背汛骂。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝶念,地道東北人媒殉。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓廷蓉,卻偏偏與公主長得像苦酱,于是被迫代替她去往敵國和親疫萤。 傳聞我的和親對象是個(gè)殘疾皇子敢伸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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