Android 面试之 Android 篇二

本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-android.html

本文收集整理了 Android 面试中会遇到与 Android 知识相关的简述题。

线程

子线程中更新UI的方法

第一种:Handler+Message

第二种:

new Handler(context.getMainLooper()).post(
  new Runnable(){
    public void run(){
    //更新UI
    }
  });

第三种:

((Activity)context)runOnUiThread(
  new Runnable(){
    public void run(){
      //更新UI
    }
  }
  );

多线程

  • 继承 Thread 类
  • 实现 Runnable 接口
  • HandlerThread
  • Handler
  • AsyncTask
  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable),View.postDelay(Runnable,long)
Service Thread IntentService AsyncTask
When to use ? Task with no UI, but shouldn't be too long. Use threads within service for long tasks. - Long task in general.- For tasks in parallel use Multiple threads (traditional mechanisms) - Long task usually with no communication to main thread.(Update)- If communication is required, can use main thread handler or broadcast intents- When callbacks are needed (Intent triggered tasks). - Small task having to communicate with main thread.- For tasks in parallel use multiple instances OR Executor
Trigger Call to methodonStartService() Thread start() method Intent Call to method execute()
Triggered From (thread) Any thread Any Thread Main Thread (Intent is received on main thread and then worker thread is spawed) Main Thread
Runs On (thread) Main Thread Its own thread Separate worker thread Worker thread. However, Main thread methods may be invoked in between to publish progress.
Limitations /****Drawbacks May block main thread - Manual thread management- Code may become difficult to read - Cannot run tasks in parallel.- Multiple intents are queued on the same worker thread. - one instance can only be executed once (hence cannot run in a loop) - Must be created and executed from the Main thread

线程同步

  • 使用 synchronized 关键字创建 synchronized 方法。
  • 使用 synchronized 创建同步代码块。

参考:

http://www.itzhai.com/java-based-notebook-thread-synchronization-problem-solving-synchronization-problems-synchronized-block-synchronized-methods.html#2.1%E3%80%81%E4%BD%BF%E7%94%A8synchronized%E5%85%B3%E9%94%AE%E5%AD%97%E5%88%9B%E5%BB%BAsynchronized%E6%96%B9%E6%B3%95%EF%BC%9A

http://www.juwends.com/tech/android/android-inter-thread-comm.html

进程

进程优先级

  1. 前台进程:即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最后被杀死的
  2. 可见进程:可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但由于失去了焦点而不能与用户交互
  3. 服务进程:其中运行着使用startService方法启动的Service,虽然不被用户可见,但是却是用户关心的,例如用户正在非音乐界面听的音乐或者正在非下载页面自己下载的文件等;当系统要空间运行前两者进程时才会被终止
  4. 后台进程:其中运行着执行onStop方法而停止的程序,但是却不是用户当前关心的,例如后台挂着的QQ,这样的进程系统一旦没了有内存就首先被杀死
  5. 空进程:不包含任何应用程序的程序组件的进程,这样的进程系统是一般不会让他存在的

AIDL 解决了什么问题

AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在 Android 设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如 Service, 设置了属性 android:process=":remote" 后,Service 就会运行在另外一个进程)对象的操作,就可以使用AIDL生成可序列化的参数。 AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。

AIDL的全称是什么?如何工作?能处理哪些类型的数据

ADIL是一种接口定义语言,用于约束两个进程之间的通信规则,供编译器生成代码,实现android设备之间的进程通信。

进程之间的通信信息首先会被转换成AIDL协议消息,然后发送给对方,对方受到AIDL协议消息后在转换成相应的对象。AIDL支持类型包括java基础类型和String,List,Map,CharSequence,如果使用自定类型,必须实现Parcelable接口

Broadcast、Content Provider 和 AIDL的区别和联系

这3种都可以实现跨进程的通信,那么从效率,适用范围,安全性等方面来比较的话他们3者之间有什么区别?

Broadcast:用于发送和接收广播!实现信息的发送和接收!

AIDL:用于不同程序间服务的相互调用!实现了一个程序为另一个程序服务的功能!
Content Provider:用于将程序的数据库人为地暴露出来!实现一个程序可以对另个程序的数据库进行相对用的操作!

Broadcast,既然是广播,那么它的优点是:注册了这个广播接收器的应用都能够收到广播,范围广。缺点是:速度慢点,而且必须在一定时间内把事情处理完(onReceive执行必须在几秒之内),否则的话系统给出ANR。

AIDL,是进程间通信用的,类似一种协议吧。优点是:速度快(系统底层直接是共享内存),性能稳,效率高,一般进程间通信就用它。

Content Provider,因为只是把自己的数据库暴露出去,其他程序都可以来获取数据,数据本身不是实时的,不像前两者,只是起个数据供应作用。一般是某个成熟的应用来暴露自己的数据用的。 你要是为了进程间通信,还是别用这个了,这个又不是实时数据。

进程间传输方式

Android进程间通信,Binder机制

Android跨进程通讯的方式

Android Mashup设计的理解

触摸事件

View 的触摸事件分发机制

基础知识

  1. 所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。
  2. 事件类型分为ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每个事件都是以ACTION_DOWN开始ACTION_UP结束。
  3. 对事件的处理包括三类,分别为传递——dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费——onTouchEvent()函数和OnTouchListener

传递流程

  1. 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。
  2. 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。
  3. 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。
  4. 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。
  5. OnTouchListener优先于onTouchEvent()对事件进行消费。

上面的消费即表示相应函数返回值为true。

  • View不处理事件流程图:
  • View处理事件流程图:View.onTouchEvent() 返回true
  • 拦截事件流程图:ViewGroup.onInterceptTouchEvent() 对MOVE、UP事件进行拦截

参考:

Android Touch事件传递机制

事件分发机制

onInterceptTouchEvent()和onTouchEvent()的区别?

onInterceptTouchEvent()用于拦截触摸事件。

onTouchEvent()用于处理触摸事件。

view的事件冲突处理

View

View 绘制流程

当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android framework 处理。绘制是从根节点开始,对布局树进行 measure 和 draw。整个 View 树的绘图流程在ViewRoot.java类的 performTraversals() 函数展开,该函数所做 的工作可简单概况为是否需要重新计算视图大小(measure)、是否需要重新安置视图的位置(layout)、以及是否需要重绘(draw),流程图如下:

View的绘制流程是从ViewRoot的performTraversals()方法开始,依次经过measure()layout()draw()三个过程才最终将一个View绘制出来。

参考:

公共技术点之 View 绘制流程

Android 绘图机制原理

参考:

Android中的绘制机制

requertlayout onlayout onDraw drawChild 的区别和联系

  • requestLayout()方法 :会导致调用measure()过程 和 layout()过程 。 将会根据标志位判断是否需要ondraw。
  • onLayout()方法:如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局。
  • 调用onDraw()方法绘制视图本身,每个View都需要重载该方法,ViewGroup不需要实现该方法。
  • drawChild()去重新回调每个子视图的draw()方法。

View 刷新机制

在Android的布局体系中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成。

子View调用invalidate时,首先找到自己父View(View的成员变量mParent记录自己的父View),然后将AttachInfo中保存的信息告诉父View刷新自己。

在invalidate中,调用父View的invalidateChild,这是一个从第向上回溯的过程,每一层的父View都将自己的显示区域与传入的刷新Rect做交集。

这个向上回溯的过程直到ViewRoot那里结束,由ViewRoot对这个最终的刷新区域做刷新。

参考:

Android View刷新机制

invalidata() 和 postInvalidata() 的区别及使用

  • invalidata() 必须在 UI 线程中调用,所以一般都是配合 Handler 使用。
  • postInvalidata() 可以在其他线程直接调用。

notifyDataSetChanged和notifyDataSetInvalidated的区别

  • notifyDataSetInvalidated(),会重绘整个控件(还原到初始状态)
  • notifyDataSetChanged(),重绘当前可见区域

SurfaceView和View的区别是什么?

SurfaceView中采用了双缓存技术,在单独的线程中更新界面。而View在UI线程中更新界面。

RemoteView在哪些功能中使用

在 AppWidget(桌面小插件)和 Notification(通知栏)中使用。

参考:

Android widget 之RemoteView

自定义 View

自定义View相关方法

  1. 自定义属性的声明和获取
    • 分析需要的自定义属性
    • 在res/values/attrs.xml定义声明
    • 在layout文件中进行使用
    • 在View的构造方法中进行获取
  2. 测量onMeasure
  3. 布局onLayout(ViewGroup)
  4. 绘制onDraw
  5. onTouchEvent
  6. onInterceptTouchEvent(ViewGroup)
  7. 状态的恢复与保存

如何自定义控件

有哪些实现自定义控件的方法?

自定义控件的实现有三种方式,分别是:组合控件、自绘控件和继承控件。

参考:

Android自定义View的三种实现方式

优化自定义 View

为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。

你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。

另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。

如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。

自定义view控件以及自定义属性的使用

NavigationDrawer,PageAdapter等UI模式的使用和定制

Layout 布局

Android中常用的五种布局

  • FrameLayout(框架布局)
  • LinearLayout (线性布局)
  • AbsoluteLayout(绝对布局)
  • RelativeLayout(相对布局)
  • TableLayout(表格布局)

LinearLayout和RelativeLayout性能对比

  1. RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
  2. RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
  3. 在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。

最后再思考一下文章开头那个矛盾的问题,为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout。因为DecorView的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会降低层级深度,所以此时在根节点上用LinearLayout是效率最高的。而之所以给开发者默认新建了个RelativeLayout是希望开发者能采用尽量少的View层级来表达布局以实现性能最优,因为复杂的View嵌套对性能的影响会更大一些。

参考 :

http://www.jianshu.com/p/8a7d059da746

Android中px,sp,dip,dp的区别与联系

px: pixel,即像素,1px代表屏幕上的一个物理的像素点。但px单位不被建议使用。因为同样像素大小的图片在不同手机显示的实际大小可能不同。要用到px的情况是需要画1像素表格线或阴影线的时候,如果用其他单位画则会显得模糊。

dip (dp): device independent pixel。dp (dip)是最常用也是最难理解的尺寸单位。与像素密度密切相关。Android系统定义了四种像素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi),它们对应的dp到px的系数分别为0.75、1、1.5和2,这个系数乘以dp长度就是像素数。例如界面上有一个长度为“80dp”的图片,那么它在240dpi的手机上实际显示为80x1.5=120px,在320dpi的手机上实际显示为80x2=160px。如果你拿这两部手机放在一起对比,会发现这个图片的物理尺寸“差不多”,这就是使用dp作为单位的效果。

sp: Scale-independent Pixel,即与缩放无关的抽象像素。sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时,1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。

asset目录与res目录的区别。

res 目录下面有很多文件,例如 drawable,mipmap,raw 等。res 下面除了 raw 文件不会被压缩外,其余文件都会被压缩。同时 res目录下的文件可以通过R 文件访问。

Asset 也是用来存储资源,但是 asset 文件内容只能通过路径或者 AssetManager 读取。

参考:

官方文档

Android屏幕适配

动画

Android属性动画特性

Android 起初有两种动画:Frame Animation(逐帧动画) Tween Animation(补间动画),但是在用的时候发现这两种动画有时候并不能满足我们的一些需要,所以Google在Androi3.0的时候推出了(Property Animation)属性动画,至于为什么前边的两种动画不能满足我们的需要,请往下看:

Frame Animation(逐帧动画)

逐帧动画就是UI设计多张图片组成一个动画,然后将它们组合链接起来进行动画播放。该方式类似于早期电影的制作原理:具体实现方式就不多说了,你只需要让你们的UI出多张图片,然后你顺序的组合就可以(前提是UI给您做图)

Tween Animation(补间动画)

Tween Animation:是对某个View进行一系列的动画的操作,包括淡入淡出(Alpha),缩放(Scale),平移(Translate),旋转(Rotate)四种模式

Tween Animation(补间动画)的一些缺点:

  1. Tween Animation(补间动画)只是针对于View,超脱了View就无法操作了,这句话的意思是:假如我们需要对一个Button,ImageView,LinearLayout或者是其他的继承自View的各种组件进行动画的操作时,Tween Animation是可以帮我们完成我们需要完成的功能的,但是如果我们需要用到对一个非View的对象进行动画操作的话,那么补间动画就没办法实现了。举个例子:比如我们有一个自定义的View,在这个View中有一个Point对象用于管理坐标,然后在onDraw()方法中的坐标就是根据该Pointde坐标值进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义的View,那么整个自继承View的当前类就都有了动画,但是我们的目的是不想让View有动画,只是对动画中的Point坐标产生动画,这样补间动画就不能满足了。
  2. Tween Animation动画有四种动画操作(移动,缩放,旋转,淡入淡出),但是我们现在有个需求就是将当前View的背景色进行改变呢?抱歉Tween Animation是不能帮助我们实现的。
  3. Tween Animation动画只是改变View的显示效果而已,但是不会真正的去改变View的属性,举个例子:我们现在屏幕的顶部有一个小球,然后通过补间动画让他移动到右下角,然后我们给这个小球添加了点击事件,希望位置移动到右下角的时候点击小球能的放大小球。但是点击事件是绝对不会触发的,原因是补间动画只是将该小球绘制到了屏幕的右下角,实际这个小球还是停在屏幕的顶部,所以你在右下角点击是没有任何反应的。

Property Animatior(属性动画)

属性动画是Android3.0之后引进的,它更改的是动画的实际属性,在Tween Animation(补间动画)中,其改变的是View的绘制效果,真正的View的属性是改变不了的,比如你将你的Button位置移动之后你再次点击Button是没有任何点击效果的,或者是你如何缩放你的Button大小,缩放后的有效的点击区域还是只有你当初初始的Button的大小的点击区域,其位置和大小的属性并没有改变。而在Property Animator(属性动画)中,改变的是动画的实际属性,如Button的缩放,Button的位置和大小属性值都会发生改变。而且Property Animation不止可以应用于View,还可以应用于任何对象,Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。

Android动画框架实现原理

Animation 框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是整个View。实现原理:

每次绘制视图时,View 所在的 ViewGroup 中的 drawChild 函数获取该View 的 Animation 的 Transformation 值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用 invalidate() 函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源,最重要的是,动画改变的只是显示,并不能相应事件。

参考:

Android动画原理分析

图片缓存

图片三级缓存实现?自己设计一个图片加载框架

参考:

Android中图片的三级缓存

开源选型之Android三大图片缓存原理、特性对比

对 LruCache 的理解

参考:

内存缓存LruCache实现原理

Android提供的LruCache类简介

DiskLruCache

参考:

Android DiskLruCache完全解析,硬盘缓存的最佳方案

缓存算法

Bitmap的分析与使用

参考:

Android 从具体实例分析Bitmap使用时候内存注意点

Android之Bitmap大图加载处理

Loading Large Bitmaps Efficiently

Bitmap 压缩

public static Bitmap create(byte[] bytes, int maxWidth, int maxHeight) {
        //上面的省略了
        option.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, option);
        int actualWidth = option.outWidth;
        int actualHeight = option.outHeight;

        // 计算出图片应该显示的宽高
        int desiredWidth = getResizedDimension(maxWidth, maxHeight, actualWidth, actualHeight);
        int desiredHeight = getResizedDimension(maxHeight, maxWidth, actualHeight, actualWidth);

        option.inJustDecodeBounds = false;
        option.inSampleSize = findBestSampleSize(actualWidth, actualHeight,
                desiredWidth, desiredHeight);
        Bitmap tempBitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, option);

        // 做缩放
        if (tempBitmap != null
                && (tempBitmap.getWidth() > desiredWidth || tempBitmap
                .getHeight() > desiredHeight)) {
            bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth,
                    desiredHeight, true);
            tempBitmap.recycle();
        } else {
            bitmap = tempBitmap;
        }
    }

    return bitmap;
}

你这么做,decodeByteArray两次不是更占内存吗?😂😂😂

第一次设置inJustDecodeBounds = true 时候是不占内存的,因为返回的是null

一脸不相信我的说:噢,这地方我下去再看看。

吓得我回来了以后赶紧又看了看,还好没有记错,见源码注释

/**
* If set to true, the decoder will return null (no bitmap), but
* the out... fields will still be set, allowing the caller to query
* the bitmap without having to allocate the memory for its pixels.
*/
public boolean inJustDecodeBounds;

