Android從門外到入門(1)

此文假設所有人都會java的語法.

手把手創(chuàng)建項目

  1. 打開Android studio后, 選擇file-new project-選擇Phone and Tablet-選中Basic Activity, 點擊Next, 輸入名字和選擇api level之后, 點擊Finish.
  2. 此時android studio 自動創(chuàng)建了一個項目并進行sync 操作. 查看對應的AndroidManifest.xml文件, 可以看到已經自動創(chuàng)建了一個MainActivity項并配置完成
  3. 然后點擊android studio上的Run按鈕, 此時就會自動打包并安裝到手機上

初識Android文件結構

Android的文件結構, 主要包含幾個重要部分:
1.gradle文件
包括項目的build.gradle文件, 主要負責配置gradle倉庫和打包腳本, 無需過多關注, 以及組件的build.gradle文件, 負責配置安卓版本以及依賴包, 這個文件需要注意, 在導入依賴包時必須使用到.

  • plugin 一般有兩個值可選: 'com.android.application'表示這是一個應用程序模塊, 'com.android.library'表示這是一個庫模塊
apply plugin: 'com.android.application'
  • android 閉包
android {
   compileOptions{  // 這里表示使用java 1.8特性
       sourceCompatibility JavaVersion.VERSION_1_8
       targetCompatibility JavaVersion.VERSION_1_8
   }
   compileSdkVersion 28   //這個表示默認打包為sdk 28版本
   defaultConfig {
       applicationId "com.zzy.xuexiqiangguo"  // 包id
       minSdkVersion 26   // 最低支持的系統(tǒng)版本
       targetSdkVersion 28 // 默認的系統(tǒng)版本
       versionCode 1  //包版本
       versionName "1.0" //包版本
       testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // 這里表示無界面測試依賴包
   }
   buildTypes {
       release {
           minifyEnabled false
           proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
       }
   }
}
  • dependencies
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')  // 依賴libs/*.jar包
    implementation 'com.android.support:appcompat-v7:28.0.0' // 依賴包
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2' // 測試依賴包
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation project(':rhinojs') // 表示依賴另一個項目
}
  1. AndroidManifest.xml 文件, 該文件配置了app的名字, 活動, 權限等數據, 必須關注, 在啟動時會從該文件中查找對應的動作.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zzy.xuexiqiangguo">
    <uses-permission android:name="android.permission.INTERNET"/> //這里表示請求網絡權限
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service  // 這段表示綁定AccessibilityService
            android:name=".RobService"
            android:enabled="true"
            android:exported="true"
            android:label="學習強國"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService" />
        </intent-filter>
        <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/myaccessibility"/>
        </service>
        <activity android:name=".MainActivity"> // 這里表示下面的是啟動Activity
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
  1. main/java目錄, 該目錄下存放了android的代碼.
  2. main/res目錄, 該目錄下存放的是設計/圖片/媒體文件
Android的日志模塊Log

安卓的日志模塊Log, 在這個類中提供了5個不同級別的日志打印方法, 另外提供了logt這個快捷輸入命令用于添加TAG變量

  1. Log.v() 打印最瑣碎的日志信息, 快捷輸入logv
  2. Log.d() 打印調試信息, 快捷輸入logd
  3. Log.i() 打印一些比較重要的信息, 快捷輸入logi
  4. Log.w() 打印一些警告信息, 快捷輸入logw
  5. Log.e() 打印錯誤信息. 快捷輸入loge
    添加了日志打印內容后, 就可以在logcat中看到對應的日志了.

從活動Activity入手

活動在Android中的意思是指包含用戶界面的組件, 主要用于和用戶交互, 我們打開一個app時看到的每一個界面都是一個活動.

創(chuàng)建布局
  1. 在res目錄下新建layout目錄后, 右鍵點擊layout-layout resource file, 此時彈出新建面板, 輸入文件名后點擊ok
  2. 在Design頁中拖動一個button后加入到layout中, 此時可以實時看到button的顯示. 在這里解釋一下各個屬性
<Button
        android:id="@+id/button1" //@+id表示注冊一個新的id到R.id中, 在這里就是注冊R.id.button1
        android:layout_width="match_parent" // 這里表示寬度與父節(jié)點一致
        android:layout_height="wrap_content" // 這里表示高度適應大小
        android:text="Button" /> // text表示button上顯示的文本
活動的基本用法
  1. 在onCreate() 中加載布局: setContentView(R.layout.main_activity);
  2. 使用findViewById方法獲取到對應的View后, 添加事件監(jiān)聽
        Button button = (Button) findViewById(R.id.button1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "show toast", Toast.LENGTH_SHORT).show();
            }
        });
