Android学习笔记6 Fragment完全解析

Fragment,翻译为碎片、片段,Android 在 Android 3.0(API 11 )中引入了Fragment,主要是为了给大屏幕(如平板电脑)上更加动态和灵活的 UI 设计提供支持,本文带来Fragment完全解析,关于Fragment,你应该了解的一切!

一、Fragment概述
二、静态Fragment用法与解析
三、动态Fragment用法与解析
四、Fragment生命周期
五、Fragment与Activity通信
六、Fragment总结

一、Fragment概述

1.Fragment是什么
2.Fragment的设计目的

这部分主要简单介绍下Fragment是什么,与Activity的关系,以及Fragment的设计目的等部分,主要是给大家一个总体上的把握,之后会有Fragment的用法和详细解析。

1. Fragment是什么

AFragmentrepresents a behavior or a portion of user interface in anActivity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a "sub activity" that you can reuse in different activities).

Fragment表示Activity中的行为或者用户界面的一部分,我们可以在单个Activity中组合多个Fragment来构建多格的界面,也可以在多个Activity之间重用同一个Fragment。我们可以把Fragment想象成Activity的一个模块部分,它有自己的生命周期,可以接受用户事件,允许你在Activity正常运行期间添加或者移除,类似一个你可以在不同的Activity之间复用的子Activity。

Fragment必须绑定在Activity之中,它的生命周期也直接受着宿主Activity生命周期的影响。例如,当Activity暂停时,其中的所有Fragment也暂停,当Activity被销毁时,其中的所有Fragment也销毁。但是,当Activity正常运行时,你可以单独地管理每个Fragment,添加或移除。

2. Fragment的设计目的

Android应用运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布局以适应不同设备的需要。那么有没有办法可以做到一个App同时适应手机和平板呢?Fragment的出现就是为了解决这样的问题的。

Android 在 Android 3.0(API 11 级)中引入了片段,主要是为了给像平板电脑这类设备的大屏幕更加动态和灵活的 UI 设计提供支持。由于平板电脑的屏幕比手机屏幕大得多,因此可用于组合和交换 UI 组件的空间更大。利用片段实现此类设计时,您无需管理对视图层次结构的复杂更改。 通过将 Activity 布局分成片段,您可以在运行时修改 Activity 的外观,并在由 Activity 管理的返回栈中保留这些更改。

例如,新闻应用可以使用一个Fragment 在左侧显示文章列表,使用另一个Fragment 在右侧显示文章,两个片段并排显示在一个 Activity 中,每个片段都具有自己的一套生命周期回调方法,并各自处理自己的用户输入事件。 因此,用户不需要使用一个 Activity 来选择文章,然后使用另一个 Activity 来阅读文章,而是可以在同一个 Activity 内选择文章并进行阅读,如图所示。


不同设备上的展示方式

二、静态Fragment用法与解析

之所以称之为静态,是因为我们在布局文件里直接把Fragment看做是View作为Activity布局的一部分,大家可以看下面这张图,我已经标出了1、2两部分,的确,它是由两个Fragment组成,上面是标题,下面是内容部分,内容部分还有一个按钮。

两个Fragment组成的布局

下面我们按步骤创建出上面的布局,主要是让大家熟悉Fragment的基本使用,在用到Fragment导入包时,我选择的是不包含V4的包,因为我的minSdkVersion设置成了14,如果你的应用要支持11即Android 3.0以下的版本,则导入的是v4的包。

  1. 创建TopFragment,主要就是重写onCreateView方法初始化界面。
/**
 * Created by JackalTsc on 2016/7/11.
 */
public class TopFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        //初始化Fragment界面
        View view = inflater.inflate(R.layout.view_fragment_top, container, false);
        return view;

    }
}
  1. 创建TopFragment的布局 view_fragment_top.xml,其中只有一个TextView。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="50dp"
              android:background="#0000ff"
              android:gravity="center"
              android:orientation="vertical">
   <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="应用宝"
        android:textColor="#ffffff"/>
</LinearLayout>
  1. 创建BottomFragment, 方法onCreateView里初始化BottomFragment界面。
/**
 * Created by JackalTsc on 2016/7/11.
 */
public class BottomFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        //初始化Fragment界面
        View view = LayoutInflater.from(getActivity()).inflate(R.layout.view_fragment_bottom, container, false);

        Button btnHome = (Button) view.findViewById(R.id.btn_home);
        btnHome.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(), "选择了首页", Toast.LENGTH_LONG).show();
            }
        });

        return view;
    }
}

4.创建BottomFragment的布局 view_fragment_bottom.xml,其中包含一个TextView和一个Button。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="首页内容"
        android:textSize="50sp"/>

    <Button
        android:id="@+id/btn_comment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:text="首页"/>

