2013年12月3日星期二

Android Fragment 使用详解 - Livingstone

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Android Fragment 使用详解 - Livingstone  阅读原文»

  虽然网上有很多关于Fragment的文章,但我这里还是要写这篇笔记,因为我在编写程序的过程中发现了一个问题,至今未解决,希望得到大家的帮助;
  PS:当我在Fragment中定义一个名为setIndex(int index)的方法之后,运行程序,就会报错(打印的错误信息显示错误为找不到这个Fragment对应的类),但当把这个方法的名称改为其它的名称之后,程序即可正常运行,我的api level为17和18;

先看看Fragment的生命周期方法,其实和Activity基本还是相似的,了解Activity的生命周期,再看Fragment的生命周期方法,也就比较容易理解;

先介绍相关概念

一、fragment通常作为宿主activity UI的一部分, 被作为activity整个view hierarchy的一部分被嵌入,相当于一个轻量级的Activity;

(一)、将一个fragment添加到layout,有两种方法。
1、在Layout文件中,添加一个Fragement对应的节点

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width
="fill_parent"
android:layout_height
="wrap_content"
android:orientation
="vertical" >
<fragment
android:id="@+id/main_mf"
android:name
="com.dbo4.domain.MyFragement"
android:layout_width
="match_parent"
android:layout_height
="match_parent" />
</LinearLayout>
  <fragment> 中的 android:name 属性指定了在layout中具体的Fragment类. 当系统创建这个layout时, 它实例化每一个在layout中指定的fragment,并调用每一个fragment的onCreateView()方法,来获取每一个fragment的layout. 系统将从fragment返回的View直接插入到<fragment>元素所在的地方.
  需要注意的是,每一个fragment都需要一个唯一的标识, 如果activity重启,系统可以用来恢复fragment(并且也可以用来捕获fragment来处理事务,例如移除它.)
  有3种方法来为一个fragment提供一个标识:
  • 为 android:id 属性提供一个唯一ID;
  • 为 android:tag 属性提供一个唯一字符串;
  • 如果以上2个你都没有提供, 系统使用容器view的ID.

2、使用FragmentManager将fragment添加到一个已经存在的ViewGroup
  当activity运行的任何时候, 都可以将fragment添加到它的layout.只需简单的指定一个需要放置fragment的ViewGroup(通常为FrameLayout).FragmentManager提供了一个FragmentTransaction的API,以实现在activity中操作fragment事务(例如添加,移除,或代替一个fragment)。

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction
= fragmentManager.beginTransaction();

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

MyFragment fragment = new MyFragment();
fragmentTransaction.add(R.id.xx_viewgroup, fragment);
fragmentTransaction.commit();

两个参数分别是要放入的ViewGroup, 由resource ID指定和需要添加的fragment。为了使改变生效,还须调用commit()提交事务.

(二)、如果需要Fragment显示菜单,可设置hasOptionsMenu = true;

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

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.add(
"Ma").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(
"Mb").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO
return super.onOptionsItemSelected(item);
}

二、FragmentManager

FragmentManager能够实现管理activity中fragment. 通过调用activity的getFragmentManager()取得它的实例.FragmentManager可以做如下一些事情:
1、使用findFragmentById() (适用于在layout中提供了一个UI的fragment)或findFragmentByTag()(适用于有或没有UI的fragment)获取activity中存在的fragment;
2、将fragment从后台堆栈中弹出, 使用 popBackStack() (模拟用户按下BACK 命令);
3、使用addOnBackStackChangeListener()注册一个监听后台堆栈变化的listener.

三、FragmentTransaction
  FragmentTransaction提供了对fragment进行添加,移除,替换,以及执行其他操作的api。每一个事务都是同时要执行的一套变化.可以在一个给定的事务中设置你想执行的所有变化,使用诸如 add(), remove(), 和 replace(),然后, 要给activity应用事务, 还必须要调用 commit().
  在调用commit()之前, 你可能想调用 addToBackStack(),将事务添加到一个fragment事务的back stack. 这个back stack由activity管理, 并允许用户通过按下 BACK 按键返回到前一个fragment状态.

  举个例子,操作1在将layout中R.id.cont替换Fragment2,并在后台堆栈中保留之前的状态;操作2将R.id.cont替换为Fragment3,但并不保存状态。

ft = fm.beginTransaction();
ft.replace(R.id.cont, new Fragment2());
ft.addToBackStack("f2");
ft.commit();

/************************************/