在AndroidManifest.xml中注冊
  1. 以下中intent-filter表示在啟動時打開MainActivity
        <activity android:name=".MainActivity"  android:label="demo activity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter>
        </activity>

完成了以上三個步驟之后, 就算是已經完成了一個最簡單的可用的app了.

使用Intent 切換Activity

切換界面, 是程序運行中一個再正常不過的需求

  1. 使用顯式Intent切換
Intent intent = new Intent(MainActivity.this, secondActivity.class);
startActivity(intent);
  1. 使用隱式Intent切換, 一般都是使用這個切換方式
Intent intent = new Intent("android.intent.action.MAIN");
intent.addCategory("android.intent.category.LAUNCHER");
startActivity(intent);
  1. 通過隱式Intent, 還可以用于打開網頁, 打開撥號盤等
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("https://www.baidu.com"));
                startActivity(intent);
                Intent intent = new Intent(Intent.ACTION_DIAL);
                intent.setData(Uri.parse("tel:10086"));
                startActivity(intent);

####### 活動間數據傳遞
傳遞數據代碼

Intent intent = new Intent("android.intent.action.MAIN");
intent.addCategory("android.intent.category.LAUNCHER");
intent.putExtra("extra_data", "helloworld");
startActivity(intent);

獲取數據代碼

        Intent intent = getIntent();
        String data = intent.getExtra("extra_data");

活動的生命周期

  1. 返回棧
    Android中的活動是可以層疊的. 每當啟動一個新的活動, 就會覆蓋在原活動之上, 然后按back鍵會銷毀最上面的活動, 下面的活動重新顯示出來.

  2. 活動狀態(tài)
    每個活動在其生命周期中最多可能會有4種狀態(tài)

    1. 運行狀態(tài)
      當一個活動位于棧頂時, 就處于運行狀態(tài).
    2. 暫停狀態(tài)
      當一個活動不再處于棧頂, 但活動依然可見時, 就處于暫停狀態(tài), 比如說點擊某個按鈕后彈出對話框, 此時對話框處于運行狀態(tài), 對話框下的活動處于暫停狀態(tài). 處于暫停狀態(tài)下的活動仍然是存活的, 系統(tǒng)也不愿意去回收這種活動.
    3. 停止狀態(tài)
      當一個活動不再處于棧頂, 并且不可見時, 就進入停止狀態(tài). 系統(tǒng)會為這種活動保存相應的狀態(tài)和成員變量, 但是當其他地方需要內存時, 停止狀態(tài)的活動可能會被回收.
    4. 銷毀狀態(tài)
      當一個活動從返回棧中移除后就變成銷毀狀態(tài).
  3. 活動的生存期
    Activity類提供了7個回調方法, 覆蓋了生命周期中的每一個環(huán)節(jié), 依次為

    • onCreate() 創(chuàng)建時調用, 這個創(chuàng)建可能是第一次創(chuàng)建, 也有可能是被系統(tǒng)回收后, 從返回棧中取出狀態(tài)重新創(chuàng)建
    • onStart() 活動由不可見狀態(tài)變?yōu)榭梢姞顟B(tài)時調用
    • onResume() 活動準備好與用戶進行交互時調用, 此時活動一定位于棧頂(比如關閉對話框時調用)
    • onPause() 系統(tǒng)準備去啟動或者恢復另一個活動的時候調用
    • onStop() 活動由可見變?yōu)椴豢梢姇r調用, 這個跟onPause的區(qū)別在于如果啟動的是一個對話框, 則onPause會執(zhí)行, onStop不會執(zhí)行
    • onDestroy() 活動被銷毀時調用
    • onRestart() 活動由停止狀態(tài)變?yōu)檫\行狀態(tài)時調用
完整生存期

可見生存期

前臺生存期

活動的生命周期
  1. 活動回收的處理
    前面的生命周期可以看到, 如果活動進入了停止狀態(tài), 是有可能被系統(tǒng)回收的. 那么這時候如果用戶按back鍵返回一個已經被回收的活動, 這時候系統(tǒng)不會執(zhí)行onRestart()方法, 而是會執(zhí)行onCreate()方法重新創(chuàng)建一次.
    但是活動是可能存在輸入狀態(tài)的, 比如文本框中的輸入文字, 在系統(tǒng)回收了該活動后, 重新創(chuàng)建出來的活動如果沒有了用戶輸入的內容, 是會嚴重影響用戶體驗的. 所以Android提供了一個onSaveInstanceState(Bundle outState)方法, 用于在系統(tǒng)回收活動的時候調用該方法保存用戶輸入. 代碼如下
