Android 工具類匯總

文/程序員男神

前言

今早起的還算早床绪,看了一場NBA,一想到工作還沒給答復(fù)客情,心里就有點著急了。中午定了份外賣癞己,心酸的吃著土豆絲膀斋,好心酸,這時女朋友發(fā)來微信痹雅,說今晚我們?nèi)タ次也皇桥私鹕彴裳龅#∵€記得在北京的時候這電影就一直在宣傳,聽到這個消息绩社,心情好了那么點摔蓝。把昨天整理的代碼寫篇文章平復(fù)一下糟糕的心情。今天帶來了基本每個項目中都會使用的工具類愉耙。前方代碼較多......


aj

工具類

1项鬼、日志工具類

package com.example.dj.testdemo.Utils;

import com.example.dj.testdemo.BuildConfig;

/**
 * 描述:日志工具類
 * <p>
 *     這個工具類主要在三處地方做了封裝。
 *     第一是加入BuildConfig.DEBUG判斷劲阎,這樣發(fā)布時就不會打印log绘盟,如果不了解BuildConfig,可以參考這篇文章Android BuildConfig.DEBUG的妙用
 *     第二是log工具類都常見的悯仙,預(yù)設(shè)置TAG龄毡,這樣不用每次都傳兩個參數(shù)
 *     第三,通過StackTraceElement獲取當(dāng)前打印日志的類名和方法名锡垄,這個用來代替我們平時手寫的TAG值沦零。StackTrace用棧的形式保存了方法的調(diào)用信息。
 * Created by dj on 2016/11/16 0016.
 */
public class MyLogger {

    protected static final String TAG = "DSBBM";

    public MyLogger() {
    }

    /**
     * Send a VERBOSE log message.
     *
     * @param msg The message you would like logged.
     */
    public static void v(String msg) {
        if (BuildConfig.DEBUG)
            android.util.Log.v(TAG, buildMessage(msg));
    }

    /**
     * Send a VERBOSE log message and log the exception.
     *
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */
    public static void v(String msg, Throwable tr) {
        if (BuildConfig.DEBUG)
            android.util.Log.v(TAG, buildMessage(msg), tr);
    }

    /**
     * Send a DEBUG log message.
     *
     * @param msg
     */
    public static void d(String msg) {
        if (BuildConfig.DEBUG)
            android.util.Log.d(TAG, buildMessage(msg));
    }

    /**
     * Send a DEBUG log message and log the exception.
     *
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */
    public static void d(String msg, Throwable tr) {
        if (BuildConfig.DEBUG)
            android.util.Log.d(TAG, buildMessage(msg), tr);
    }

    /**
     * Send an INFO log message.
     *
     * @param msg The message you would like logged.
     */
    public static void i(String msg) {
        if (BuildConfig.DEBUG)
            android.util.Log.i(TAG, buildMessage(msg));
    }

    /**
     * Send a INFO log message and log the exception.
     *
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */
    public static void i(String msg, Throwable tr) {
        if (BuildConfig.DEBUG)
            android.util.Log.i(TAG, buildMessage(msg), tr);
    }

    /**
     * Send an ERROR log message.
     *
     * @param msg The message you would like logged.
     */
    public static void e(String msg) {
        if (BuildConfig.DEBUG)
            android.util.Log.e(TAG, buildMessage(msg));
    }

    /**
     * Send an ERROR log message and log the exception.
     *
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */
    public static void e(String msg, Throwable tr) {
        if (BuildConfig.DEBUG)
            android.util.Log.e(TAG, buildMessage(msg), tr);
    }

    /**
     * Send a WARN log message
     *
     * @param msg The message you would like logged.
     */
    public static void w(String msg) {
        if (BuildConfig.DEBUG)
            android.util.Log.w(TAG, buildMessage(msg));
    }

    /**
     * Send a WARN log message and log the exception.
     *
     * @param msg The message you would like logged.
     * @param thr An exception to log
     */
    public static void w(String msg, Throwable thr) {
        if (BuildConfig.DEBUG)
            android.util.Log.w(TAG, buildMessage(msg), thr);
    }

    /**
     * Send an empty WARN log message and log the exception.
     *
     * @param thr An exception to log
     */
    public static void w(Throwable thr) {
        if (BuildConfig.DEBUG)
            android.util.Log.w(TAG, buildMessage(""), thr);
    }

    protected static String buildMessage(String msg) {

        //通過StackTraceElement獲取當(dāng)前打印日志的類名和方法名货岭,這個用來代替我們平時手寫的TAG值路操。
        // StackTrace用棧的形式保存了方法的調(diào)用信息
        StackTraceElement caller = new Throwable().fillInStackTrace().getStackTrace()[2];

        return new StringBuilder().append(caller.getClassName()).append(".").append(caller.getMethodName()).append("(): ").append(msg).toString();
    }
}

打印格式:I/DSBBM: com.example.dj.testdemo.MainActivity.onClick(): msg

這個工具類主要在三處地方做了封裝疾渴。
第一是加入BuildConfig.DEBUG判斷,這樣發(fā)布時就不會打印log屯仗,如果不了解BuildConfig搞坝,可以參考這篇文章Android BuildConfig.DEBUG的妙用
第二是log工具類都常見的,預(yù)設(shè)置TAG魁袜,這樣不用每次都傳兩個參數(shù)
第三是通過StackTraceElement獲取當(dāng)前打印日志的類名和方法名桩撮,這個用來代替我們平時手寫的TAG值。StackTrace用棧的形式保存了方法的調(diào)用信息峰弹。對StackTrace不了解的同學(xué)可以參考這篇文章StackTrace簡述以及StackTraceElement使用實例