ft = fm.beginTransaction();
ft.replace(R.id.cont, new Fragment3());
ft.commit();

  通过调用 addToBackStack(), replace事务被保存到back stack, 因此用户可以回退事务,并通过按下BACK按键带回前一个fragment.

 执行上面两个方法执行的Fragment2的生命周期方法为:

  onAttach -- onCreate -- onCreateView -- onActivityCreated -- onStart -- onResume --
  onPause -- onStop -- onDestoryView --
  onCreateView -- onActivityCreated -- onStart -- onResume --

  如果添加多个变化到事务(例如add()或remove())并调用addToBackStack(), 然后在调用commit()之前的所有应用的变化会被作为一个单个事务添加到后台堆栈, BACK按键会将它们一起回退.当执行一个移除fragment的事务时, 如果没有调用 addToBackStack(), 那么当事务提交后, 那个fragment会被销毁,并且用户不能导航回到它。反之,比如当移除一个fragment时,如果调用了 addToBackStack(), 那么fragment会被停止, 如果用户导航回来,它将会被恢复.

  如果添加多个fragment到同一个容器,那么添加的顺序决定了它们在view hierachy中显示的顺序.对于每一个fragment事务, 如果需要添加一个事务动画, 可以通过在提交事务之前调用setTransition()实现.

  实际上,调用 commit() 并不立即执行事务.恰恰相反, 它将事务安排排期, 一旦准备好, 就在activity的UI线程上运行(主线程).如果有必要, 可以在UI线程中调用 executePendingTransactions() 来立即执行由commit()提交的事务. 但这么做通常不必要, 除非事务是其他线程中的job的一个从属.

  只能在activity保存它的状态(当用户离开activity)之前使用commit()提交事务.如果试图在那个点之后提交, 会抛出一个异常.这是因为如果activity需要被恢复, 提交之后的状态可能会丢失.对于觉得可以丢失提交的状况, 使用 commitAllowingStateLoss().

四、Fragment之间的通信
  Fragment之间通信,我分为两种情况,一是两个Fragment同时在一个activity中,二是两个Fragment不同时存在在前台显示;

(一)、同时显示:对于同时添加显示于activity的情况,比较简单,下面是一个例子

>>.布局文件

(最后一篇,开始专心研发).net通用底层搭建 - 浩浩浩浩浩浩  阅读原文»

  之前写过几篇,有朋友说看不懂,有朋友说写的有点乱,自己看了下,的确是需要很认真的看才能看懂整套思路。

  于是写下了这篇。

1.这个底层,使用的是ado.net,微软企业库

2.实体类对应执行sql语句后数据库返回的结果视图你要获取的列,而实体类与数据访问层基类乃是最重要的一环,用到了反射,缓存,拼接语句,高度封装

下面,先看添加操作

1.十个线程,同时执行,各自插库一万条

2.id从原来的程序里加锁处理改为采取数据库自增id,交给数据库处理,想了很久,觉得未来几年都还是单数据库服务器的,所以,用自增吧

执行前的查询

运行网站,

50多秒,每个线程互相等待,数据库帮我们做了并发处理,最后十万条数据57秒全部执行完毕

以下是添加操作的代码

1.页面的

StringBuilder sb = new StringBuilder();
LogManager DBLog;

// LogInfo logInfo1 = new LogInfo();//更新
LogInfo logInfo2= new LogInfo();//插库
int n = 10000;//插库用
int result = -9;



protected void Page_Load(object sender, EventArgs e)
{
DBLog
= new LogManager(typeof(LogInfo));
logInfo2.UserName
= "test";
logInfo2.UserIP
= HT_Context.Current.UserHostAddress;
logInfo2.ScriptName
= Request.RawUrl;
logInfo2.Timestamp
= DateTime.Now;
logInfo2.Source
= "测试数据";
logInfo2.PostString
= "测试数据";
logInfo2.Category
= LogCategory.LogOnFailure;
logInfo2.Message
= "测试数据";
logInfo2.Title
= "测试数据";
logInfo2.Priority
= LogPriority.Highest;
//logInfo1 = DBLog.GetLogById(DBLog.BaseGetMinId<LogInfo>());

if (!Page.IsPostBack)
{
try
{
for (int i = 0; i <10; i++)
{
Thread aa
= null;
aa
= new Thread(new ParameterizedThreadStart(Add));//修改线程名即可,同时20线程
aa.Start(i);
}
while (!result.ToBoolean())
{

}
Response.Write(sb.ToString());
}
catch(Exception ex)
{
Response.Write(ex.Message);

}
}


}
private void Add(object jj)
{
Stopwatch watchH
= new Stopwatch();
watchH.Start();
for (int i = 0; i < n; i++)
{

DBLog.Add(logInfo2);
}
sb.Append(
"我是线程" + jj.ToInt32() + "sql需要的时间为——" + watchH.Elapsed + "<br/>");

result
++;

}

注释部分是用来更新的,方法体外的是全局变量

2.派生数据访问层

/// <summary>
/// 日志数据访问层
/// </summary>
public class LogManager : BaseDal
{
public LogManager() { }

public LogManager(Type type) : base(type) { }

/// <summary>
/// 添加日志
/// </summary>
/// <param name="logInfo">日志信息</param>
public bool Add(LogInfo logInfo)
{
bool result = false;

Parameters parms
=GetParameters(logInfo);
parms.AddOutParameter(
"@Identity",DbType.Int32,int.MaxValue);
int Identity=0;
Identity
= base.ExecuteSql_GetIdentity(parms);

if (Identity>0)
{
SiteCache.Max(SiteCacheKey.CK_MaxID_
+ info_table_name, Identity);
result
=true;
}

return result;
}

3.基类,数据访问层基类,这里还是把整个类贴上会更方便看。采取了缓存策

阅读更多内容

没有评论:

发表评论