</RelativeLayout>

5、创建Activity的布局 layout_activity_fragment.xml,其中包含两个Fragment。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">
    <fragment
        android:id="@+id/fragment_top"
        android:name="com.jackaltsc.android.mydemoproject.fragment.TopFragment"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>

    <fragment
        android:id="@+id/fragment_bottom"
        android:name="com.jackaltsc.android.mydemoproject.fragment.BottomFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
</LinearLayout>

6、最后我们只需要在Activity里设置布局即可,看,这里的逻辑十分简单,当我们点击评论按钮时,会有一个Toast消息,但是逻辑是在BottomFragment里进行处理的。有人可能会问,做了这么多工作好像很麻烦,但是我们应该记住,如果Fragment的界面有很好的通用性,那么重用的地方就会很多,为我们之后的工作节省不少功夫。

/**
 * Created by JackalTsc on 2016/7/11.
 */
public class Fragment1Activity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_activity_fragment);

    }
}

静态Fragment小结:

  1. Fragment里面重写回调方法onCreateView用来初始化Fragment的界面,方法里LayoutInflater对象可以扩展指定布局,返回View即为Fragment布局,这样Fragment即可作为Activity界面的一部分。
  2. Activity的界面里在包含Fragment时,Fragment的android:name属性为全限定名,用来实例化指定的Fragment,同时别忘了要给Fragment一个唯一的id,这个很重要,系统在Activity恢复时用它来存储状态。

三、动态Fragment用法与解析

动态Fragment主要是可以在Activity正常运行期间的任意时刻添加、删除或者替换Fragment。我们可以看下面这张图,它是由两部分组成,第1部分是内容,第2部分是两个按钮,当点击不同的按钮时,内容部分是会变化的。

动态Fragment使用.png

下面是详细的步骤。

1、首先是HomeFragment

/**
 * Created by JackalTsc on 2016/7/11.
 */
public class HomeFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.layout_fragment_home, container,false);
        return view;

    }
}

2、它的布局为 layout_fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center"
              android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="50sp"
        android:text="首页内容"/>

</LinearLayout>

3、其次是FindFragment

/**
 * Created by JackalTsc on 2016/7/11.
 */
public class FindFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.layout_fragment_find, container,false);
        return view;

    }
}

4、它的布局为 layout_fragment_find.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center"
              android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发现内容"
        android:textSize="50sp"/>

</LinearLayout>

5、Activity的布局为 layout_activity_fragment2.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_home"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="首页"/>

        <Button
            android:id="@+id/btn_find"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="5dp"
            android:layout_weight="1"
            android:text="发现"/>

    </LinearLayout>
</LinearLayout>

6、最后Activity里的代码

/**
 * Created by JackalTsc on 2016/7/11.
 */
public class Fragment2Activity extends Activity implements View.OnClickListener {

    private Button btnHome,btnFind;
    private HomeFragment homeFragment;
    private FindFragment findFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_activity_fragment2);
        //初始化
        init();
    }

    private void init() {
        btnHome = (Button) findViewById(R.id.btn_home);
        btnFind = (Button) findViewById(R.id.btn_find);

        btnHome.setOnClickListener(this);
        btnFind.setOnClickListener(this);

        getFragment(0);
    }

    @Override
    public void onClick(View v) {


        switch (v.getId()) {

            case R.id.btn_home:
                Toast.makeText(Fragment2Activity.this, "首页", Toast.LENGTH_SHORT).show();
                getFragment(0);
                break;

            case R.id.btn_find:
                Toast.makeText(Fragment2Activity.this, "发现", Toast.LENGTH_SHORT).show();
                getFragment(1);
                break;
        }
    }

    private void getFragment(int i) {

        //Fragment管理器
        FragmentManager manager = getFragmentManager();
        //事务
        FragmentTransaction transaction = manager.beginTransaction();

        switch (i) {

            case 0:
                if (homeFragment == null) {
                    homeFragment = new HomeFragment();
                }
                //选中首页 内容部分就替换为首页的Fragment
                transaction.replace(R.id.fragment_container, homeFragment);
                break;

            case 1:
                if (findFragment == null) {
                    findFragment = new FindFragment();
                }
                //选中发现 内容部分就替换为发现的Fragment
                transaction.replace(R.id.fragment_container, findFragment);
                break;
        }

        //只有提交才有效果
        transaction.commit();
    }
}

这样,你应该可以看到了,点击不同的Button时,内容部分是会切换的。Fragment2Activity里的代码可能比较长,但是并不复杂,我们重点关注getFragment这个函数里的东西,它主要是先用getFragmentManager()获取Fragment管理器,再获得Fragment事务,由事务进行替换,最后commit()。

