概述
 
Fragment表现Activity中UI的一个行为或者一部分。可以将多个fragment组合在一起,放在一个单独的activity中来创建一个多界面区域的UI,并可以在多个activity里重用某一个fragment。把fragment想象成一个activity的模块化区域,有它自己的生命周期,接收属于它自己的输入事件,并且可以在activity运行期间添加和删除.
 
Fragment必须总是被嵌入到一个activity中。它们的生命周期直接受其宿主activity的生命周期影响。 例如:当activity被暂停,那么在其中的所有fragment也被暂停;当activity被销毁,所有隶属于它的fragment也被销毁。然而,当一个activity正在运行时(处于resumed状态),我们可以独立地操作每一个fragment,比如添加或删除它们。当处理这样一种fragment事务时,可以将它添加到activity所管理的back stack —— 每一个activity中的back stack实体都是一个发生过的fragment事务的记录。back stack允许用户通过按下 BACK 按键从一个fragment事务后退(往后导航)。
 
将一个fragment作为activity布局的一部分添加进来时,它处在activity的view hierarchy中的ViewGroup中,并且定义有它自己的view布局。通过在activity的布局文件中声明fragment来插入一个fragment到你的activity布局中,或者可以写代码将它添加到一个已存在的ViewGroup。然而,fragment并不一定必须是activity布局的一部分;如果愿意的话,也可以将一个fragment隐藏在activity的后台工作。
 
本文档描述了如何使用fragment创建应用程序,包括:当被添加到activity的back stack后,fragment如何维护它们的状态。在activity中,与activity和其他fragment共享事件。构建到activity的action bar。以及更多内容。
 
 
设计哲学
    Android在3.0中引入了fragments的概念,主要目的是用在大屏幕设备上——例如平板电脑上,支持更加动态和灵活的UI设计。平板电脑的屏幕要比手机的大得多,有更多的空间来放更多的UI组件,并且这些组件之间会产生更多的交互。Fragment允许这样的一种设计,而不需要你亲自来管理view hierarchy的复杂变化。通过将activity的布局分散到fragment中,可以在运行时修改activity的外观,并在由activity管理的back stack中保存那些变化。
 
例如,一个新闻应用可以在屏幕左侧使用一个fragment来展示一个文章的列表,然后在屏幕右侧使用另一个fragment来展示一篇文章 —— 2个fragment并排显示在相同的一个activity中,并且每一个fragment拥有它自己的一套生命周期回调方法,并且处理它们自己的用户输入事件。因此,用这种方式来取代使用一个activity来选择一篇文章,而另一个activity来阅读文章的模式, 用户可以在相同的activity中选择一篇文章并且阅读, 如图所示: 

 fragment在应用中应当是一个模块化和可重用的组件。即,由于fragment定义了它自己的布局,以及通过使用它自己的生命周期回调方法定义了它自己的行为,因此可以将fragment包含到多个activity中。这点特别重要,因为这允许你将你的用户体验适配到不同的屏幕尺寸。举个例子,你可能会仅当在屏幕尺寸足够大时,在一个activity中包含多个fragment,当不属于这种情况时,会启动另一个单独的、使用不同fragment的activity。
 
    继续之前那个新闻的例子 —— 当运行在一个特别大的屏幕时(例如平板电脑),app可以在Activity A中嵌入2个fragment。然而,在一个正常尺寸的屏幕(例如手机)上,没有足够的空间同时供2个fragment用,因此,Activity A 会仅包含文章列表的fragment,而当用户选择一篇文章时,它会启动Activity B,它包含阅读文章的fragment。因此,应用可以同时支持图1中的2种设计模式。
 
 
创建Fragment
    

要创建一个fragment,必须创建一个 Fragment 的子类(或者继承自一个已存在的它的子类)。 Fragment 类的代码看起来很像Activity。它包含了与activity类似的回调方法,例如onCreate()、onStart()、onPause(),以及onStop()。事实上,如果你准备将一个现成的Android应用转换到使用fragment技术,可能只需简单的将代码从activity的回调函数分别移动到fragment的回调方法。
 