2店量、Toast統(tǒng)一管理工具類

package com.example.dj.testdemo.Utils;

import android.content.Context;
import android.view.Gravity;
import android.widget.Toast;

/**
 * 描述:統(tǒng)一管理類
 * <p>
 * Created by dj on 2016/11/17 0017.
 */

public class MyToast {

    private MyToast() {
        //不能被實例化
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    public static boolean isShow = true;

    /**
     * 屏幕中間位置顯示短時間Toast
     *
     * @param context
     * @param msg
     */
    public static void ToastShortCenter(Context context, String msg) {
        if (isShow) {
            if (context != null) {
                Toast toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();
            }
        }

    }

    /**
     * 屏幕中心位置長時間顯示Toast
     *
     * @param context
     * @param message
     */
    public static void ToastLongCenter(Context context, String message) {
        if (isShow) {
            if (context != null) {
                Toast toast = Toast.makeText(context, message, Toast.LENGTH_LONG);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();
            }
        }
    }
    
    /**
     * 自定義顯示Toast時間
     *
     * @param context
     * @param message
     * @param duration
     */
    public static void ToastShow(Context context, String message, int duration) {
        if (isShow)
            Toast.makeText(context, message, duration).show();
    }
}

非常簡單的一個封裝類,短Toast鞠呈、長Toast融师、自定義Toast的實現(xiàn)。

3蚁吝、SharedPreferences封裝工具類

package com.example.dj.testdemo.Utils;

import android.content.Context;
import android.content.SharedPreferences;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 描述:SharedPreferences封裝類
 * <p>
 * Created by dj on 2016/11/17 0017.
 */

public class SPUtils {

    /**
     * 保存在手機里面的文件名
     */
    public static final String FILE_NAME = "share_data";

    /**
     * 保存數(shù)據(jù)的方法诬滩,我們需要拿到保存數(shù)據(jù)的具體類型,然后根據(jù)類型調(diào)用不同的保存方法
     *
     * @param context
     * @param key
     * @param object
     */
    public static void put(Context context, String key, Object object) {

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        if (object instanceof String) {
            editor.putString(key, (String) object);
        } else if (object instanceof Integer) {
            editor.putInt(key, (Integer) object);
        } else if (object instanceof Boolean) {
            editor.putBoolean(key, (Boolean) object);
        } else if (object instanceof Float) {
            editor.putFloat(key, (Float) object);
        } else if (object instanceof Long) {
            editor.putLong(key, (Long) object);
        } else {
            editor.putString(key, object.toString());
        }

        /**
         * commit操作使用了SharedPreferencesCompat.apply進行了替代灭将,目的是盡可能的使用apply代替commit
         * 因為commit方法是同步的疼鸟,并且我們很多時候的commit操作都是UI線程中,畢竟是IO操作庙曙,盡可能異步空镜;
         */
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 得到保存數(shù)據(jù)的方法,我們根據(jù)默認值得到保存的數(shù)據(jù)的具體類型捌朴,然后調(diào)用相對于的方法獲取值
     *
     * @param context
     * @param key
     * @param defaultObject
     * @return
     */
    public static Object get(Context context, String key, Object defaultObject) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);

        if (defaultObject instanceof String) {
            return sp.getString(key, (String) defaultObject);
        } else if (defaultObject instanceof Integer) {
            return sp.getInt(key, (Integer) defaultObject);
        } else if (defaultObject instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultObject);
        } else if (defaultObject instanceof Float) {
            return sp.getFloat(key, (Float) defaultObject);
        } else if (defaultObject instanceof Long) {
            return sp.getLong(key, (Long) defaultObject);
        }