动态Fragment使用小结

  1. 关于FragmentManager
    FragmentManager,Fragment管理器,是在Activity里进行Fragment交互的接口,可以通过getFragmentManager()方法获取当前Activity相关的事务管理器。
  2. **关于FragmentTransaction **
    FragmentTransaction,Fragment事务,是执行Fragment一系列操作的接口,可以通过FragmentManager对象的beginTransaction()获得,一般常用的操作主要有add,replace,remove,show,hide等等。当然,Fragment的操作最后都要commit提交才有效。

四、Fragment生命周期

Fragment的生命周期与Activity的生命有很多相似的地方,同时也有不同的地方,比如Fragment与Activity一样都有三种状态:

  1. Resumed
    Fragment在运行的Activity里处于可见状态
  1. Paused
    别的Activity正常运行状态,但是Fragment的宿主Activity仍处于可见状态
  2. Stopped
    Fragment处于不可见状态

Activity的生命周期对它的影响。官网上的这张图很清楚。

Activity生命周期影响着Fragment生命周期

下面介绍几个Fragment中的主要回调方法,

  1. onAttach()
    当fragment和activity关联时调用。
  2. onCreateView()
    当创建Fragment的View视图时调用
  3. onActivityCreated()
    当Activity的onCreate()方法返回时调用
  4. onDestroyView()
    当移除Fragment的View视图时调用
  5. onDetach()
    当fragment和activity解除关联时调用。

Activity和Fragment生命周期最大的不同之处在于它们在各自的回退栈中的存储方式不一样。默认情况下,一个Activity在停止时是存放在由系统管理的Activity回退栈中。但是,Fragment在移除的事务处理中,只有在你使用addToBackStack()方法明确请求保存实例状态时,它才会存放在由宿主Activity管理的回退栈中。

关于Fragment回退栈
类似与Android系统为Activity维护一个任务栈,我们也可以通过Activity维护一个回退栈来保存每次Fragment事务发生的变化。如果你将Fragment任务添加到回退栈,当用户点击后退按钮时,将看到上一次的保存的Fragment。一旦Fragment完全从后退栈中弹出,用户再次点击后退键,则退出当前Activity。

五、Fragment与Activity通信

虽然Fragment是实现成一个独立于Activity的对象并且可以在多个Activity中重复使用,但是一个指定的Fragment实例是直接与包含它的Activity绑定的。Fragment与Activity通信情况主要有以下几种。

  1. Fragment获取所在的Activity
    在Fragment中可以用getActivity()来访问Activity的实例,并且可以执行一些操作,比如查找一个视图:
View listView = getActivity().findViewById(R.id.list);
  1. Activity获取它包含的Fragment
    Activity 可以通过从FragmentManager获取对Fragment的引用来调用片段中的方法,findFragmentById()或findFragmentByTag()。
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
  1. Fragment与Activity共享数据
    有时候,如果需要Fragment和Activity共享事件,最好的方法是在Fragment里定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口,这样Fragment即可调用该回调方法将数据传给Activity。

针对第3种情况,这里有个简单的例子,是我参考疯狂Android讲义上的内容修改而成的,是个不错的学习Demo。如下图所示,分成两个部分,左边是食物的标题,右边是详细介绍。点击不同的标题时,详情部分会切换。

Fragment与Activity之间的通信
  1. 首先,新建一个FoodUtil 类,这个类主要包含一个实体FoodEntity 和相关数据集合,在之后会有用处。
/**
 * Created by JackalTsc on 2016/7/12.
 */
public class FoodUtil {

    //Food实体
    public static class FoodEntity {

        private int fId;
        private String fTitle;
        private String fDetail;

        public FoodEntity(int fId, String fTitle, String fDetail) {
            this.fId = fId;
            this.fTitle = fTitle;
            this.fDetail = fDetail;
        }

        @Override
        public String toString() {
            return getfTitle();
        }

        public String getfTitle() {
            return fTitle;
        }

        public void setfTitle(String fTitle) {
            this.fTitle = fTitle;
        }

        public int getfId() {
            return fId;
        }

        public void setfId(int fId) {
            this.fId = fId;
        }

        public String getfDetail() {
            return fDetail;
        }

        public void setfContent(String fContent) {
            this.fDetail = fDetail;
        }

    }

    //Book相关数据集合
    public static List<FoodEntity> foodList = new ArrayList<>();
    public static Map<Integer, FoodEntity> foodMap = new HashMap<>();

    //添加数据
    static {
        addData(new FoodEntity(1, "土豆", "属茄科多年生草本植物,块茎可供食用,是全球第四大重要的粮食作物。"));
        addData(new FoodEntity(2, "花生", "原名落花生,是我国产量丰富、食用广泛的一种坚果,又名“长生果”、“泥豆”等。"));
        addData(new FoodEntity(3, "番茄", "是茄科番茄属一年生或多年生草本植物,体高0.6-2米,全体生粘质腺毛,有强烈气味,茎易倒伏。"));
    }