通常,应当至少实现如下的生命周期方法:
  • onCreate()
    当创建fragment时,系统调用此方法。
    在实现代码中,应当初始化想要在fragment中保持的必要组件,当fragment被暂停或者停止后可以恢复。
  • onCreateView()
    fragment第一次绘制它的用户界面的时候,系统会调用此方法。为了绘制fragment的UI,此方法必须返回一个View,这个view是你的fragment布局的根view。如果fragment不提供UI,可以返回null。
  • onPause()
    用户将要离开fragment时,系统调用这个方法作为第一个指示(然而它不总是意味着fragment将被销毁。) 在当前用户会话结束之前,通常应当在这里提交任何应该持久化的变化(因为用户有可能不会返回)。
大多数应用应当为每一个fragment实现至少这3个方法,但是还有一些其他回调方法你也应当用来去处理fragment生命周期的各种阶段。全部的生命周期回调方法将会在后面章节 《处理Fragment生命周期》 中讨论。
 
除了继承基类Fragment,还有一些子类你可能会继承:
  • DialogFragment
    显示一个浮动的对话框。
    用这个类来创建一个对话框,是除了使用Activity类的对话框工具方法之外的一个好的选择,
    因为你可以将一个fragment对话框合并到activity管理的fragment back stack中,允许用户返回到一个之前曾被摒弃的fragment.
  • ListFragment
    显示一个由一个adapter(例如 SimpleCursorAdapter)管理的项目的列表,类似于ListActivity。
    它提供一些方法来管理一个list view,例如onListItemClick()回调来处理点击事件。
  • PreferenceFragment
    显示一个 Preference对象的层次结构的列表,类似于 PreferenceActivity。
    这在为你的应用创建一个“设置”activity时有用处。
 
添加一个用户界面
 
    fragment通常用来作为一个activity的用户界面的一部分,并将它的layout提供给activity。为了给fragment提供一个layout,必须实现onCreateView()回调方法,当到了fragment绘制它自己的layout的时候,Android系统调用它。此方法的实现代码必须返回fragment的layout的根view。
 
注意:如果你的fragment是ListFragment的子类,它的默认实现是返回从onCreateView()返回一个ListView,所以一般情况下不必实现它。
 
从onCreateView()返回的View,也可以从一个xml layout资源文件中读取并生成。为了帮助你这么做,onCreateView() 提供了一个 LayoutInflater 对象。
 

举个例子,这里有一个Fragment的子类,从文件 example_fragment.xml 加载了一个layout:

1 public static class ExampleFragment extends Fragment {
2          @Override
3          public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
4              // Inflate the layout for this fragment
5              return inflater.inflate(R.layout.example_fragment, container, false);
6          }
7      }
 
传入 onCreateView() 的 container 参数是你的fragment layout将要插入的父ViewGroup(来自activity的layout)。savedInstanceState 参数是一个 Bundle,如果fragment是被恢复的,它提供关于fragment的之前的实例的数据。
 
inflate() 方法有3个参数:
  • 想要加载的layout的resource ID。
  • 加载的layout的父ViewGroup。
    传入container是很重要的,目的是为了让系统接受所要加载的layout的根view的layout参数,
    由它将挂靠的父view指定。
  • 布尔值指示在加载期间,展开的layout是否应当附着到ViewGroup (第二个参数)。
    (在这个例子中, 指定了false, 因为系统已经把展开的layout插入到container – 传入true会在最后的layout中创建一个多余的view group。)
 
将fragment添加到activity
 
通常地,fragment为宿主activity提供UI的一部分,被作为activity的整个view hierarchy的一部分被嵌入。 有2种方法你可以添加一个fragment到activity layout:
 
在activity的layout文件中声明fragment
 
可以像使用View一样,为fragment指定layout属性。

例子是一个有2个fragment的activity:

01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03     android:orientation="horizontal"
04     android:layout_width="match_parent"
05     android:layout_height="match_parent">
06      <fragment android:name="com.example.news.ArticleListFragment"
07             android:id="@+id/list"
08             android:layout_weight="1"
09             android:layout_width="0dp"
10             android:layout_height="match_parent" />
11      <fragment android:name="com.example.news.ArticleReaderFragment"
12             android:id="@+id/viewer"
13             android:layout_weight="2"
14             android:layout_width="0dp"
15             android:layout_height="match_parent" />
16 </LinearLayout>
<fragment> 中的 android:name 属性指定了在layout中实例化的Fragment类。
 
当系统创建这个activity layout时,它实例化每一个在layout中指定的fragment,并调用它们的onCreateView()方法,来获取每一个fragment的layout,系统将从fragment返回的 View 直接插入到<fragment>元素所在的地方。
 