ARGB_8888格式图片占用内存大小

1 byte = 8 bit

8+8+8+8 = 32 32/8 = 4 byte 一个像素就占4byte

参考:

你的 Bitmap 究竟占多大内存

如何判断本地缓存的时候数据需要从网络端获取

图片加载机制

ListView

ListView的优化

ListView卡顿原因

  1. 在adapter中的getView方法中尽量少使用逻辑
  2. 尽最大可能避免GC
  3. 滑动的时候不加载图片
  4. 将ListView的scrollingCache和animateCache设置为false
  5. item的布局层级越少越好
  6. 使用ViewHolder

ListView 的实现原理

参考:

Android ListView工作原理完全解析,带你从源码的角度彻底理解

ViewHolder

参考:

ListView中convertView和ViewHolder的工作原理

ListView 下拉刷新、上拉加载更多实现原理

参考:

下拉刷新及滚动到底部加载更多的Listview使用 — 优先使用该开源实现

Android ListView下拉/上拉刷新:设计原理与实现

一个支持下拉上拉的开源库

RecyclerView和ListView的异同

  • RecyclerView 自带 ViewHolder;而 ListView 则需要自定义。
  • RecyclerView 支持水平和垂直滚动;而 ListView 只支持垂直滚动。
  • RecyclerView 提供默认的列表项动画实现,例如:添加、删除和移动列表项动画。
  • ListView通过AdapterView.OnItemClickListener接口来监听点击事件。而RecyclerView则通过RecyclerView.OnItemTouchListener接口来监听触摸事件。它虽然增加了实现的难度,但是却给予开发人员拦截触摸事件更多的控制权限。
  • ListView可以设置选择模式,并添加MultiChoiceModeListener;而 RecyclerView 没有该功能。