outState.putString("data_key", "helloworld");

現在我們再看onCreate方法, 注意到該方法中有一個參數onCreate(Bundle savedInstanceState), 此時我們只需要通過這個bundle恢復之前所保存的數據即可

if (savedInstanceState != null) {
    String data = savedInstanceState.getString("data_key");
}
  1. 活動的啟動模式
    活動由幾種啟動模式, 可以在AndroidManifest.xml中通過給<activity>標簽指定android:launchMode屬性來選中啟動模式
    • standard
      standard是活動默認的啟動模式, 在不進行指定的情況下, 所有活動都是使用這個模式. 在standard模式下, 每當啟動一個新的活動, 它就會在返回棧中入棧, 并處于棧頂的位置, 系統(tǒng)并不關注活動是否在返回棧中已存在.
    • singleTop
      在singleTop模式下, 在啟動活動時系統(tǒng)會判斷返回棧的棧頂是否是該活動, 如果是則認為可以直接使用它. 不會再創(chuàng)建活動實例.
    • singleTask
      在singleTask模式下, 在啟動活動時系統(tǒng)會首先在返回棧中檢查是否已經存在該活動的實例, 如果發(fā)現已存在則直接使用該實例, 并且把該活動之上的所有活動都出棧, 銷毀. 如果沒有則創(chuàng)建一個新的活動實例.
    • singleInstance
      指定為singleInstance模式的活動會啟用一個新的返回棧來管理這個活動. 一般用于在與其他的程序共享一個活動的實例時.

UI

常用控件

因為篇幅有限, 加上控件的使用大同小異, 就不詳細寫控件的使用了, 只寫常用控件的特性和應用場景, 目的就是讓大家知道有這么個東西, 能解決什么樣的問題, 在關鍵時刻的時候尋找谷哥的幫助時知道用什么關鍵詞.

  1. TextView 顯示文本信息
  2. Button 按鈕
  3. EditText 輸入框
  4. ImageView 圖片控件
  5. ProgressBar 進度條
  6. AlertDialog 對話框
  7. ProgressDialog 進度條對話框
  8. RecyclerView 滾動控件
基本布局

UI 就是布局加控件的組合 -- 魯迅.

所以我們接下來還要了解一下基本布局

  1. 線性布局 LinearLayout, 如名所示, 這個布局會將它所包含的控件在線性上依次排列.
  2. 相對布局 RelativeLayout, 它可以通過相對定位的方式讓控件出現在布局的任何地方.
  3. 幀布局 FrameLayout, 這種布局沒有方便的定位方式, 所有的控件都會默認擺放在布局的左上角.
  4. 百分比布局 PercentFrameLayout 和 PercentRelativeLayout

廣播

  1. 廣播機制簡介
    Android中的每個應用都可以對自己感興趣的廣播進行注冊, 這樣該程序就只會接收到自己所關心的廣播內容. 這些廣播可能是來自于系統(tǒng)的, 也可能是來自于其他應用程序的.

    • 標準廣播 是一種完全異步執(zhí)行的廣播, 在廣播發(fā)出之后, 所有的廣播接收器幾乎都會在同一時刻接收到這條廣播消息
    • 有序廣播 則是一種同步執(zhí)行的廣播, 在廣播發(fā)出之后, 同一時刻只會有一個廣播接收器可以接收到這條消息. 當這條廣播接受器的邏輯處理完成后, 廣播才會繼續(xù)傳遞, 因此前面的廣播接收器可以截斷正在傳遞的廣播, 這樣后面的廣播接收器就無法收到廣播消息了.
  2. 接收系統(tǒng)廣播

    • 動態(tài)注冊監(jiān)聽網絡變化, 先在AndroidManifest.xml中加入<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" ></uses-permission>
private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;
    @Override
    public void onCreate(Bundle saveedInstanceState) {
        super.onCreate(saveedInstanceState);
        setContentView(R.layout.main_activity);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter);
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }
    
    class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            
        }
    }
  • 靜態(tài)注冊實現開機啟動
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" ></uses-permission>
<receiver 
        android:name=".BroadcastReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
</receiver>
  1. 發(fā)送廣播
    發(fā)廣播的方法跟啟動活動的方法很相似
                Intent intent = new Intent("com.zzy.broadcast.mybroadcast");
                sendBoardcast(intent);