注意:每一个fragment都需要一个唯一的标识,如果activity重启,系统可以用来恢复fragment(并且你也可以用来捕获fragment来处理事务,例如移除它。) 
 
有3种方法来为一个fragment提供一个标识:
  • 为 android:id 属性提供一个唯一ID。
  • 为 android:tag 属性提供一个唯一字符串。
  • 如果以上2个你都没有提供,系统使用容器view的ID。
 
撰写代码将fragment添加到一个已存在的ViewGroup。
 
当activity运行的任何时候,都可以将fragment添加到activity layout。只需简单的指定一个需要放置fragment的ViewGroup。为了在你的activity中操作fragment事务(例如添加、移除、或替换一个fragment),必须使用来自 FragmentTransaction 的API。
 
按如下方法,从Activity取得一个 FragmentTransaction 的实例:
 FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
 

然后使用 add() 方法添加一个fragment,指定要添加的fragment, 以及要插入的view。

1 ExampleFragment fragment = new ExampleFragment();
2 fragmentTransaction.add(R.id.fragment_container, fragment);
3 fragmentTransaction.commit();

add()的第一个参数是fragment要放入的ViewGroup,由resource ID指定,第二个参数是需要添加的fragment。一旦用FragmentTransaction作了改变,为了使改变生效,必须调用commit()。

 
 
添加一个无UI的fragment
 
之前的例子展示了对UI的支持,如何将一个fragment添加到activity。然而,也可以使用fragment来为activity提供后台行为而不用展现额外的UI。
 
要添加一个无UI的fragment,需要activity使用 add(Fragment, String) 来添加 fragment (第二个参数为fragment提供一个唯一的字符串"tag",而不是一个view ID)。这么做虽然添加了fragment,但因为它没有关联到一个activity layout中的某个view,所以不会接收到onCreateView()调用。因此不必实现此方法。
 
为fragment提供一个字符串tag并不是专门针对无UI的fragment的 —— 也可以提供字符串tag给有UI的fragment —— 但是如果fragment没有UI,那么这个tag是仅有的标识它的途径。如果随后你想从activity获取这个fragment,需要使用 findFragmentByTag()。
 
 
管理Fragment
要在activity中管理fragment,需要使用FragmentManager。通过调用activity的getFragmentManager()取得它的实例。
 
可以通过FragmentManager做一些事情,包括:
  • 使用findFragmentById() (用于在activity layout中提供UI的fragment)或findFragmentByTag() (适用于有或没有UI的fragment)获取activity中存在的fragment。
  • 使用 popBackStack() (模拟用户按下BACK 命令),将fragment从后台堆栈中弹出。
  • 使用addOnBackStackChangeListener()注册一个监听后台堆栈变化的listener。
 
 
处理Fragment事务
关于在activity中使用fragment的很强的一个特性是:根据用户的交互情况,对fragment进行添加、移除、替换、以及执行其他动作。提交给activity的每一套变化被称为一个事务,使用FragmentTransaction API 处理。我们也可以保存每一个事务到一个activity管理的back stack,允许用户经由fragment的变化往回导航(类似于通过activity往后导航)。
 
从 FragmentManager 获得一个FragmentTransaction的实例:
 FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
 
每一个事务都是同时要执行的一套变化。可以在一个给定的事务中设置你想执行的所有变化,使用诸如 add()、remove()、以及replace()。然后要给activity应用事务,必须调用 commit()。
 
在调用commit()之前,你可能想调用addToBackStack(),将事务添加到一个fragment事务的back stack。这个back stack由activity管理,并允许用户通过按下 BACK 按键返回到前一个fragment状态。
 

举个例子,这里是如何将一个fragment替换为另一个,并在后台堆栈中保留之前的状态:

1 // Create new fragment and transaction
2 Fragment newFragment = new ExampleFragment();
3 FragmentTransaction transaction = getFragmentManager().beginTransaction();
4 // Replace whatever is in the fragment_container view with this fragment,
5 // and add the transaction to the back stack
6 transaction.replace(R.id.fragment_container, newFragment);
7 transaction.addToBackStack(null);
8 // Commit the transaction
9 transaction.commit();
 
在这个例子中,newFragment 替换了当前layout容器中的由R.id.fragment_container标识的fragment。通过调用addToBackStack(),replace事务被保存到back stack,因此用户可以回退事务,并通过按下BACK按键带回前一个fragment。
 
如果添加多个变化到事务(例如add()或remove())并调用addToBackStack(),然后在你调用commit()之前的所有应用的变化会被作为一个单个事务添加到后台堆栈,BACK按键会将它们一起回退。
 