        return null;
    }

    /**
     * 移除某個key值已經(jīng)對應(yīng)的值
     *
     * @param context
     * @param key
     */
    public static void remove(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 清除所有數(shù)據(jù)
     *
     * @param context
     */
    public static void clear(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 查詢某個key是否已經(jīng)存在
     *
     * @param context
     * @param key
     * @return
     */
    public static boolean contains(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        return sp.contains(key);
    }

    /**
     * 返回所有的鍵值對
     *
     * @param context
     * @return
     */
    public static Map<String, ?> getAll(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        return sp.getAll();
    }

    /**
     * 創(chuàng)建一個解決SharedPreferencesCompat.apply方法的一個兼容類
     *
     * @author dj
     */
    private static class SharedPreferencesCompat {
        private static final Method sApplyMethod = findApplyMethod();

        /**
         * 反射查找apply的方法
         *
         * @return
         */
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static Method findApplyMethod() {
            try {
                Class clz = SharedPreferences.Editor.class;
                return clz.getMethod("apply");
            } catch (NoSuchMethodException e) {
            }

            return null;
        }

        /**
         * 如果找到則使用apply執(zhí)行吴攒,否則使用commit
         *
         * @param editor
         */
        public static void apply(SharedPreferences.Editor editor) {
            try {
                if (sApplyMethod != null) {
                    sApplyMethod.invoke(editor);
                    return;
                }
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            editor.commit();
        }
    }
}

對SharedPreference的使用做了建議的封裝,對外公布出put砂蔽,get洼怔,remove,clear等等方法左驾;
注意一點镣隶,里面所有的commit操作使用了SharedPreferencesCompat.apply進行了替代,目的是盡可能的使用apply代替commit诡右;
首先說下為什么安岂,因為commit方法是同步的,并且我們很多時候的commit操作都是UI線程中帆吻,畢竟是IO操作域那,盡可能異步;
所以我們使用apply進行替代猜煮,apply異步的進行寫入次员;
但是apply相當(dāng)于commit來說是new API呢败许,為了更好的兼容,我們做了適配淑蔚;

4市殷、單位轉(zhuǎn)換工具類

package com.example.dj.testdemo.Utils;

import android.content.Context;
import android.util.TypedValue;

/**
 * 描述:單位轉(zhuǎn)換輔助類
 * <p>
 * Created by dj on 2016/11/17 0017.
 */

public class DensityUtils {

    private DensityUtils() {
        //不能被實例化
        new UnsupportedOperationException("cannot be instantiated");
    }

    /**
     * dp轉(zhuǎn)px
     *
     * @param context
     * @param dpVal
     * @return
     */
    public static int dp2px(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, context.getResources().getDisplayMetrics());
    }

    /**
     * sp轉(zhuǎn)px
     *
     * @param context
     * @param spVal
     * @return
     */
    public static int sp2px(Context context, float spVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                spVal, context.getResources().getDisplayMetrics());
    }

    /**
     * px轉(zhuǎn)dp
     *
     * @param context
     * @param pxVal
     * @return
     */
    public static float px2dp(Context context, float pxVal) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (pxVal / scale);
    }

    /**
     * px轉(zhuǎn)sp
     *
     * @param context
     * @param pxVal
     * @return
     */
    public static float px2sp(Context context, float pxVal) {
        return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
    }
}

5、SCard相關(guān)工具類

package com.example.dj.testdemo.Utils;

import android.os.Environment;
import android.os.StatFs;

import java.io.File;

/**
 * 描述:SDCard輔助類
 * <p>
 * Created by dj on 2016/11/17 0017.
 */

public class SDCardUtils {

    private SDCardUtils() {
        /* cannot be instantiated */
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    /**
     * 判斷SDCard是否可用
     *
     * @return
     */
    public static boolean isSDCardEnable() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    }

    /**
     * 獲取SD卡路徑
     *
     * @return
     */
    public static String getSDCardPath() {
        return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
    }

    /**
     * 獲取SD卡的剩余容量 單位byte
     *
     * @return
     */
    public static long getSDCardAllSize() {
        if (isSDCardEnable()) {
            StatFs stat = new StatFs(getSDCardPath());
            // 獲取空閑的數(shù)據(jù)塊的數(shù)量
            long availableBlocks = (long) stat.getAvailableBlocks() - 4;
            // 獲取單個數(shù)據(jù)塊的大惺丁(byte)
            long freeBlocks = stat.getAvailableBlocks();
            return freeBlocks * availableBlocks;
        }
        return 0;
    }

    /**
     * 獲取指定路徑所在空間的剩余可用容量字節(jié)數(shù)被丧,單位byte
     *
     * @param filePath
     * @return 容量字節(jié) SDCard可用空間盟戏,內(nèi)部存儲可用空間
     */
    public static long getFreeBytes(String filePath) {
        // 如果是sd卡的下的路徑绪妹,則獲取sd卡可用容量
        if (filePath.startsWith(getSDCardPath())) {
            filePath = getSDCardPath();
        } else {// 如果是內(nèi)部存儲的路徑,則獲取內(nèi)存存儲的可用容量
            filePath = Environment.getDataDirectory().getAbsolutePath();
        }
        StatFs stat = new StatFs(filePath);
        long availableBlocks = (long) stat.getAvailableBlocks() - 4;
        return stat.getBlockSize() * availableBlocks;
    }

    /**
     * 獲取系統(tǒng)存儲路徑
     *
     * @return
     */
    public static String getRootDirectoryPath() {
        return Environment.getRootDirectory().getAbsolutePath();
    }
}

6柿究、屏幕相關(guān)工具類

package com.example.dj.testdemo.Utils;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;

/**
 * 描述:屏幕相關(guān)輔助類
 * <p>
 * Created by dj on 2016/11/17 0017.
 */

public class ScreenUtils {

    private ScreenUtils() {
        /* cannot be instantiated */
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    /**
     * 獲得屏幕高度
     *
     * @param context
     * @return
     */
    public static int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    /**
     * 獲得屏幕寬度
     *
     * @param context
     * @return
     */
    public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }

    /**
     * 獲得狀態(tài)欄的高度
     *
     * @param context
     * @return
     */
    public static int getStatusHeight(Context context) {

        int statusHeight = -1;
        try {
            Class<?> clazz = Class.forName("com.android.internal.R$dimen");
            Object object = clazz.newInstance();
            int height = Integer.parseInt(clazz.getField("status_bar_height")
                    .get(object).toString());
            statusHeight = context.getResources().getDimensionPixelSize(height);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return statusHeight;
    }

    /**
     * 獲取當(dāng)前屏幕截圖邮旷,包含狀態(tài)欄
     *
     * @param activity
     * @return
     */
    public static Bitmap snapShotWithStatusBar(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        int width = getScreenWidth(activity);
        int height = getScreenHeight(activity);
        Bitmap bp = null;
        bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
        view.destroyDrawingCache();
        return bp;

    }

    /**
     * 獲取當(dāng)前屏幕截圖,不包含狀態(tài)欄
     *
     * @param activity
     * @return
     */
    public static Bitmap snapShotWithoutStatusBar(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        Rect frame = new Rect();
      activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;
        int width = getScreenWidth(activity);
        int height = getScreenHeight(activity);
        Bitmap bp = null;
        bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight);
        view.destroyDrawingCache();
        return bp;
    }
}