發(fā)送有序廣播的方法跟發(fā)送標準廣播的方法只需要修改一點sendOrderedBoardcast(intent, null); 這里的第二個參數是一個與權限有關的字符串.

  1. 發(fā)送本地廣播
    前面我們發(fā)送和接收的廣播全部屬于系統(tǒng)全局廣播, 這樣很容易引起安全性問題, 為了能夠解決安全性問題, android引入了一套本地廣播體系, 本地廣播只能夠在應用程序的內部進行傳遞, 并且廣播接收器也只能接收來自本應用程序發(fā)出的廣播. 本地廣播的操作和全局廣播基本是一樣的, 只是通過LocalBroadcastManager進行一層管理.
        LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
        localBroadcastManager.sendBroadcast(intent);
        localBroadcastManager.registerReceiver(localReceiver, intentFilter);

數據持久化

  1. 文件存儲

多媒體

通知
                NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                //NotificationChannel channelbody = new NotificationChannel(channel,"消息推送",NotificationManager.IMPORTANCE_DEFAULT);
                String channelid = "channelid";
                String channelname = "channelname";
                Notification notification;
                Intent intent = new Intent(MainActivity.this, FruitRecycleView.class);
                PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, 0); //設置點擊通知的響應
                int importance = NotificationManager.IMPORTANCE_LOW;
                NotificationChannel mChannel = manager.getNotificationChannel(channelid);;
                if (mChannel == null) {
                    mChannel = new NotificationChannel(channelid, channelname, importance);
                    mChannel.setDescription("My Channel");
                    // 設置通知出現時的閃燈(如果 android 設備支持的話)
                    mChannel.enableLights(true);
                    mChannel.setLightColor(Color.RED);
                    // 設置通知出現時的震動(如果 android 設備支持的話)
                    mChannel.enableVibration(true);
                    mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});

                    manager.createNotificationChannel(mChannel);
                }
                notification = new NotificationCompat.Builder(MainActivity.this, channelid )
                        .setContentTitle("This is Title")
                        .setContentText("This is content Text")
                        .setWhen(System.currentTimeMillis())
                        .setSmallIcon(R.drawable.logo)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.icon128))
                        .setAutoCancel(true)
                        .setContentIntent(pendingIntent)
                        .build();

                manager.notify(1, notification);
從相冊查看相片
if (ContextCompat.checkSelfPermission(cameraActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "onClick: checkpermission failed");
                    ActivityCompat.requestPermissions(cameraActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                } else {
                    Log.d(TAG, "onClick: start image select");
                    Intent intent = new Intent("android.intent.action.GET_CONTENT");
                    intent.setType("image/*");
                    startActivityForResult(intent, 2);
                }
調用相機
                File file = new File(getExternalCacheDir(), "image.jpg");
                try {
                    if(file.exists()) {
                        file.delete();
                    }
                    file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // 第二個參數可以是任意唯一的字符串
                imageUri = FileProvider.getUriForFile(cameraActivity.this, "com.example.cameratest.provider", file);
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                startActivityForResult(intent, 1);

服務

Android多線程

和其他的gui庫一樣, android的UI也是線程不安全的, 也就是說, 如果想要更新UI元素, 就必須在主線程中進行, 否則就會出現異常.
因此, android提供了一套異步消息處理機制, 解決了線程中的通信問題.
寫在UI線程中

    private Handler handler = new Handler(){
          @Override
          public void handleMessage(Message message) {
              switch (message.what) {
                  case 1:
                      String txt = (String)message.obj;
                      text.setText(txt);
                      break;
              }
          }
    };

寫在子線程中

Message message = new Message();
message.obj = "helloworld";
handle.sendMessage(message);
使用AsyncTask

android還提供了另外一些工具以方便在子進程中對UI進行操作.

服務

跟activity類似, 服務也存在onCreate, onDestroy方法, 服務主要用于執(zhí)行一些比較耗時的工作. 另外Service并不是運行在單獨線程中,而是主線程中。所以盡量要避免一些ANR(Application Not Responding)的操作杂抽。

public class MyService extends Service {
    String TAG = "MyService";
    public MyService() {
    }

    @Override
    public void onCreate(){
        super.onCreate();
        Log.d("MyService", "onCreate execute");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        Log.d("MyService", "onStartCommand execute");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy(){
        super.onDestroy();
        Log.d("MyService", "onDestroy execute");
    }
}
活動與服務通信

為了讓活動與服務通信, 需要借助onBind接口, 通過這個接口, 活動可以調用服務的方法獲取狀態(tài), 以進行ui更新操作, 比如說在迅雷中的下載操作需要通過服務來進行, 然而為了實時更新進度條, 這就需要活動通過onBind接口實時獲取到進度之后更新進度條顯示.

    public MyBinder myBinder = new MyBinder();
    class MyBinder extends Binder{

        public void startBind(){
            Log.d("MyService", "startBind execute");
        }

        public int getProgress() {
            Log.d(TAG, "getProgress: execute");
            return 0;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.d("MyService", "onBind execute");
        return myBinder;
    }

    @Override
    public boolean onUnbind(Intent intent){
        Log.d("MyService", "onUnbind execute");
        return true;
    }

其中onBind和onUnbind方法是用于在綁定和解除綁定服務的時候調用的, 當活動與服務綁定之后, 就可以調用服務中的方法了.

Button bindService= (Button) findViewById(R.id.bindService);
        bindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, MyService.class);
                bindService(intent, connection, BIND_AUTO_CREATE);
            }
        });

        Button unbindService= (Button) findViewById(R.id.unbindService);
        unbindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                unbindService(connection);
            }
        });