添加变化到 FragmentTransaction的顺序不重要,除以下例外:
  • 必须最后调用 commit()。
  • 如果添加多个fragment到同一个容器,那么添加的顺序决定了它们在view hierarchy中显示的顺序。
当执行一个移除fragment的事务时,如果没有调用 addToBackStack(),那么当事务提交后,那个fragment会被销毁,并且用户不能导航回到它。有鉴于此,当移除一个fragment时,如果调用了 addToBackStack(),那么fragment会被停止,如果用户导航回来,它将会被恢复。
 
提示: 对于每一个fragment事务,你可以应用一个事务动画,通过在提交事务之前调用setTransition()实现。
 
调用 commit() 并不立即执行事务。恰恰相反,它将事务安排排期,一旦准备好,就在activity的UI线程上运行(主线程)。如果无论如何有必要,你可以从你的UI线程调用 executePendingTransactions() 来立即执行由commit()提交的事务。但这么做通常不必要,除非事务是其他线程中的job的一个从属。
 
警告: 你只能在activity保存它的状态(当用户离开activity)之前使用commit()提交事务。
 
如果你试图在那个点之后提交,会抛出一个异常。这是因为如果activity需要被恢复,提交之后的状态可能会丢失。对于你觉得可以丢失提交的状况,使用 commitAllowingStateLoss()。
 
 
与Activity通信
尽管Fragment被实现为一个独立于Activity的对象,并且可以在多个activity中使用,但一个给定的fragment实例是直接绑定到包含它的activity的。特别的,fragment可以使用 getActivity() 访问Activity实例,并且容易地执行比如在activity layout中查找一个view的任务。
View listView = getActivity().findViewById(R.id.list);
同样地,activity可以通过从FragmentManager获得一个到Fragment的引用来调用fragment中的方法,使用 findFragmentById() 或 findFragmentByTag()。
 ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
 
 
为Activity创建事件回调方法
 
在一些情况下,你可能需要fragment与activity分享事件。一个好的方法是在fragment中定义一个回调的interface,并要求宿主activity实现它。当activity通过interface接收到一个回调,必要时它可以和在layout中的其他fragment分享信息。
 
例如,如果一个新的应用在activity中有2个fragment —— 一个用来显示文章列表(framgent A),另一个显示文章内容(fragment B) —— 然后 framgent A必须告诉activity何时一个list item被选中,然后它可以告诉fragment B去显示文章。
 

在这个例子中,OnArticleSelectedListener 接口在fragment A中声明:

1 public static class FragmentA extends ListFragment {
2      ...
3      // Container Activity must implement this interface
4     public interface OnArticleSelectedListener {
5          public void onArticleSelected(Uri articleUri);
6      }
7      ...
8 }

然后fragment的宿主activity实现 OnArticleSelectedListener 接口,并覆写 onArticleSelected() 来通知fragment B,从fragment A传来了事件。为了确保宿主activity实现这个接口,fragment A的 onAttach() 回调方法(当添加fragment到activity时由系统调用)通过将作为参数传入onAttach()的Activity做类型转换来实例化一个OnArticleSelectedListener实例。