7蝇摸、版本檢測工具類

package com.example.dj.testdemo.Utils;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

/**
 * 基本功能:app版本工具
 * <p>
 * Created by dj on 2016/11/17 0017.
 */

public class VersionUtil {

    /**
     * 獲取應(yīng)用程序名稱
     * @param context
     * @return
     */
    public static String getAppName(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            int labelRes = packageInfo.applicationInfo.labelRes;
            return context.getResources().getString(labelRes);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 獲取版本號
     *
     * @param context
     * @return 當(dāng)前應(yīng)用的版本號
     */
    public static String getVersion(Context context) {
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
            String version = info.versionName;
            return version;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 版本比較
     *
     * @param nowVersion    app版本
     * @param serverVersion 服務(wù)器版本
     * @return
     */
    public static boolean compareVersion(String nowVersion, String serverVersion) {
        if (nowVersion != null && serverVersion != null) {
            String[] nowVersions = nowVersion.split("\\.");
            String[] serverVersions = serverVersion.split("\\.");
            if (nowVersion != null && serverVersion != null && nowVersions.length > 1 && serverVersions.length > 1) {
                int nowVersionFirst = Integer.parseInt(nowVersions[0]);
                int serverVersionFirst = Integer.parseInt(serverVersions[0]);
                int nowVersionSecond = Integer.parseInt(nowVersions[1]);
                int serverVersionSecond = Integer.parseInt(serverVersions[1]);
                if (nowVersionFirst < serverVersionFirst) {
                    return true;
                } else if (nowVersionFirst == serverVersionFirst && nowVersionSecond < serverVersionSecond) {
                    return true;
                }
            }
        }
        return false;
    }
}

8婶肩、網(wǎng)絡(luò)相關(guān)輔助類

package com.example.dj.testdemo.Utils;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

/**
 * 描述:網(wǎng)絡(luò)輔助類
 * <p>
 * Created by dj on 2016/11/17 0017.
 */
public class NetUtils {

    private NetUtils() {
        /* cannot be instantiated */
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    /**
     * 判斷網(wǎng)絡(luò)是否連接
     *
     * @param context
     * @return
     */
    public static boolean isConnected(Context context) {

        ConnectivityManager connectivity = (ConnectivityManager) context.
                getSystemService(Context.CONNECTIVITY_SERVICE);

        if (null != connectivity) {
            NetworkInfo info = connectivity.getActiveNetworkInfo();
            if (null != info && info.isConnected()) {
                if (info.getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 判斷是否是wifi連接
     */
    public static boolean isWifi(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);

        if (cm == null)
            return false;
        return cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI;

    }

    /**
     * 打開網(wǎng)絡(luò)設(shè)置界面
     */
    public static void openSetting(Activity activity) {
        Intent intent = new Intent("/");
        ComponentName cm = new ComponentName("com.android.settings",
                "com.android.settings.WirelessSettings");
        intent.setComponent(cm);
        intent.setAction("android.intent.action.VIEW");
        activity.startActivityForResult(intent, 0);
    }
}

9、手機信息采集工具類

package com.example.dj.testdemo.Utils;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.SystemClock;
import android.telephony.TelephonyManager;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 基本功能:手機信息采集工具
 * <p>
 * Created by dj on 2016/11/17 0017.
 */

public class MobileUtil {

    /**
     * Print telephone info.
     */
    public static String printMobileInfo(Context context) {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = dateFormat.format(date);
        StringBuilder sb = new StringBuilder();
        sb.append("系統(tǒng)時間:").append(time).append("\n");
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        String IMSI = tm.getSubscriberId();
        //IMSI前面三位460是國家號碼貌夕,其次的兩位是運營商代號律歼,00、02是中國移動啡专,01是聯(lián)通险毁,03是電信。
        String providerName = null;
        if (IMSI != null) {
            if (IMSI.startsWith("46000") || IMSI.startsWith("46002")) {
                providerName = "中國移動";
            } else if (IMSI.startsWith("46001")) {
                providerName = "中國聯(lián)通";
            } else if (IMSI.startsWith("46003")) {
                providerName = "中國電信";
            }
        }
        sb.append(providerName).append("\n").append(getNativePhoneNumber(context)).append("\n網(wǎng)絡(luò)模式:").append(getNetType(context)).append("\nIMSI是:").append(IMSI);
        sb.append("\nDeviceID(IMEI)       :").append(tm.getDeviceId());
        sb.append("\nDeviceSoftwareVersion:").append(tm.getDeviceSoftwareVersion());
        sb.append("\ngetLine1Number       :").append(tm.getLine1Number());
        sb.append("\nNetworkCountryIso    :").append(tm.getNetworkCountryIso());
        sb.append("\nNetworkOperator      :").append(tm.getNetworkOperator());
        sb.append("\nNetworkOperatorName  :").append(tm.getNetworkOperatorName());
        sb.append("\nNetworkType          :").append(tm.getNetworkType());
        sb.append("\nPhoneType            :").append(tm.getPhoneType());
        sb.append("\nSimCountryIso        :").append(tm.getSimCountryIso());
        sb.append("\nSimOperator          :").append(tm.getSimOperator());
        sb.append("\nSimOperatorName      :").append(tm.getSimOperatorName());
        sb.append("\nSimSerialNumber      :").append(tm.getSimSerialNumber());
        sb.append("\ngetSimState          :").append(tm.getSimState());
        sb.append("\nSubscriberId         :").append(tm.getSubscriberId());
        sb.append("\nVoiceMailNumber      :").append(tm.getVoiceMailNumber());

        return sb.toString();
    }


    /**
     * 打印系統(tǒng)信息
     *
     * @return
     */
    public static String printSystemInfo() {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = dateFormat.format(date);
        StringBuilder sb = new StringBuilder();
        sb.append("_______  系統(tǒng)信息  ").append(time).append(" ______________");
        sb.append("\nID                 :").append(Build.ID);
        sb.append("\nBRAND              :").append(Build.BRAND);
        sb.append("\nMODEL              :").append(Build.MODEL);
        sb.append("\nRELEASE            :").append(Build.VERSION.RELEASE);
        sb.append("\nSDK                :").append(Build.VERSION.SDK);

        sb.append("\n_______ OTHER _______");
        sb.append("\nBOARD              :").append(Build.BOARD);
        sb.append("\nPRODUCT            :").append(Build.PRODUCT);
        sb.append("\nDEVICE             :").append(Build.DEVICE);
        sb.append("\nFINGERPRINT        :").append(Build.FINGERPRINT);
        sb.append("\nHOST               :").append(Build.HOST);
        sb.append("\nTAGS               :").append(Build.TAGS);
        sb.append("\nTYPE               :").append(Build.TYPE);
        sb.append("\nTIME               :").append(Build.TIME);
        sb.append("\nINCREMENTAL        :").append(Build.VERSION.INCREMENTAL);

        sb.append("\n_______ CUPCAKE-3 _______");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
            sb.append("\nDISPLAY            :").append(Build.DISPLAY);
        }

        sb.append("\n_______ DONUT-4 _______");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT) {
            sb.append("\nSDK_INT            :").append(Build.VERSION.SDK_INT);
            sb.append("\nMANUFACTURER       :").append(Build.MANUFACTURER);
            sb.append("\nBOOTLOADER         :").append(Build.BOOTLOADER);
            sb.append("\nCPU_ABI            :").append(Build.CPU_ABI);
            sb.append("\nCPU_ABI2           :").append(Build.CPU_ABI2);
            sb.append("\nHARDWARE           :").append(Build.HARDWARE);
            sb.append("\nUNKNOWN            :").append(Build.UNKNOWN);
            sb.append("\nCODENAME           :").append(Build.VERSION.CODENAME);
        }

        sb.append("\n_______ GINGERBREAD-9 _______");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            sb.append("\nSERIAL             :").append(Build.SERIAL);
        }
        return sb.toString();
    }

    /****
     * 獲取網(wǎng)絡(luò)類型
     *
     * @param context
     * @return
     */
    public static String getNetType(Context context) {
        try {
            ConnectivityManager connectMgr = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo info = connectMgr.getActiveNetworkInfo();
            if (info == null) {
                return "";
            }
            if (info.getType() == ConnectivityManager.TYPE_WIFI) {
                return "WIFI";
            } else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
                if (info.getSubtype() == TelephonyManager.NETWORK_TYPE_CDMA) {
                    return "CDMA";
                } else if (info.getSubtype() == TelephonyManager.NETWORK_TYPE_EDGE) {
                    return "EDGE";
                } else if (info.getSubtype() == TelephonyManager.NETWORK_TYPE_EVDO_0) {
                    return "EVDO0";
                } else if (info.getSubtype() == TelephonyManager.NETWORK_TYPE_EVDO_A) {
                    return "EVDOA";
                } else if (info.getSubtype() == TelephonyManager.NETWORK_TYPE_GPRS) {
                    return "GPRS";
                }
                /*
                 * else if(info.getSubtype() ==
                 * TelephonyManager.NETWORK_TYPE_HSDPA){ return "HSDPA"; }else
                 * if(info.getSubtype() == TelephonyManager.NETWORK_TYPE_HSPA){
                 * return "HSPA"; }else if(info.getSubtype() ==
                 * TelephonyManager.NETWORK_TYPE_HSUPA){ return "HSUPA"; }
                 */
                else if (info.getSubtype() == TelephonyManager.NETWORK_TYPE_UMTS) {
                    return "UMTS";
                } else {
                    return "3G";
                }
            } else {
                return "";
            }
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 獲取當(dāng)前設(shè)置的電話號碼
     */
    public static String getNativePhoneNumber(Context context) {
        TelephonyManager telephonyManager = (TelephonyManager) context
                .getSystemService(Context.TELEPHONY_SERVICE);
        String NativePhoneNumber = null;
        NativePhoneNumber = telephonyManager.getLine1Number();
        return String.format("手機號: %s", NativePhoneNumber);
    }

    /**
     * IMSI是國際移動用戶識別碼的簡稱(International Mobile Subscriber Identity)
     * IMSI共有15位们童,其結(jié)構(gòu)如下:
     * MCC+MNC+MIN
     * MCC:Mobile Country Code畔况,移動國家碼,共3位慧库,中國為460;
     * MNC:Mobile NetworkCode跷跪,移動網(wǎng)絡(luò)碼,共2位
     * 在中國齐板,移動的代碼為電00和02吵瞻,聯(lián)通的代碼為01,電信的代碼為03
     * 合起來就是(也是Android手機中APN配置文件中的代碼):
     * 中國移動:46000 46002
     * 中國聯(lián)通:46001
     * 中國電信:46003
     * 舉例甘磨,一個典型的IMSI號碼為460030912121001
     */
    public static String getIMSI(Context context) {
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        String IMSI = telephonyManager.getSubscriberId();
        return IMSI;
    }

    /**
     * IMEI是International Mobile Equipment Identity (國際移動設(shè)備標(biāo)識)的簡稱
     * IMEI由15位數(shù)字組成的”電子串號”听皿,它與每臺手機一一對應(yīng),而且該碼是全世界唯一的
     * 其組成為:
     * 1. 前6位數(shù)(TAC)是”型號核準(zhǔn)號碼”宽档,一般代表機型
     * 2. 接著的2位數(shù)(FAC)是”最后裝配號”尉姨,一般代表產(chǎn)地
     * 3. 之后的6位數(shù)(SNR)是”串號”,一般代表生產(chǎn)順序號
     * 4. 最后1位數(shù)(SP)通常是”0″吗冤,為檢驗碼又厉,目前暫備用
     */
    public static String getIMEI(Context context) {
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        String IMEI = telephonyManager.getDeviceId();
        return IMEI;
    }


    /////_________________ 雙卡雙待系統(tǒng)IMEI和IMSI方案(see more on http://benson37.iteye.com/blog/1923946)

    /**
     * 雙卡雙待神機IMSI九府、IMSI、PhoneType信息
     * <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     */
    public static class TeleInfo {
        public String imsi_1;
        public String imsi_2;
        public String imei_1;
        public String imei_2;
        public int phoneType_1;
        public int phoneType_2;

        @Override
        public String toString() {
            return "TeleInfo{" +
                    "imsi_1='" + imsi_1 + '\'' +
                    ", imsi_2='" + imsi_2 + '\'' +
                    ", imei_1='" + imei_1 + '\'' +
                    ", imei_2='" + imei_2 + '\'' +
                    ", phoneType_1=" + phoneType_1 +
                    ", phoneType_2=" + phoneType_2 +
                    '}';
        }
    }

    /**
     * MTK Phone.
     * <p>
     * 獲取 MTK 神機的雙卡 IMSI覆致、IMSI 信息
     */
    public static TeleInfo getMtkTeleInfo(Context context) {
        TeleInfo teleInfo = new TeleInfo();
        try {
            Class<?> phone = Class.forName("com.android.internal.telephony.Phone");

            Field fields1 = phone.getField("GEMINI_SIM_1");
            fields1.setAccessible(true);
            int simId_1 = (Integer) fields1.get(null);

            Field fields2 = phone.getField("GEMINI_SIM_2");
            fields2.setAccessible(true);
            int simId_2 = (Integer) fields2.get(null);

            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            Method getSubscriberIdGemini = TelephonyManager.class.getDeclaredMethod("getSubscriberIdGemini", int.class);
            String imsi_1 = (String) getSubscriberIdGemini.invoke(tm, simId_1);
            String imsi_2 = (String) getSubscriberIdGemini.invoke(tm, simId_2);
            teleInfo.imsi_1 = imsi_1;
            teleInfo.imsi_2 = imsi_2;

            Method getDeviceIdGemini = TelephonyManager.class.getDeclaredMethod("getDeviceIdGemini", int.class);
            String imei_1 = (String) getDeviceIdGemini.invoke(tm, simId_1);
            String imei_2 = (String) getDeviceIdGemini.invoke(tm, simId_2);

            teleInfo.imei_1 = imei_1;
            teleInfo.imei_2 = imei_2;

            Method getPhoneTypeGemini = TelephonyManager.class.getDeclaredMethod("getPhoneTypeGemini", int.class);
            int phoneType_1 = (Integer) getPhoneTypeGemini.invoke(tm, simId_1);
            int phoneType_2 = (Integer) getPhoneTypeGemini.invoke(tm, simId_2);
            teleInfo.phoneType_1 = phoneType_1;
            teleInfo.phoneType_2 = phoneType_2;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return teleInfo;
    }

    /**
     * MTK Phone.
     * <p>
     * 獲取 MTK 神機的雙卡 IMSI侄旬、IMSI 信息
     */
    public static TeleInfo getMtkTeleInfo2(Context context) {
        TeleInfo teleInfo = new TeleInfo();
        try {
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            Class<?> phone = Class.forName("com.android.internal.telephony.Phone");
            Field fields1 = phone.getField("GEMINI_SIM_1");
            fields1.setAccessible(true);
            int simId_1 = (Integer) fields1.get(null);
            Field fields2 = phone.getField("GEMINI_SIM_2");
            fields2.setAccessible(true);
            int simId_2 = (Integer) fields2.get(null);

            Method getDefault = TelephonyManager.class.getMethod("getDefault", int.class);
            TelephonyManager tm1 = (TelephonyManager) getDefault.invoke(tm, simId_1);
            TelephonyManager tm2 = (TelephonyManager) getDefault.invoke(tm, simId_2);

            String imsi_1 = tm1.getSubscriberId();
            String imsi_2 = tm2.getSubscriberId();
            teleInfo.imsi_1 = imsi_1;
            teleInfo.imsi_2 = imsi_2;

            String imei_1 = tm1.getDeviceId();
            String imei_2 = tm2.getDeviceId();
            teleInfo.imei_1 = imei_1;
            teleInfo.imei_2 = imei_2;

            int phoneType_1 = tm1.getPhoneType();
            int phoneType_2 = tm2.getPhoneType();
            teleInfo.phoneType_1 = phoneType_1;
            teleInfo.phoneType_2 = phoneType_2;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return teleInfo;
    }

    /**
     * Qualcomm Phone.
     * 獲取 高通 神機的雙卡 IMSI、IMSI 信息
     */
    public static TeleInfo getQualcommTeleInfo(Context context) {
        TeleInfo teleInfo = new TeleInfo();
        try {
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            Class<?> simTMclass = Class.forName("android.telephony.MSimTelephonyManager");
            // Object sim = context.getSystemService("phone_msim");
            Object sim = context.getSystemService(Context.TELEPHONY_SERVICE);
            int simId_1 = 0;
            int simId_2 = 1;

            Method getSubscriberId = simTMclass.getMethod("getSubscriberId", int.class);
            String imsi_1 = (String) getSubscriberId.invoke(sim, simId_1);
            String imsi_2 = (String) getSubscriberId.invoke(sim, simId_2);
            teleInfo.imsi_1 = imsi_1;
            teleInfo.imsi_2 = imsi_2;

            Method getDeviceId = simTMclass.getMethod("getDeviceId", int.class);
            String imei_1 = (String) getDeviceId.invoke(sim, simId_1);
            String imei_2 = (String) getDeviceId.invoke(sim, simId_2);
            teleInfo.imei_1 = imei_1;
            teleInfo.imei_2 = imei_2;

            Method getDataState = simTMclass.getMethod("getDataState");
            int phoneType_1 = tm.getDataState();
            int phoneType_2 = (Integer) getDataState.invoke(sim);
            teleInfo.phoneType_1 = phoneType_1;
            teleInfo.phoneType_2 = phoneType_2;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return teleInfo;
    }

    /**
     * Spreadtrum Phone.
     * <p>
     * 獲取 展訊 神機的雙卡 IMSI煌妈、IMSI 信息
     */
    public static TeleInfo getSpreadtrumTeleInfo(Context context) {
        TeleInfo teleInfo = new TeleInfo();
        try {

            TelephonyManager tm1 = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            String imsi_1 = tm1.getSubscriberId();
            String imei_1 = tm1.getDeviceId();
            int phoneType_1 = tm1.getPhoneType();
            teleInfo.imsi_1 = imsi_1;
            teleInfo.imei_1 = imei_1;
            teleInfo.phoneType_1 = phoneType_1;

            Class<?> phoneFactory = Class.forName("com.android.internal.telephony.PhoneFactory");
            Method getServiceName = phoneFactory.getMethod("getServiceName", String.class, int.class);
            getServiceName.setAccessible(true);
            TelephonyManager tm2 = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            String imsi_2 = tm2.getSubscriberId();
            String imei_2 = tm2.getDeviceId();
            int phoneType_2 = tm2.getPhoneType();
            teleInfo.imsi_2 = imsi_2;
            teleInfo.imei_2 = imei_2;
            teleInfo.phoneType_2 = phoneType_2;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return teleInfo;
    }

    /**
     * 獲取 MAC 地址
     * <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
     */
    public static String getMacAddress(Context context) {
        //wifi mac地址
        WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        WifiInfo info = wifi.getConnectionInfo();
        String mac = info.getMacAddress();

        return mac;
    }

    /**
     * 獲取 開機時間
     */
    public static String getBootTimeString() {
        long ut = SystemClock.elapsedRealtime() / 1000;
        int h = (int) ((ut / 3600));
        int m = (int) ((ut / 60) % 60);

        return h + ":" + m;
    }
}

10儡羔、錯誤信息反饋工具類

package com.example.dj.testdemo.Utils;

import android.content.Context;

/**
 * 基本功能:錯誤信息反饋信息
 * <p>
 * Created by dj on 2016/11/17 0017.
 */

public class ErrorMessageUtil {

    public static String printErrorMessage(Context context, String methodName, String errorMessage) {
        return "\n############################errorMessage start ##############################\n"
                + MobileUtil.printMobileInfo(context) + MobileUtil.printSystemInfo() + "\n錯誤信息:" + errorMessage + "\n方法名:" + methodName + "\n當(dāng)前app版本號:" + VersionUtil.getVersion(context)
                + "\n############################errorMessage end##############################";
    }
}

11、Snackbar的工具類

使用方法:
使用Snackbar要導(dǎo)入com.android.support:design庫璧诵。
bug:設(shè)置的位置為什么沒有效果汰蜘??之宿?
SnackbarUtil.ShortSnackbar(linearLayout, "登錄成功", getResources().getColor(R.color.white),
Gravity.CENTER_HORIZONTAL, getResources().getColor(R.color.green)).show();

/**
 * desc: SnackBar的工具類
 * author: dj
 * date: 2017/2/16 13:19
 */

public class SnackbarUtil {

    public static final int Success = 1;
    public static final int Error = 2;
    public static final int Warning = 3;


    public static int red = 0xfff44336;
    public static int blue = 0xff2195f3;
    public static int orange = 0xffffc107;

    /**
     * 短顯示SnackBar族操,自定義顏色
     *
     * @param view
     * @param message
     * @param messageColor
     * @param backgroundColor
     * @return
     */
    public static Snackbar ShortSnackbar(View view, String message, int messageColor, int gravity, int backgroundColor) {
        Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT);
        setSnackbarColor(snackbar, messageColor, gravity, backgroundColor);
        return snackbar;
    }

    /**
     * 長顯示SnackBar,自定義顏色
     *
     * @param view
     * @param message
     * @param messageColor
     * @param backgroundColor
     * @return
     */
    public static Snackbar LongSnackbar(View view, String message, int messageColor, int gravity, int backgroundColor) {
        Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
        setSnackbarColor(snackbar, messageColor, gravity, backgroundColor);
        return snackbar;
    }

    /**
     * 自定義時常顯示SnackBar比被,自定義顏色
     *
     * @param view
     * @param message
     * @param messageColor
     * @param backgroundColor
     * @return
     */
    public static Snackbar IndefiniteSnackbar(View view, String message, int duration, int messageColor, int gravity, int backgroundColor) {
        Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE).setDuration(duration);
        setSnackbarColor(snackbar, messageColor, gravity, backgroundColor);
        return snackbar;
    }

    /**
     * 短顯示SnackBar色难,可選預(yù)設(shè)類型
     *
     * @param view
     * @param message
     * @param type
     * @return
     */
    public static Snackbar ShortSnackbar(View view, String message, int type) {
        Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT);
        switchType(snackbar, type);
        return snackbar;
    }

    /**
     * 長顯示SnackBar,可選預(yù)設(shè)類型
     *
     * @param view
     * @param message
     * @param type
     * @return
     */
    public static Snackbar LongSnackbar(View view, String message, int type) {
        Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
        switchType(snackbar, type);
        return snackbar;
    }

    /**
     * 自定義時常顯示SnackBar等缀,可選預(yù)設(shè)類型B
     *
     * @param view
     * @param message
     * @param type
     * @return
     */
    public static Snackbar IndefiniteSnackbar(View view, String message, int duration, int type) {
        Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE).setDuration(duration);
        switchType(snackbar, type);
        return snackbar;
    }

    //選擇預(yù)設(shè)類型
    private static void switchType(Snackbar snackbar, int type) {
        switch (type) {
            case Success:
                setSnackbarColor(snackbar, blue);
                break;
            case Error:
                setSnackbarColor(snackbar, red);
                break;
            case Warning:
                setSnackbarColor(snackbar, orange);
                break;

        }
    }

    /**
     * 設(shè)置SnackBar背景顏色
     *
     * @param snackbar
     * @param backgroundColor
     */
    public static void setSnackbarColor(Snackbar snackbar, int backgroundColor) {
        View view = snackbar.getView();
        if (view != null) {
            view.setBackgroundColor(backgroundColor);
        }
    }

    /**
     * 設(shè)置SnackBar文字和背景顏色
     *
     * @param snackbar
     * @param messageColor
     * @param backgroundColor
     */
    public static void setSnackbarColor(Snackbar snackbar, int messageColor, int gravity, int backgroundColor) {
        View view = snackbar.getView();
        if (view != null) {
            view.setBackgroundColor(backgroundColor);
            ((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(messageColor);
            ((TextView) view.findViewById(R.id.snackbar_text)).setGravity(gravity);
        }
    }

    /**
     * 向SnackBar中添加view
     *
     * @param snackbar
     * @param layoutId
     * @param index    新加布局在SnackBar中的位置
     */
    public static void SnackbarAddView(Snackbar snackbar, int layoutId, int index) {
        View snackbarview = snackbar.getView();
        Snackbar.SnackbarLayout snackbarLayout = (Snackbar.SnackbarLayout) snackbarview;

        View add_view = LayoutInflater.from(snackbarview.getContext()).inflate(layoutId, null);

        LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        p.gravity = Gravity.CENTER_VERTICAL;

        snackbarLayout.addView(add_view, index, p);
    }
}

參考文獻:鴻洋
簡名

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末枷莉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子尺迂,更是在濱河造成了極大的恐慌笤妙,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枪狂,死亡現(xiàn)場離奇詭異危喉,居然都是意外死亡,警方通過查閱死者的電腦和手機州疾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門辜限,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人严蓖,你說我怎么就攤上這事薄嫡。” “怎么了颗胡?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵毫深,是天一觀的道長。 經(jīng)常有香客問我毒姨,道長哑蔫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮闸迷,結(jié)果婚禮上嵌纲,老公的妹妹穿的比我還像新娘。我一直安慰自己腥沽,他們只是感情好逮走,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著今阳,像睡著了一般师溅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盾舌,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天墓臭,我揣著相機與錄音,去河邊找鬼矿筝。 笑死起便,一個胖子當(dāng)著我的面吹牛棚贾,可吹牛的內(nèi)容都是我干的窖维。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼妙痹,長吁一口氣:“原來是場噩夢啊……” “哼铸史!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起怯伊,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤琳轿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后耿芹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崭篡,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年吧秕,在試婚紗的時候發(fā)現(xiàn)自己被綠了琉闪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡砸彬,死狀恐怖颠毙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情砂碉,我是刑警寧澤蛀蜜,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站增蹭,受9級特大地震影響滴某,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一霎奢、第九天 我趴在偏房一處隱蔽的房頂上張望偏瓤。 院中可真熱鬧,春花似錦椰憋、人聲如沸厅克。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽证舟。三九已至,卻和暖如春窗骑,著一層夾襖步出監(jiān)牢的瞬間女责,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工创译, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抵知,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓软族,卻偏偏與公主長得像刷喜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子立砸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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