Android框架之路——Fragmentation的使⽤(流式交互Demo)
简介:
YoKey⼤神的Fragment库Fragmentation,主要⽤于现在App经常需要实现的单Activity+多Fragment以及多Activity+多
Fragment的形式架构。同时最最重要的是,它帮助我们封装了很多好⽤的⽅法,解决了⼀些官⽅Fragment库中存在的⼀些Bug。
我在学习做⼀款有关Ble蓝⽛防丢器的App时想要尝试以单Activity+多Fragment的架构去实现,恰好可以使⽤这个库,也就⽪⽑的研究了⼀下。之前我是通过ViewPager去管理多个Fragment的进出,后来还是抛弃这种⽅式,因为确实不太合理。所以,⽤了
Fragmentation这个库,还是⾮常不错的。
⼤神的话:
使⽤教程:
1. 添加依赖
compile 'me.yokeyword:fragmentation:最新版'
我的是
compile 'me.yokeyword:fragmentation:0.10.3'
2. 单Activity需要继承⾃SupportActivity,多Fragment都继承⾃SupportFragment。可以在AndroidStudio中使⽤Ctrl+H快捷键查
看类的继承结构,如下所⽰,SupportActivity继承⾃AppCompatActivity,爷爷正好是FragmentActivity,SupportFragment继承⾃V4包下的Fragment,所以基本不影响我们使⽤:
3. ⼀些API的使⽤(对照流式交互Demo)
1. 先看⼀下demo的整体效果
2. 这⾥先贴出单Activity的代码,代码内我添加了⼀些注释,基本可以了解清楚MainActivity 中做了哪些事情。这⾥可以列出⽐较
重要的Api:
1. 装载根Fragment,⼀般在saveInstanceState==null时load;
loadRootFragment(R.id.fl_container, wInstance()); //activity初始加载HomeFragment
2. 在Activity中注册所有Fragment⽣命周期的回调函数,可以监听该Activity下的所有Fragment的18个 ⽣命周期⽅
法,这⾥监听的是Fragment的创建:
registerFragmentLifecycleCallbacks(new FragmentLifecycleCallbacks() {
/
/ 当有Fragment Create时回调,打印log
@Override
public void onFragmentCreated(SupportFragment fragment, Bundle savedInstanceState) {
Log.i("MainActivity", "onFragmentCreated--->" + Class().getSimpleName());
Log.i("MainActivity", "onFragmentCreated--->" + Class().getSimpleName());
}
});
3. 在Activity中重写onCreateFragmentAnimator()⽅法来设置所有Fragment的出场消失动画,如果在某个单独的
Fragment中复写该⽅法,则只单独对该Fragment有效,这⾥可以详细的看⼀下;
4. 通过重写⽗类SupportActivity的onBackPressedSupport()⽅法,可以轻松的实现按下⼿机返回键要实现的功能,
在下⾯的demo源码中给出了详细的注释,这⾥也可以详细的看⼀下;
5. 启动跳转Fragment,
// 启动新的Fragment,启动者和被启动者是在同⼀个栈的
start(SupportFragment fragment)
// 以某种启动模式,启动新的Fragment
start(SupportFragment fragment, int launchMode)
// 启动新的Fragment,并能接收到新Fragment的数据返回
startForResult(SupportFragment fragment,int requestCode)
// 启动⽬标Fragment,并关闭当前Fragment;不要尝试pop()+start(),动画会有问题
startWithPop(SupportFragment fragment)
6. 出栈,移出某个Fragment
/
/ 当前Fragment出栈(在当前Fragment所在栈内pop)
pop();
// 出栈某⼀个Fragment栈内之上的所有Fragment
popTo(Class fragmentClass/String tag, boolean includeSelf);
// 出栈某⼀个Fragment栈内之上的所有Fragment。如果想出栈后,紧接着.beginTransaction()开始⼀个新事务,
//请使⽤下⾯的⽅法,防⽌多事务连续执⾏的异常
popTo(Class fragmentClass, boolean includeSelf, Runnable afterTransaction);
7. 查获取某⼀Fragment
// 获取所在栈内的栈顶Fragment
getTopFragment();
// 获取当前Fragment所在栈内的前⼀个Fragment
getPreFragment();
// 获取所在栈内的某个Fragment,可以是xxxFragment.Class,也可以是tag
findFragment(Class fragmentClass/String tag);
8. 防⽌动画卡顿,可以先让其加载完Fragment的转场动画,然后继续实现⼀些繁琐的业务逻辑。在Fragment中重写
onEnterAnimationEnd(Bundle saveInstanceState)⽅法,在这个⽅法⾥继续执⾏⼀些繁琐操作。通常可以采取这样的⼀种模式:
public View onCreateView(...) {
...
// 这⾥仅给⼀些findViewById等轻量UI的操作
initView();
return view;
}
@Override
protected void onEnterAnimationEnd(Bundle saveInstanceState) {
// 这⾥设置Listener、各种Adapter、请求数据等等
initLazyView();
}
9. Fragment实例调⽤startForResult(SupportFragment fragment,int requestCode)⽤来Fragment之间返回数
据,类似于Activity的startActivityForResult()。⼤致⽤法如下;
据,类似于Activity的startActivityForResult()。⼤致⽤法如下;
public class DetailFragment extends SupportFragment{
private void goDetail(){
// 启动ModifyDetailFragment
wInstance(mTitle), REQ_CODE);
}
// ModifyDetailFragment调⽤setFragmentResult()后,在其出栈时,会回调该⽅法
@Override
public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
android学习教程if (requestCode == REQ_CODE && resultCode == RESULT_OK ) {
// 在此通过Bundle data 获取返回的数据
}
}
}
public class ModifyTitleFragment extends SupportFragment{
// 设置传给上个Fragment的bundle数据
private void setResult(){
Bundle bundle = new Bundle();
bundle.putString("title", "xxxx");
setFramgentResult(RESULT_OK, bundle);
}
}
10. 以某种启动模式启动Fragment:start(SupportFragment fragment, int launchMode)。下⾯是以SingleTask模
式重新启动⼀个已存在的Fragment的标准代码: ⽐如:HomeFragment->B Fragment->C Fragment,C
Fragment以SingleTask模式重新启动HomeFragment。在被以SingleTask模式启动的Fragment中重写
onNewBundle()⽅法,可以接收到SINGLETASK/SINGTOP启动模式传递的数据。类似于Activity中的
onNewIntent()。
// 任意同栈内的Fragment中:
HomeFragment fragment = findFragment(HomeFragment.class);
Bundle newBundle = new Bundle();
newBundle.putString("from", "主页-->来⾃:" + Class().getSimpleName());
fragment.putNewBundle(newBundle);
// 在栈内的HomeFragment以SingleTask模式启动(即在其之上的Fragment会出栈)
start(fragment, SupportFragment.SINGLETASK);
public class HomeFragment extends SupportFragment{
@Override
protected void onNewBundle(Bundle newBundle){
// 在此可以接收到SINGLETASK/SINGTOP启动模式传递的数据类似Activity中的onNewIntent()
Toast.makeText(_mActivity, String("from"), Toast.LENGTH_SHORT).show();
}
}
附:MainActivity .java
/**
* 流程式demo tip: 多使⽤右上⾓的"查看栈视图"
* Created by YoKeyword on 16/1/29.
*/
public class MainActivity extends SupportActivity
implements NavigationView.OnNavigationItemSelectedListener, BaseMainFragment.OnFragmentOpenDrawerListener
, LoginFragment.OnLoginSuccessListener, SwipeBackSampleFragment.OnLockDrawLayoutListener {
public static final String TAG = SimpleName();
// 再点⼀次退出程序时间设置
private static final long WAIT_TIME = 2000L;
private long TOUCH_TIME = 0; //点击返回键时间
private DrawerLayout mDrawer;
private NavigationView mNavigationView;
private TextView mTvName; // NavigationView上的名字
private ImageView mImgNav; // NavigationView上的头像
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
loadRootFragment(R.id.fl_container, wInstance()); //activity初始加载HomeFragment
}
initView();
/
/在Activity中注册所有Fragment⽣命周期的回调函数,可以监听该Activity下的所有Fragment的18个⽣命周期⽅法 registerFragmentLifecycleCallbacks(new FragmentLifecycleCallbacks() {
// 当有Fragment Create时回调,打印log
@Override
public void onFragmentCreated(SupportFragment fragment, Bundle savedInstanceState) {
Log.i("MainActivity", "onFragmentCreated--->" + Class().getSimpleName());
}
});
}
//设置所有Fragment的转场动画
@Override
public FragmentAnimator onCreateFragmentAnimator() {
// 设置默认Fragment动画默认竖向(和安卓5.0以上的动画相同)
CreateFragmentAnimator();
// 设置横向(和安卓4.x动画相同)
// return new DefaultHorizontalAnimator();
// 设置⾃定义动画
// return new FragmentAnimator(enter,exit,popEnter,popExit);
}
private void initView() {
mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, mDrawer, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
/
/ mDrawer.setDrawerListener(toggle);
toggle.syncState();
mNavigationView = (NavigationView) findViewById(R.id.nav_view);
mNavigationView.setNavigationItemSelectedListener(this); //设置NavigationItem的点击事件
mNavigationView.setCheckedItem(R.id.nav_home); //默认初始设置⾸页被选中
//绑定NavigationView的headview⾥的控件
//设置点击事件登录(延时250ms跳转LoginFragment)
LinearLayout llNavHeader = (LinearLayout) HeaderView(0);
mTvName = (TextView) llNavHeader.findViewById(R.id.tv_name);
mImgNav = (ImageView) llNavHeader.findViewById(R.id.img_nav);
llNavHeader.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDrawer.closeDrawer(GravityCompat.START);
mDrawer.postDelayed(new Runnable() {
@Override
public void run() {
goLogin();
goLogin();
}
}, 250);
}
});
}
//设置⼿机返回键事件
//如果侧边栏打开则关闭,否则:如果栈顶的Fragment是BaseMainFragment的实例,那么先设置mNavigationView的nav_home被选中 // 同时如果栈中不⽌⼀个Fragment,就出栈⼀个,否则提⽰是否要再按⼀次退出。在WAIT_TIME时间内再按则退出。 @Override
public void onBackPressedSupport() {
if (mDrawer.isDrawerOpen(GravityCompat.START)) {
mDrawer.closeDrawer(GravityCompat.START);
} else {
Fragment topFragment = getTopFragment();
// 主页的Fragment
if (topFragment instanceof BaseMainFragment) {
mNavigationView.setCheckedItem(R.id.nav_home);
}
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
pop();
} else {
if (System.currentTimeMillis() - TOUCH_TIME < WAIT_TIME) {
finish();
} else {
TOUCH_TIME = System.currentTimeMillis();
Toast.makeText(this, R.string.press_again_exit, Toast.LENGTH_SHORT).show();
}
}
}
}
/**
* 打开抽屉
*/
@Override
public void onOpenDrawer() {
if (!mDrawer.isDrawerOpen(GravityCompat.START)) {
mDrawer.openDrawer(GravityCompat.START);
}
}
@Override
public boolean onNavigationItemSelected(final MenuItem item) {
mDrawer.closeDrawer(GravityCompat.START);
mDrawer.postDelayed(new Runnable() {
@Override
public void run() {
int id = ItemId();
//获取栈顶的Fragment
final SupportFragment topFragment = getTopFragment();
if (id == R.id.nav_home) {
HomeFragment fragment = findFragment(HomeFragment.class); //根据Fragment类名查对应的Fragment
//fragment再次启动时,fragment类中通过重写onNewBundle⽅法取出数据
Bundle newBundle = new Bundle();
newBundle.putString("from", "主页-->来⾃:" + Class().getSimpleName());
fragment.putNewBundle(newBundle);
start(fragment, SupportFragment.SINGLETASK); //跳转HomeFragment
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论