01 public static class FragmentA extends ListFragment {
02      OnArticleSelectedListener mListener;
03      ...
04      @Override
05      public void onAttach(Activity activity) {
06          super.onAttach(activity);
07          try {
08              mListener = (OnArticleSelectedListener) activity;
09          catch (ClassCastException e) {
10              throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
11          }
12      }
13      ...
14 }

如果activity没有实现接口,fragment会抛出 ClassCastException 异常。正常情形下,mListener成员会保持一个到activity的OnArticleSelectedListener实现的引用,因此fragment A可以通过调用在OnArticleSelectedListener接口中定义的方法分享事件给activity。例如,如果fragment A是一个 ListFragment的子类,每次用户点击一个列表项,系统调用 在fragment中的onListItemClick(),然后后者调用 onArticleSelected() 来分配事件给activity。

01 public static class FragmentA extends ListFragment {
02      OnArticleSelectedListener mListener;
03      ...
04      @Override
05      public void onListItemClick(ListView l, View v, int position, long id) {
06          // Append the clicked item's row ID with the content provider Uri
07         Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
08          // Send the event and Uri to the host activity
09         mListener.onArticleSelected(noteUri);
10      }
11      ...
12 }
传给 onListItemClick() 的 id 参数是被点击的项的行ID,activity(或其他fragment)用来从应用的 ContentProvider 获取文章。
 
 
添加项目到Action Bar
 
你的fragment可以通过实现 onCreateOptionMenu() 提供菜单项给activity的选项菜单(以此类推, Action Bar也一样)。为了使这个方法接收调用,无论如何,你必须在 onCreate() 期间调用 setHasOptionsMenu() 来指出fragment愿意添加item到选项菜单(否则, fragment将接收不到对 onCreateOptionsMenu()的调用)。
 
随后从fragment添加到Option菜单的任何项,都会被追加到现有菜单项的后面。当一个菜单项被选择,fragment也会接收到 对 onOptionsItemSelected() 的回调。也可以在你的fragment layout中通过调用 registerForContextMenu() 注册一个view来提供一个环境菜单。当用户打开环境菜单,fragment接收到一个对 onCreateContextMenu() 的调用。当用户选择一个项目,fragment接收到一个对onContextItemSelected() 的调用。
 
注意:尽管你的fragment会接收到它所添加的每一个菜单项被选择后的回调,但实际上当用户选择一个菜单项时,activity会首先接收到对应的回调。如果activity的on-item-selected回调函数实现并没有处理被选中的项目。然后事件才会被传递到fragment的回调。
 
这个规则适用于选项菜单和环境菜单。
 
 
处理Fragment生命周期

管理fragment的生命周期,大多数地方和管理activity生命周期很像。和activity一样,fragment可以处于3种状态:
  • Resumed
    在运行中的activity中fragment可见。
  • Paused
    另一个activity处于前台并拥有焦点,但是这个fragment所在的activity仍然可见(前台activity局部透明或者没有覆盖整个屏幕)。
  • Stopped
    要么是宿主activity已经被停止,要么是fragment从activity被移除但被添加到后台堆栈中。
    停止状态的fragment仍然活着(所有状态和成员信息被系统保持着)。然而,它对用户不再可见,并且如果activity被杀死,它也会被杀死。
仍然和activity一样,可以使用Bundle保持fragment的状态,万一activity的进程被杀死,并且当activity被重新创建的时候,需要恢复fragment的状态时就可以用到。可以在fragment的 onSaveInstanceState() 期间保存状态,并可以在 onCreate()、onCreateView() 或 onActivityCreated() 期间恢复它。
 
生命周期方面,activity和fragment之间最重要的区别是各自如何在它的后台堆栈中储存。默认地,activity在停止后,它会被放到一个由系统管理的用于保存activity的后台堆栈。(因此用户可以使用BACK按键导航回退到它)。
 
然而,当你在一个事务期间移除fragment时,只有显式调用addToBackStack()请求保存实例,才会被放到一个由宿主activity管理的后台堆栈。
 
另外,管理fragment的生命周期和管理activity生命周期非常类似。因此,《管理activity生命周期》一章中的相同实践也同样适用于fragment。你需要理解的是,activity的生命期如何影响fragment的生命期.
 
 
与activity生命周期的协调工作
 
fragment所生存的activity的生命周期,直接影响fragment的生命周期,每一个activity的生命周期的回调行为都会引起每一个fragment中类似的回调。
 
例如,当activity接收到onPause()时,activity中的每一个fragment都会接收到onPause()。
 
为了执行例如创建和销毁fragment的UI的动作,Fragment有一些额外的生命周期回调方法,它们是处理与activity交互的唯一渠道。这些额外的回调方法是:
  • onAttach()
    当fragment被绑定到activity时被调用(Activity会被传入)。
  • onCreateView()
    创建和fragment关联的view hierarchy时被调用。
  • onActivityCreated()
    当activity的onCreate()方法返回时被调用。
  • onDestroyView()
    当和fragment关联的view hierarchy被移除时调用。
  • onDetach()
    当fragment从activity解除关联时被调用。
fragment生命周期的流程,以及宿主activity对它的影响,在图3中显示。在这个图中,可以看到activity依次的每个状态是如何决定fragment可能接收到的回调方法。例如,当activity接收到它的onCreate(),activity中的fragment接收到最多是onActivityCreated()。
 
一旦activity到达了resumed状态,你可以自由地在activity添加和移除fragment。因此,仅当activity处于resumed状态时,fragment的生命周期才可以独立变化。
无论如何,当activity离开resumed状态,fragment再次被activity带入其生命周期过程。

【Android UI】:Fragment官方文档的更多相关文章

  1. Google android开发者 中国官方文档开放了呀

    Google官方开发文档地址 包括 android , android TV

  2. Android外部存储 - 官方文档解读

    预备知识:External Storage Technical Information 摘要: "The WRITE_EXTERNAL_STORAGE permission must onl ...

  3. android自定义控件(一) 官方文档的翻译

    构建自定义组件 Android中,你的应用程序程序与View类组件有着一种固定的联系,例如按钮(Button).文本框(TextView),可编辑文本框(EditText),列表框(ListView) ...

  4. Google Android官方文档进程与线程(Processes and Threads)翻译

    android的多线程在开发中已经有使用过了,想再系统地学习一下,找到了android的官方文档,介绍进程与线程的介绍,试着翻译一下. 原文地址:http://developer.android.co ...

  5. Android 线性布局(LinearLayout)相关官方文档 - 指南部分

    Android 线性布局(LinearLayout)相关官方文档 - 指南部分 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用 ...

  6. [翻译]Android官方文档 - 通知(Notifications)

    翻译的好辛苦,有些地方也不太理解什么意思,如果有误,还请大神指正. 官方文档地址:http://developer.android.com/guide/topics/ui/notifiers/noti ...

  7. Android 触摸手势基础 官方文档概览

    Android 触摸手势基础 官方文档概览 触摸手势检测基础 手势检测一般包含两个阶段: 1.获取touch事件数据 2.解析这些数据,看它们是否满足你的应用所支持的某种手势. 相关API: Moti ...

  8. Android 触摸手势基础 官方文档概览2

    Android 触摸手势基础 官方文档概览 触摸手势检测基础 手势检测一般包含两个阶段: 1.获取touch事件数据 2.解析这些数据,看它们是否满足你的应用所支持的某种手势. 相关API: Moti ...

  9. Android的AutoCompleteTextView在API17高版本添加的setText函数在低版本系统居然能正常调用?官方文档是不是不靠谱了?

    官方文档:https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#setText(java.l ...

随机推荐

  1. Device eth0 does not seem to be present, delaying initialization. 问题

    今天在复制vmware的时候 出现网卡无法启动 报错显示 Device eth0 does not seem to be present, delaying initialization. 这个错误原 ...

  2. DIOCP之开发流程图之Client

    本次分析开发流程图采用的是DIOCP群里的群友[彩蛋]所给的DEMO,依然是win7的画图作品. 本人分析认为:学习网络开发不同本地开发,首先你应该知道完整的开发流程即网络程序运行的先后顺序,有个整体 ...

  3. What is “:-!!” in C code?

    stackoverflow上看到的这个问题,觉得挺有趣,顺手记下来. 楼主提问: I bumped into this strange macro code in /usr/include/linux ...

  4. http 错误 500.21

    出现这个错误一般都是.net Framework 在iis中安装错误 这个时候需要重新安装iis .netframework 4.0框架 我的解决方案如下: 在cmd中以管理员身份运行->%wi ...

  5. PHP开启cURL功能

    PHP开启cURL功能 在php.ini中开启 确定php扩展目录下有php_curl.dll类库 在php.int中找到扩展库所在目录 判断目录下是否有php_curl.dll 没有的话去搜索下载 ...

  6. SQL SERVER 分页查询

    Sqlserver数据库分页查询一直是Sqlserver的短板. 但现在不是了. 自从有了它. 一口气上十楼. 官方语法说明示例: https://technet.microsoft.com/zh-c ...

  7. hdu 1849(Rabbit and Grass) 尼姆博弈

    Rabbit and Grass Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  8. 关于MySQL的CRUD操作

    一.清除mysql表中数据 delete from 表名; truncate table 表名; 不带where参数的delete语句可以删除mysql表中所有内容,使用truncate table也 ...

  9. 数据库事务中的隔离级别和锁+spring Transactional注解

    数据库事务中的隔离级别和锁 数据库事务在后端开发中占非常重要的地位,如何确保数据读取的正确性.安全性也是我们需要研究的问题.ACID首先总结一下数据库事务正确执行的四个要素(ACID): 原子性(At ...

  10. H5学习系列之Geolocation API

    获取位置信息途径: 1.IP地址地理定位数据 2.GPS地理定位数据 3.WI-FI地理定位数据 4.手机地理定位数据 无废话直接上重点:navigator.geolocation对象就是获取地理位置 ...