Android开发学习教程(26)- Android Fragment(碎片)
—— 尽吾志也,而不能至者,所以无悔矣
什么是单窗格或多窗格布局?
面板或窗格代表用户界面的一部分 。术语窗格是一个通用术语,用于描述根据实际可用空间将多个视图组合成一个复合视图的概念。
如果没有足够的可用空间,则仅显示一个面板。这通常称为单窗格布局。
如果有更多可用空间,可以显示多个面板。
什么是Fragment?
Fragment是 Android 中的一个组件,Fragment依赖于Activity运行,但有自己的生命周期,通常有自己的用户界面。
Android设备存在各种屏幕尺寸和密度。Fragment简化了组件在不同布局及其逻辑中的重用。你可以为手机构建单窗格布局,为平板电脑构建多窗格布局。你还可以使用Fragment来支持智能手机上横向和纵向的不同布局。
因为可以从Activity中动态添加和删除Fragment。所以Fragment的使用允许设计非常灵活的用户界面。
典型示例是Activity中的项目列表。在平板电脑上,如果单击项目,你会立即在右侧的同一屏幕上看到详细信息。而在手机上,你需要跳转到新的详细信息屏幕。这在下图中进行了描述。
Fragment的用法
有两种方法可以将Fragmtn添加到Activity中:动态添加和静态添加。
静态添加
要静态添加Fragment,只需将Fragment嵌入到活动的 xml 布局文件中:
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:baselineAligned
=
"false"
android:orientation
=
"horizontal"
>
<
fragment
android:id
=
"@+id/listFragment"
class
=
"com.example.myapplication1.MyListFragment"
android:layout_width
=
"0dp"
android:layout_height
=
"match_parent"
android:layout_weight
=
"1"
android:tag
=
"listFragment"
tools:layout
=
"@layout/fragment_rsslist_overview"
/>
<
fragment
android:id
=
"@+id/detailFragment"
class
=
"com.example.myapplication1.DetailFragment"
android:layout_width
=
"0dp"
android:layout_height
=
"match_parent"
android:layout_weight
=
"2"
android:tag
=
"detailFragment"
tools:layout
=
"@layout/fragment_rssitem_detail"
/>
</
LinearLayout
>
import
android.os.Bundle;
import
androidx.appcompat.app.AppCompatActivity;
public
class
MainActivityByXml
extends
AppCompatActivity
implements
MyListFragment.OnItemSelectedListener {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_byxml);
}
@Override
public
void
onRssItemSelected(String str) {
// DetailFragment fragment = (DetailFragment) getSupportFragmentManager().findFragmentById(R.id.detailFragment);
DetailFragment fragment = (DetailFragment) getSupportFragmentManager().findFragmentByTag(
"detailFragment"
);
fragment.setText(str);
}
}
动态添加
动态添加允许你在Activity中添加、删除和替换片段。
<?
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"
>
<
FrameLayout
android:id
=
"@+id/listcontainer"
android:layout_width
=
"0dp"
android:layout_height
=
"match_parent"
android:layout_weight
=
"1"
/>
<
FrameLayout
android:id
=
"@+id/detailscontainer"
android:layout_width
=
"0dp"
android:layout_height
=
"match_parent"
android:layout_weight
=
"1"
/>
</
LinearLayout
>
import
android.os.Bundle;
import
androidx.appcompat.app.AppCompatActivity;
import
androidx.fragment.app.FragmentManager;
import
androidx.fragment.app.FragmentTransaction;
public
class
MainActivityByManager
extends
AppCompatActivity
implements
MyListFragment.OnItemSelectedListener {
private
FragmentManager fragmentManager;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_bymanager);
instanceFragmentManager();
}
private
void
instanceFragmentManager() {
// 获取FragmentManger
fragmentManager = getSupportFragmentManager();
// 把Fragment add到FrameLayout容器中,并设置此add进来的Fragment的Tag为MyListFragment
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.listcontainer,
new
MyListFragment(),
"MyListFragment"
);
fragmentTransaction.add(R.id.detailscontainer,
new
DetailFragment(),
"DetailFragment"
);
fragmentTransaction.commit();
// // replace Fragment
// FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// fragmentTransaction.replace(R.id.detailscontainer, new DetailFragment());
// fragmentTransaction.commit();
//
// // remove Fragment
// Fragment fragment = fragmentManager.findFragmentById(R.id.detailscontainer);
// FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// fragmentTransaction.remove(fragment);
// fragmentTransaction.commit();
}
@Override
public
void
onRssItemSelected(String str) {
// 使用 findFragmentById 或者 findFragmentByTag都行,建议还是使用 findFragmentByTag,避免逻辑层与视图层耦合
DetailFragment fragment = (DetailFragment) getSupportFragmentManager().findFragmentById(R.id.detailscontainer);
// DetailFragment fragment = (DetailFragment) getSupportFragmentManager().findFragmentByTag("DetailFragment");
fragment.setText(str);
}
}
import
android.content.Context;
import
android.os.Bundle;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.Button;
import
androidx.fragment.app.Fragment;
public
class
MyListFragment
extends
Fragment
implements
View.OnClickListener {
private
OnItemSelectedListener listener;
@Override
public
View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rsslist_overview, container,
false
);
view.findViewById(R.id.button1).setOnClickListener(
this
);
view.findViewById(R.id.button2).setOnClickListener(
this
);
view.findViewById(R.id.button3).setOnClickListener(
this
);
view.findViewById(R.id.button4).setOnClickListener(
this
);
view.findViewById(R.id.button5).setOnClickListener(
this
);
return
view;
}
@Override
public
void
onClick(View v) {
updateDetail(((Button) v).getText().toString());
}
public
interface
OnItemSelectedListener {
void
onRssItemSelected(String str);
}
@Override
public
void
onAttach(Context context) {
super
.onAttach(context);
if
(context
instanceof
OnItemSelectedListener) {
listener = (OnItemSelectedListener) context;
}
else
{
throw
new
ClassCastException(context.toString() +
" must implemenet MyListFragment.OnItemSelectedListener"
);
}
}
@Override
public
void
onDetach() {
super
.onDetach();
listener =
null
;
}
private
void
updateDetail(String str) {
listener.onRssItemSelected(str);
}
}
import
android.os.Bundle;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.TextView;
import
androidx.fragment.app.Fragment;
public
class
DetailFragment
extends
Fragment {
@Override
public
View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rssitem_detail, container,
false
);
return
view;
}
public
void
setText(String text) {
TextView view = (TextView) getView().findViewById(R.id.detailsText);
view.setText(text);
}
}
查找Fragment实例
通常我们需要在Activity中查找Fragment实例用于操作Fragment。有几种方法可以查找现有的Fragment实例:
1. 通过ID查找即findFragmentById
2. 通过Tag查找即findFragmentByTag
下面更详细地概述了每种方法。
按ID查找即findFragmentById
如果是通过静态添加的,这里的ID就表示静态xml中fragment标签的id,例如上面示例中的findFragmentById(R.id.detailFragment)。如果是通过动态添加的(大部分时候都是此方式),ID则表示Fragment被add上去的那个布局的ID,例如上面示例中的findFragmentById(R.id.detailscontainer)。
按Tag查找即findFragmentById
Tag可以理解为每一个Fragment的唯一标识符。如果是通过静态添加的,这里的Tag就表示静态xml中fragment标签的android:tag值,例如上面示例中的findFragmentByTag(“detailFragment”)。如果是通过动态添加的(大部分时候都是此方式),ID则表示Fragment被add上去时指定的Tag字符串,例如上面示例中的fragmentTransaction.add(R.id.detailscontainer, new DetailFragment(), “DetailFragment”)、findFragmentByTag(“DetailFragment”)。
Activity Fragment通信
Fragment通常应该只与它们的父Activity通信。通过父Activity来管理与其他Fragment的交互。Activity可以看做是每个Fragment之间交互的控制器。
Fragment和Activity可以通过三种方式进行通信:
1. 通过Bundle传参 – Activity 可以构造一个片段并设置参数
2. 通过调用Fragment成员方法 – Activity 可以调用Fragment实例上的方法
3. 通过接口回调 – Fragment可以通过接口在Activity上触发侦听器事件
1. 通过Bundle传参
在某些情况下,Fragment可能希望接受某些参数。一种常见的模式是创建一个静态newInstance方法来创建带有参数的Fragment:
public
class
DemoFragment
extends
Fragment {
public
static
DemoFragment newInstance(
int
someInt, String someTitle) {
DemoFragment fragmentDemo =
new
DemoFragment();
Bundle args =
new
Bundle();
args.putInt(
"someInt"
, someInt);
args.putString(
"someTitle"
, someTitle);
fragmentDemo.setArguments(args);
return
fragmentDemo;
}
}
这会将某些参数设置到 Fragment 中,之后可以在 onCreate 中使用以下方法访问参数:
public
class
DemoFragment
extends
Fragment {
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
int
SomeInt = getArguments().getInt(
"someInt"
,
0
);
String someTitle = getArguments().getString(
"someTitle"
,
""
);
}
}
在 Activity 中动态加载片段:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
DemoFragment fragmentDemo = DemoFragment.newInstance(
5
,
"my title"
);
ft.replace(R.id.your_placeholder, fragmentDemo);
ft.commit();
2. 通过调用Fragment成员方法
如上面示例中的fragment.setText(str)
3. 通过接口回调
如上面示例中的onRssItemSelected回调
了解FragmentManager
FragmentManager负责Fragment的所有运行时管理,包括添加、删除、隐藏、显示或以其他方式在Fragment之间导航。重要的可用方法概述如下:
addOnBackStackChangedListener:为片段返回堆栈的更改添加一个新的侦听器。
beginTransaction():创建一个新事务以在运行时更改片段。
findFragmentById(
int
id):通过通常从活动 XML 布局中扩展的 id 查找片段。
findFragmentByTag(String tag):通常为运行时添加的片段按标签查找片段。
popBackStack():从 backstack 中删除一个片段。
executePendingTransactions():强制应用已提交的事务。
Fragment生命周期
上面我们说过,Fragment虽然依赖于Activity运行,但是Fragment有它自己的生命周期
onAttach():当片段连接到活动时调用。
onCreate():被调用来进行片段的初始创建。
onCreateView():一旦 Fragment 应该膨胀视图,Android 就会调用它。
onViewCreated():在之后调用onCreateView()并确保片段的根视图是non-
null
. 任何视图设置都应该在这里进行。例如,查看查找、附加侦听器。
onActivityCreated():当宿主活动完成其onCreate()方法时调用。
onStart():一旦片段准备好显示在屏幕上,就会被调用。
onResume():分配“昂贵”的资源,例如注册位置、传感器更新等。
onPause():释放“昂贵”的资源。提交任何更改。
onDestroyView():当片段的视图被销毁时调用,但片段仍然保留在周围。
onDestroy():当片段不再使用时调用。
onDetach():当片段不再连接到活动时调用。
通常在onCreateView中设置视图,onCreate用于任何数据初始化,onActivityCreated用于设置只有在 Activity 完全创建后才能发生的事情。
这是一个如何使用各种片段生命周期事件的示例:
public
class
SomeFragment
extends
Fragment {
ThingsAdapter adapter;
FragmentActivity listener;
// 此事件在创建Fragment或任何视图之前最先触发,当Fragment与Activity关联时,将调用onAttach方法。
@Override
public
void
onAttach(Context context) {
super
.onAttach(context);
if
(context
instanceof
Activity){
this
.listener = (FragmentActivity) context;
}
}
// 此事件在为Fragment创建视图之前触发,在创建或重新创建Fragment时,会调用onCreate方法。
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
ArrayList<Thing> things =
new
ArrayList<Thing>();
adapter =
new
ThingsAdapter(getActivity(), things);
}
// 当Fragment应该动态地或通过XML布局创建其视图对象层次结构时,调用onCreateView方法。
@Override
public
View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
return
inflater.inflate(R.layout.fragment_some, parent,
false
);
}
// 此事件在onCreateView()之后不久触发。只有从onCreateView()返回的视图非空时,才会调用onViewCreated()。任何视图设置都建议在这里进行。
@Override
public
void
onViewCreated(View view, Bundle savedInstanceState) {
super
.onViewCreated(view, savedInstanceState);
ListView lv = (ListView) view.findViewById(R.id.lvSome);
lv.setAdapter(adapter);
}
// 此方法在父Activity的onCreate()方法完成后调用。
@Override
public
void
onActivityCreated(Bundle savedInstanceState) {
super
.onActivityCreated(savedInstanceState);
}
// 当Fragment与Activity失去关联时,将调用此方法。保存在onAttach中的任何引用都应在此处为null,以防止内存泄漏。
@Override
public
void
onDetach() {
super
.onDetach();
this
.listener =
null
;
}
}
源码链接:https://yunjunet.cn/876809.html