private MyService.MyBinder myBinder ;
private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            myBinder = (MyService.MyBinder)iBinder;
            myBinder.startBind();
            myBinder.getProgress();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            
        }
    };
服務的生命周期

服務與活動的生命周期有一點重要的區(qū)別, 在于服務存在一個綁定的方法.

  1. onCreate() 創(chuàng)建時調用
  2. onStartCommand() 啟動服務時調用
  3. onBind() 綁定服務時調用, 只要調用方和服務之間的連接沒有斷開, 服務就會一直保持運行狀態(tài). 如果在之前沒有調用過startService()方法, 則還會先調用服務的onCreate()方法
  4. onUnBind() 取消綁定時調用, 如果是調用onBind()啟動的服務, 并且沒有調用過startService()方法, 則此時還會銷毀服務.
  5. onDestroy() 銷毀時調用, 注意如果一個服務既調用了startService()也調用了bingService()方法, 則此時必須要同時調用stopService()和unBindService()方法才會銷毀.

使用前臺服務

當系統(tǒng)內存不足時, 還是可能會回收掉后臺運行的服務, 如果希望服務可以一直保持運行狀態(tài)而不會因為系統(tǒng)內存不足而被回收掉, 可以使用前臺服務.
前臺服務和普通服務的區(qū)別在于前臺服務會一直有一個正在運行的圖標在系統(tǒng)的狀態(tài)欄顯示. 比如說音樂播放器的正在播放狀態(tài).

// 在service的oncreate方法中執(zhí)行
Intent intent = new Intent(MainActivity.this, FruitRecycleView.class);
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, 0); //設置點擊通知的響應
Notification notification = new NotificationCompat.Builder(this)
                        .setContentTitle("This is Title")
                        .setContentText("This is content Text")
                        .setWhen(System.currentTimeMillis())
                        .setSmallIcon(R.drawable.logo)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.icon128))
                        .setContentIntent(pendingIntent)
                        .build();
startForceground(1, notification);
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末遂赠,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子脉让,更是在濱河造成了極大的恐慌桂敛,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溅潜,死亡現場離奇詭異术唬,居然都是意外死亡,警方通過查閱死者的電腦和手機滚澜,發(fā)現死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門粗仓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人博秫,你說我怎么就攤上這事潦牛。” “怎么了挡育?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵巴碗,是天一觀的道長。 經常有香客問我即寒,道長橡淆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任母赵,我火速辦了婚禮逸爵,結果婚禮上,老公的妹妹穿的比我還像新娘凹嘲。我一直安慰自己师倔,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布周蹭。 她就那樣靜靜地躺著趋艘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凶朗。 梳的紋絲不亂的頭發(fā)上瓷胧,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音棚愤,去河邊找鬼搓萧。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的瘸洛。 我是一名探鬼主播揍移,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼货矮!你這毒婦竟也來了羊精?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤囚玫,失蹤者是張志新(化名)和其女友劉穎喧锦,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體抓督,經...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡燃少,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了铃在。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阵具。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖定铜,靈堂內的尸體忽然破棺而出阳液,到底是詐尸還是另有隱情,我是刑警寧澤揣炕,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布帘皿,位于F島的核電站,受9級特大地震影響畸陡,放射性物質發(fā)生泄漏鹰溜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一丁恭、第九天 我趴在偏房一處隱蔽的房頂上張望曹动。 院中可真熱鬧许赃,春花似錦坛增、人聲如沸抄瑟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瞧壮。三九已至蝌麸,卻和暖如春莉恼,著一層夾襖步出監(jiān)牢的瞬間痊硕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工押框, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留岔绸,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像盒揉,于是被迫代替她去往敵國和親晋被。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內容