    private static void addData(FoodEntity food) {
        foodList.add(food);
        foodMap.put(food.fId, food);
    }

}

2、之后是左边的标题TitleFragment,它是一个继承ListFragment的类,设置了数据适配器时会有列表的效果。

/**
 * Created by JackalTsc on 2016/7/12.
 */
public class TitleFragment extends ListFragment {

    private Callbacks mCallbacks;

    //ListFragment的某项被选中时的回调接口
    public interface Callbacks {
        public void onItemSelected(Integer id);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //ListFragment创建时设置数据适配器 这里FoodUtil.foodList是我们静态设置的数据集合
        setListAdapter(new ArrayAdapter<>(getActivity(),
                android.R.layout.simple_list_item_activated_1,
                android.R.id.text1, FoodUtil.foodList));
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        //Activity与Fragment关联时获取初始化回调
        if (!(activity instanceof Callbacks)) {
            throw new IllegalStateException("BookListFragment 所在的Activity必须实现Callbacks接口!");
        }
        mCallbacks = (Callbacks) activity;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mCallbacks = null; //解除关联时销毁接口
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        //发生点击事件时 传入数据集合对应位置的id 这样即可获取到详情内容
        mCallbacks.onItemSelected(FoodUtil.foodList.get(position).getfId());
    }

}

3、之后是右边的食物详细介绍部分,DetailFragment。

public class DetailFragment extends Fragment {

    private FoodUtil.FoodEntity mFoodEntity;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //创建时如果有fid 那么就根据fid获取对应的详细内容
        if (getArguments().containsKey("fid")) {
            mFoodEntity = FoodUtil.foodMap.get(getArguments().getInt("fid"));
        }

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.view_fragment_fdetail, container, false);

        //如果有数据 就初始化界面数据
        if (mFoodEntity != null) {
            ((TextView) view.findViewById(R.id.tv_title)).setText(mFoodEntity.getfTitle());
            ((TextView) view.findViewById(R.id.tv_detail)).setText(mFoodEntity.getfDetail());
        }

        return view;
    }
}

4、DetailFragment要有一个布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center"
              android:layout_marginLeft="10dp"
              android:layout_marginRight="10dp"
              android:orientation="vertical">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:text="标题"
        android:textAppearance="?android:attr/textAppearanceLarge"/>

    <TextView
        android:id="@+id/tv_detail"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="详情"
        android:textAppearance="?android:attr/textAppearanceMedium"/>
</LinearLayout>

5、最后是Activity的布局部分,layout_activity_fragment3.xml,注意其中的fragment的name属性换成你自己的TitleFragment的完整路径。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="horizontal">

    <fragment
        android:id="@+id/fragment_title"
        android:name="com.jackaltsc.android.mydemoproject.fragment.TitleFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

    <FrameLayout
        android:id="@+id/container_food_detail"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"/>

</LinearLayout>

6、Activity里的代码

/**
 * Created by JackalTsc on 2016/7/12.
 */
public class Fragment3Activity extends Activity implements TitleFragment.Callbacks {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_activity_fragment3);
    }


    @Override
    public void onItemSelected(Integer id) {

        //获取选中时对应的fid
        Bundle bundle = new Bundle();
        bundle.putInt("fid", id);

        //新建Fragment 并填充数据
        DetailFragment detailFragment = new DetailFragment();
        detailFragment.setArguments(bundle);

        //替换详情Fragment部分
        getFragmentManager().beginTransaction()
                .replace(R.id.container_food_detail, detailFragment)
                .commit();

    }
}

这样就可以看到效果了,如果有问题,欢迎私信我。

六、Fragment总结

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,391评论 25 707
  • Fragment概述 Fragment是Activity中用户界面的一个行为或者说是一部分。主要是支持大屏幕上动态...
    wangling90阅读 11,514评论 5 76
  • 什么是你真正值得追求的,什么是你不应舍弃的,有些梦很近,即使触手可及,但始终到达不了,生活给你开了个玩笑,还是你给...
    楠果飘飘阅读 238评论 0 1
  • 今天一天很累,状态也不好,孩子没睡午觉晚上还搞得很晚才睡,一天下来也没挤出属于自己的时间,洗完澡吹好头发躺到床上已...
    韵之加油阅读 161评论 0 1
  • 通过搜集和整理获得史料,进行分析得出能够揭示历史过程、本质及规律的认识。分析的方法主要有历史比较分析法、历史计量分...
    变换之水阅读 5,248评论 0 2