参考:

http://www.tuicool.com/articles/aeeaQ3J

http://blog.csdn.net/sanjay_f/article/details/48830311

能否讲讲你用过的adapter?

容器

SparseArray 和 HashMap 的区别

cpu 内存 适用场景
HashMap 增、删、查找速度较快 双倍扩容、不做空间整理,内存使用效率低 数据量较大或内存空间相对宽裕
ArrayMap 增、删、查速度较慢 size大于8扩容时,只增大当前数组大小的一半,做空间收缩整理 数据量小于1000时,速度相对差别不大,可替代HashMap
SparseArray 增、查速度较慢,由于延迟删除机制,删速度比ArrayMap快,比HashMap慢 矩阵压缩,大大减少了存储空间,节约内存 避免了key的自动装箱,空间压缩等机制,使得其在key是Integer、Long,且数据量较小场景下性能最优

参考:

HashMap、ArrayMap、SparseArray分析比较

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,263评论 25 707
  • 介绍自己负责的部分,如何实现的。 框架的搭建排查问题以及结解决方式兼容性保证性能优化上线之后模块导致crash的比...
    黄海佳阅读 13,135评论 6 350
  • 我一直想找的,又生活阅历和自己圈子的人出现了,就在猴年马月我遇见了,可是我没抓住。在想法上有种高大上的感觉。让我有...
    橙子TEL阅读 186评论 0 0
  • 我还是觉得 你 没有诗意 不向往远方的梦 活着 是眼前 我还是觉得 你 变了,不像你了 大笑 幽默 神秘 可爱 通...
    周大象xxx阅读 122评论 0 1
  • 只不过是一场雨 就让裙子飞起来了 在今年夏天的时候 好像并没有察觉
    娃哈哈乌拉拉阅读 143评论 0 0