当你面试的时候,被问到关于Fragment的种种

Android 面试题之 Fragment 使用+实例,致Android高级工程师的一封信 android.app.Fragment在API 级别 11 中 添加,已在API 级别 28 中弃用。 阅读详情

前言

不知道你们都没有自己特别的学习的方法,我是有吧所有的整理成笔记的习惯
比如今天讲解的关于Fragment的我会做成笔记

由于文章有些地方代码过于太长了繁琐,所以部分省略掉了,敲了一下午眼睛和手脖子都酸了,至于省略的部分,对这些笔记,面试内容感兴趣的可以看笔记研究,欢迎留言

把最近的知识也整理汇总了一份,打算和之前的知识做个汇总的PDF,有兴趣的可以借鉴学习一下

知识汇总的PDF相关内容后续GitHub更新,想冲击金三银四的小伙伴可以找找看看,欢迎star
(顺手留下GitHub链接,需要获取相关面试等内容的可以自己去找)
https://github.com/xiangjiana/Android-MS
更多完整项目下载。未完待续。源码。图文知识后续上传github。
可以点击关于我联系我获取

一丶Fragment 的使用

实现很简单,创建一个的布局,然后在 Activity 里点击时替换 Fragment

  mFragmentManager = getSupportFragmentManager(); 
  mFragmentManager.beginTransaction() 
    .replace(R.id.fl_content, fragment) 
    .commitAllowingStateLoss();

代码很简单,核心就三步:

  1. 创建 Fragment
  2. 获取 FragmentManager
  3. 调用事务,添加、替换

我们一步步来了解这背后的故事。
Fragment 大家应该比较熟悉,放到最后。
先来看看 FragmentManager 。
####二丶 FragmentManager

  public abstract class FragmentManager {...}

FragmentManager 是一个抽象类,定义了一些和 Fragment 相关的操作和内部类/接口。

2.1.定义的操作

FragmentManager 中定义的方法如下:

   //开启一系列对 Fragments 的操作 
   public abstract FragmentTransaction beginTransaction(); 

   //FragmentTransaction.commit() 是异步执行的,如果你想立即执行,可以调用这个方法 
  public abstract boolean executePendingTransactions();

   //根据 ID 找到从 XML 解析出来的或者事务中添加的 Fragment 
   //首先会找添加到 FragmentManager 中的,找不到就去回退栈里找 
   public abstract Fragment findFragmentById(@IdRes int id); 

   //跟上面的类似,不同的是使用 tag 进行查找 
   public abstract Fragment findFragmentByTag(String tag); 

   //弹出回退栈中栈顶的 Fragment,异步执行的 
   public abstract void popBackStack(); 

   //立即弹出回退栈中栈顶的,直接执行哦 
   public abstract boolean popBackStackImmediate();
   ......

可以看到,定义的方法有很多是异步执行的,后面看看它究竟是如何实现的异步。

2.2.内部类/接口:

  • BackStackEntry:Fragment 后退栈中的一个元素
  • onBackStackChangedListener:后退栈变动监听器
  • FragmentLifecycleCallbacks: FragmentManager 中的 Fragment 生命周期监听
  //后退栈中的一个元素 
  public interface BackStackEntry { 
    //栈中该元素的唯一标识 
    public int getId(); //获取 FragmentTransaction#addToBackStack(String) 设置的名称 public String getName(); 

    @StringRes 
    public int getBreadCrumbTitleRes(); 
    @StringRes 
    public int getBreadCrumbShortTitleRes(); 
    public CharSequence getBreadCrumbTitle();
    public CharSequence getBreadCrumbShortTitle(); 
  }

可以看到 BackStackEntry 的接口比较简单,关键信息就是 ID 和 Name。

  //在 Fragment 回退栈中有变化时回调 
  public interface OnBackStackChangedListener { 
     public void onBackStackChanged(); 
  }
  //FragmentManager 中的 Fragment 生命周期监听 
     public abstract static class FragmentLifecycleCallbacks { 
        public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {} 
        public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {} 
        public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {} 
        public void onFragmentActivityCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {} 
        public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {} 
        public void onFragmentStarted(FragmentManager fm, Fragment f) {} 
        public void onFragmentResumed(FragmentManager fm, Fragment f) {} 
        public void onFragmentPaused(FragmentManager fm, Fragment f) {} 
        public void onFragmentStopped(FragmentManager fm, Fragment f) {} 
        public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {} 
        public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {} 
        public void onFragmentDestroyed(FragmentManager fm, Fragment f) {} 
        public void onFragmentDetached(FragmentManager fm, Fragment f) {} 
    } 
  }

熟悉 Fragment 生命周期的同学一定觉得很面熟,这个接口就是为我们提供一个 FragmentManager 所 有 Fragment 生命周期变化的回调。

小结:
可以看到, FragmentManager 是一个抽象类,它定义了对一个 Activity/Fragment 中 添加进来的Fragment 列表、Fragment 回退栈的操作、管理。

2.3.实现类 FragmentManagerImpl

FragmentManager 定义的任务是由 FragmentManagerImpl 实现的。

主要成员:

  final class FragmentManagerImpl extends FragmentManager implements 
  LayoutInflaterFactory { 
     ArrayList<OpGenerator> mPendingActions; 
     Runnable[] mTmpActions; 
     boolean mExecutingActions;
     ArrayList<Fragment> mActive; 
     ArrayList<Fragment> mAdded; 
     ArrayList<Integer> mAvailIndices; 
     ArrayList<BackStackRecord> mBackStack; 
     ArrayList<Fragment> mCreatedMenus;
  // Must be accessed while locked. 
     ArrayList<BackStackRecord> mBackStackIndices; 
     ArrayList<Integer> mAvailBackStackIndices;
     ArrayList<OnBackStackChangedListener> mBackStackChangeListeners; 
     private CopyOnWriteArrayList<Pair<FragmentLifecycleCallbacks, Boolean>> mLifecycleCallbacks; 
  //... 
  }

可以看到, FragmentManagerImpl 中定义了 添加的、活跃的。以及回退栈的列表,这和FragmentManager 的要求一致

接着还有当前的状态,当前 Fragment 的起始 mParent,以及 FragmentManager 的 mHost 和mContainer。

FragmentContainer 就是一个接口,定义了关于布局的两个方法:

  public abstract class FragmentContainer { 
     @Nullable 
     public abstract View onFindViewById(@IdRes int id); 
     public abstract boolean onHasView();
   }

而 FragmentHostCallback 就复杂一点了,它提供了 Fragment 需要的信息,也定义了 Fragment 宿主应该做的操作:

  public abstract class FragmentHostCallback<E> extends FragmentContainer { 
     private final Activity mActivity; 
     final Context mContext; 
     private final Handler mHandler; 
     final int mWindowAnimations; 
     final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl(); 
     //... 
  }

我们知道,一般来说 Fragment 的宿主就两种:

  1. Activity
  2. Fragment

比如 FragmentActivity 的内部类 HostCallbacks 就实现了这个抽象类:

  class HostCallbacks extends FragmentHostCallback<FragmentActivity> { 
     public HostCallbacks() { 
        super(FragmentActivity.this /*fragmentActivity*/);
      }
      //... 

     @Override 
     public LayoutInflater onGetLayoutInflater() { 
        return 
  FragmentActivity.this.getLayoutInflater().cloneInContext(FragmentActivity.t his);
     }

    @Override 
    public FragmentActivity onGetHost() { 
       return FragmentActivity.this; 
    }
    ......
  }

我们再看看他对 FragmentManager 定义的关键方法是如何实现的。

  @Override 
  public FragmentTransaction beginTransaction() { 
     return new BackStackRecord(this); 
  }

beginTransaction() 返回一个新的 BackStackRecord ,我们后面介绍。前面提到了, popBackStack() 是一个异步操作,它是如何实现异步的呢?

  @Override 
  public void popBackStack() { 
     enqueueAction(new PopBackStackState(null, -1, 0), false); 
  }
  public void enqueueAction(OpGenerator action, boolean allowStateLoss) { 
     if (!allowStateLoss) { 
         checkStateLoss(); 
     }
     synchronized (this) { 
         if (mDestroyed || mHost == null) { 
             throw new IllegalStateException("Activity has been destroyed"); 
         }
         if (mPendingActions == null) { 
             mPendingActions = new ArrayList<>(); 
         }
         mPendingActions.add(action); 
         scheduleCommit(); 
     } 
  }
  private void scheduleCommit() { 
     synchronized (this) { 
         boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
         boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1; 
         if (postponeReady || pendingReady) { 
             mHost.getHandler().removeCallbacks(mExecCommit); 
             mHost.getHandler().post(mExecCommit); 
         } 
     } 
  }

可以看到,调用到最后,是调用宿主中的 Handler来发送任务的,so easy 嘛。其他的异步执行也是类似,就不赘述了。

后退栈相关方法:

  ArrayList<BackStackRecord> mBackStack; 
  @Override 
  public int getBackStackEntryCount() { 
     return mBackStack != null ? mBackStack.size() : 0; 
  }
  @Override 
  public BackStackEntry getBackStackEntryAt(int index) { 
     return mBackStack.get(index); 
  }

可以看到,开始事务和后退栈,返回/操作的都是 BackStackRecord ,我们来了解了解它是何方神圣。

三丶事务

BackStackRecord 继承了 FragmentTransaction :

  final class BackStackRecord extends FragmentTransaction implements 
      FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {...}

先来看看 FragmentTransaction 。

3.1.FragmentTransaction

FragmentTransaction 定义了一系列对 Fragment 的操作方法:

  //它会调用 add(int, Fragment, String),其中第一个参数传的是 0 
  public abstract FragmentTransaction add(Fragment fragment, String tag); 

  //它会调用 add(int, Fragment, String),其中第三个参数是 null 
  public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment); 

  //添加一个 Fragment 给 Activity 的最终实现 
  //第一个参数表示 Fragment 要放置的布局 id 
  //第二个参数表示要添加的 Fragment,【注意】一个 Fragment 只能添加一次 
  //第三个参数选填,可以给 Fragment 设置一个 tag,后续可以使用这个 tag 查询它 
  public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment, @Nullable String tag);

  //调用 replace(int, Fragment, String),第三个参数传的是 null 
  public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment);

  //替换宿主中一个已经存在的 fragment 
  //这一个方法等价于先调用 remove(), 再调用 add() public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment, @Nullable String tag);
  //移除一个已经存在的 fragment 
  //如果之前添加到宿主上,那它的布局也会被移除 
  public abstract FragmentTransaction remove(Fragment fragment);

  //隐藏一个已存的 fragment 
  //其实就是将添加到宿主上的布局隐藏 
  public abstract FragmentTransaction hide(Fragment fragment);

  //显示前面隐藏的 fragment,这只适用于之前添加到宿主上的 fragment 
  public abstract FragmentTransaction show(Fragment fragment);
  
  //将指定的 fragment 将布局上解除 
  //当调用这个方法时,fragment 的布局已经销毁了 
  public abstract FragmentTransaction detach(Fragment fragment); 

  //当前面解除一个 fragment 的布局绑定后,调用这个方法可以重新绑定 
  //这将导致该 fragment 的布局重建,然后添加、展示到界面上 
  public abstract FragmentTransaction attach(Fragment fragment);

对 fragment 的操作基本就这几步,我们知道,要完成对 fragment 的操作,最后还需要提交一下:

  mFragmentManager.beginTransaction() 
         .replace(R.id.fl_child, getChildFragment())
   // .commit() 
         .commitAllowingStateLoss();
2.2.事务的四种提交方式

事务最终的提交方法有四种:

  1. commit()
  2. commitAllowingStateLoss()
  3. commitNow()
  4. commitNowAllowingStateLoss()

它们之间的特点及区别如下:

  public abstract int commit();

commit() 在主线程中异步执行,其实也是 Handler 抛出任务,等待主线程调度执行。

注意:
commit() 需要在宿主 Activity 保存状态之前调用,否则会报错。
这是因为如果 Activity 出现异常需要恢复状态,在保存状态之后的 commit() 将会丢失,这和调用的初衷不符,所以会报错。

  public abstract int commitAllowingStateLoss();

commitAllowingStateLoss() 也是异步执行,但它的不同之处在于,允许在 Activity 保存状态之后调用,也就是说它遇到状态丢失不会报错。

因此我们一般在界面状态出错是可以接受的情况下使用它。

  public abstract void commitNow();

commitNow() 是同步执行的,立即提交任务。

前面提到 FragmentManager.executePendingTransactions() 也可以实现立即提交事务。但我们一般建议使用 commitNow() , 因为另外那位是一下子执行所有待执行的任务,可能会把当前所有的事务都一下子执行了,这有可能有副作用。

此外,这个方法提交的事务可能不会被添加到 FragmentManger 的后退栈,因为你这样直接提交,有可能影响其他异步执行任务在栈中的顺序。

和 commit() 一样, commitNow() 也必须在 Activity 保存状态前调用,否则会抛异常。

  public abstract void commitNowAllowingStateLoss();

同步执行的 commitAllowingStateLoss() 。
OK,了解了 FragmentTransaction 定义的操作,去看看我们真正关心的、 beginTransaction()中返回的 BackStackRecord :

  @Override 
  public FragmentTransaction beginTransaction() { 
     return new BackStackRecord(this);
   }
3.3事务真正实现/回退栈 BackStackRecord

BackStackRecord 既是对 Fragment 进行操作的事务的真正实现,也是 FragmentManager 中的回退栈的实现:

  final class BackStackRecord extends 
        FragmentTransaction implements FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {...}

它的关键成员:

  final FragmentManagerImpl mManager; 
  //Op 可选的状态值 
  static final int OP_NULL = 0; 
  static final int OP_ADD = 1; 
  static final int OP_REPLACE = 2;
  static final int OP_REMOVE = 3; 
  static final int OP_HIDE = 4; 
  static final int OP_SHOW = 5; 
  static final int OP_DETACH = 6; 
  static final int OP_ATTACH = 7; 

  ArrayList<Op> mOps = new ArrayList<>();
  static final class Op {
     int cmd; //状态 
     Fragment fragment; 
     int enterAnim; 
     int exitAnim; 
     int popEnterAnim;
     int popExitAnim; 
  }
  int mIndex = -1; 
  //栈中最后一个元素的索引
  }

可以看到 Op 就是添加了状态和动画信息的 Fragment, mOps就是栈中所有的 Fragment。事务定义的方法它是如何实现的呢

先看添加一个 Fragment 到布局 add() 的实现:

  @Override 
  public FragmentTransaction add(int containerViewId, Fragment fragment) { 
     doAddOp(containerViewId, fragment, null, OP_ADD); 
     return this; 
   ......
  }

可以看到添加一个 Fragment 到布局很简单,概况一下就是:
修改 fragmentManager 和 ID,构造成 Op,设置状态信息,然后添加到列表里。

添加完了看看替换 replace 的实现:

  @Override 
  public FragmentTransaction replace(int containerViewId, Fragment fragment) { 
     return replace(containerViewId, fragment, null); 
  }
  @Override 
  public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) { 
     if (containerViewId == 0) { 
         throw new IllegalArgumentException("Must use non-zero containerViewId"); 
     }

     doAddOp(containerViewId, fragment, tag, OP_REPLACE);
     return this;
   }

太可怕了,也是调用上面刚提到的 doAddOp() ,不同之处在于第四个参数为 OP_REPLACE ,看来之前小看了这个状态值!

再看其他方法的实现就很简单了,无非就是构造一个 Op,设置对应的状态值。

  @Override 
  public FragmentTransaction remove(Fragment fragment) { 
     Op op = new Op(); 
     op.cmd = OP_REMOVE; 
     op.fragment = fragment; 
     addOp(op);
   
     return this; 
  }
  
  @Override 
  public FragmentTransaction hide(Fragment fragment) { 
     Op op = new Op(); 
     op.cmd = OP_HIDE; 
     op.fragment = fragment; 
     addOp(op); 

    return this;
   }

  @Override 
  public FragmentTransaction show(Fragment fragment) { 
     Op op = new Op(); 
     op.cmd = OP_SHOW; 
     op.fragment = fragment; 
     addOp(op); 
    
     return this; 
  }

那这些状态值的不同是什么时候起作用的呢?
别忘了我们操作 Fragment 还有最后一步,提交。
看看这两个是怎么实现的:

  @Override 
  public int commit() { 
     return commitInternal(false); 
  }

  @Override 
  public int commitAllowingStateLoss() { 
     return commitInternal(true); 
  }
  int commitInternal(boolean allowStateLoss) { 
     if (mCommitted) throw new IllegalStateException("commit already called"); 
     //...
     }
  }

前面已经介绍过了, FragmentManager.enqueueAction() 最终是使用 Handler 实现的异步执行。
现在的问题是执行的任务是啥?
答案就是 Handler 发送的任务 mExecCommit :
代码多了一点省略掉了,但我们终于找到了最终的实现:Handler 异步发到主线,调度执行后,聚合、修改 Ops的状态,然后遍历、修改 Fragment 栈中的 View 的状态。

3.4.真正处理的部分

前面主要是对 Fragment 的包装类 Ops 进行一些状态修改,真正根据 Ops 状态进行操作在这个部分:

  /**
   * Executes the operations contained within this transaction. The Fragment states will only 
   * be modified if optimizations are not allowed. 
   */ 
   void executeOps() { 
        final int numOps = mOps.size(); 
        for (int opNum = 0; opNum < numOps; opNum++) { 
             final Op op = mOps.get(opNum); 
             final Fragment f = op.fragment; 
             f.setNextTransition(mTransition, mTransitionStyle); switch (op.cmd) { 
               case OP_ADD:
                    f.setNextAnim(op.enterAnim); 
                    mManager.addFragment(f, false); 
                    break; 
               case OP_REMOVE:
                    f.setNextAnim(op.exitAnim); 
                    mManager.removeFragment(f); 
                    break; 
               case OP_HIDE: 
                    f.setNextAnim(op.exitAnim); 
                    mManager.hideFragment(f); 
                    break; 
               case OP_SHOW: 
                    f.setNextAnim(op.enterAnim); 
                    mManager.showFragment(f); 
                    break; 
               case OP_DETACH: 
                    f.setNextAnim(op.exitAnim); 
                    mManager.detachFragment(f); 
                    break; 
               case OP_ATTACH: 
                    f.setNextAnim(op.enterAnim); 
                   mManager.attachFragment(f); 
                   break; 
               default: 
                   throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
            }
            if (!mAllowOptimization && op.cmd != OP_ADD) { 
                mManager.moveFragmentToExpectedState(f); 
            } 
        }
        if (!mAllowOptimization) { 
            // Added fragments are added at the end to comply with prior behavior.mManager.moveToState(mManager.mCurState, true); 
        } 
  }

FragmentManager 对这些方法的实现也很简单,修改 Fragment 的状态值,比如remove(Fragment) :

  public void removeFragment(Fragment fragment) { 
     if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting); 
     final boolean inactive = !fragment.isInBackStack(); 
     if (!fragment.mDetached || inactive) { 
        if (mAdded != null) { 
            mAdded.remove(fragment); 
        }
        if (fragment.mHasMenu && fragment.mMenuVisible) { 
            mNeedMenuInvalidate = true; 
        }
        fragment.mAdded = false; //设置属性值 
        fragment.mRemoving = true; 
     } 
  }

代码很长,先省略掉…但做的事情很简单:

  1. 根据状态调用对应的生命周期方法
  2. 如果是新创建的,就把布局添加到 ViewGroup 中
四丶总结

OK,看完这篇文章,相信对开头提出的问题你已经有了答案,这里再总结一下。
Fragment、FragmentManager、FragmentTransaction 关系

  • Fragment
    • 其实是对 View 的封装,它持有 view, containerView, fragmentManager, childFragmentManager 等信息
  • FragmentManager
    • 是一个抽象类,它定义了对一个 Activity/Fragment 中 添加进来的 Fragment 列表、Fragment 回退栈的操作、管理方法
    • 还定义了获取事务对象的方法
    • 具体实现在 FragmentImpl 中
  • FragmentTransaction
    • 定义了对 Fragment 添加、替换、隐藏等操作,还有四种提交方法
    • 具体实现是在 BackStackRecord 中

Fragment 如何实现布局的添加替换
通过获得当前 Activity/Fragment 的FragmentManager/ChildFragmentManager,进而拿到事务的实
现类 BackStackRecord,它将目标 Fragment 构造成 Ops(包装Fragment和状态信息),然后提交给FragmentManager 处理。

如果是异步提交,就通过 Handler 发送 Runnable 任务,FragmentManager 拿到任务后,先处理 Ops
状态,然后调用 moveToState() 方法根据状态调用 Fragment 对应的生命周期方法,从而达到Fragment 的添加、布局的替换隐藏等。

下面这张图从下往上看就是一个 Fragment 创建经历的方法:

嵌套 Fragment的原理

也比较简单,Fragment 内部有一个 childFragmentManager,通过它管理子 Fragment。
在添加子 Fragment 时,把子 Fragment 的布局 add 到父 Fragment 即可

由于很多代码太长了,敲了一下午,眼睛和手都酸了,对这样感兴趣的可以拿这份笔记自己研究,有不懂的欢迎留言

知识汇总的PDF相关内容后续GitHub更新,想冲击金三银四的小伙伴可以找找看看,欢迎star
(顺手留下GitHub链接,需要获取相关面试等内容的可以自己去找)
https://github.com/xiangjiana/Android-MS
更多完整项目下载。未完待续。源码。图文知识后续上传github。
可以点击关于我联系我获取

Flutter开发之——Android-Flutter添加到Fragment 针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。 阅读详情

相关推荐

Android面试笔记之Fragment详解

Fragment详解前言Fragment为什么被称为第五大组件Fragment的生命周期Fragment之间的通信Fragment管理器:FragmentManager总结 前言 Android面试基本知识点->Fragment面试详解问题记录,后续会完善。 提示:以下是本篇文章正文内容,下面案例可供参考 Fragment为什么被称为第五大组件 1、Fragment为什么被称为第五大组件 Android 3.0 开始引入的API 2、Fragment加载到Activity的两种方式 添加Frag

qq_35857451的博客 294

**关于切换fragment没有效果的问题**

关于切换fragment没有效果的问题 功能需求 首页上有4个fragmnt,不管在那个页面上都可以快速切换到指定的fragment上; 实现时想的办法是做一个悬浮窗,点击悬浮窗发送EventBus可以快速切换; 之前是用FragmentMananger的transaction调用replace方法,然后commit()提交;但是发现没有效果,所有方法都执行了,传的参数也没有问题。但

liboyan369的博客 618

求一个点到任意两个点所在直线距离 C#代码公式

求点C(X0,Y0) 到点A(x1,y1)和点B(x2,y2)所在直线的距离 1.已知任意两个点,求这两个点所在直线 已知点A(x1,y1),点B(x2,y2) 设直线上另外任意一个点为(x,y) 那么 (x-x1)/(y-y1) = (x2-x1)/(y2-y1); 整理后得方程: (y2-y1)x + (x1-x2)y + (y1-...

qq_29434987的博客 4492

activity使用fragment transaction.commit()进行fragment切换,activity被系统回收后再点应用就无法切换

/**  *   */ package com.cn.xm.yunluhealth.ui.set; import java.util.ArrayList; import java.util.List; import net.tsz.afinal.http.AjaxCallBack; import android.app.Dialog; import android.os.Bundle; imp

qianchen4564的博客 875

MSP430项目设计:2020年TI杯大学生电子设计竞赛 坡道行驶电动小车(C题)循迹小车(分享项目展示视频与源码)

文章目录题目要求一、硬件设计二、理论分析与计算三、电路与程序设计四、测试方案与测试结果五、项目展示 哔哩哔哩项目展示视频:https://www.bilibili.com/video/BV1oz4y1d7mH/ 百度网盘资料链接:https://pan.baidu.com/s/1PC-lkSORH_XCgIG-u3HCog 提取码:c7zz 取走记得点赞啊! 题目要求 1.任务 利用TI的MSP430/MSP432平台,设计制作一个四轮电动小车。要求小车能沿着指定路线在坡道上自动循迹骑线行驶。小车必须独立

mbs706的博客 4万+

Lattice CrosslinkNx LIFCL-40实战解析:MIPI D-PHY硬核IP配置与CSI-2数据解析全流程

本文详细解析了Lattice CrosslinkNx LIFCL-40 FPGA中MIPI D-PHY硬核IP的配置与CSI-2数据解析全流程。通过实战案例,介绍了硬件环境搭建、寄存器配置、数据包结构解析及视频流重构技巧,帮助开发者快速掌握高速图像采集系统的设计与优化方法。

weixin_29159613的博客 198

Android 进阶17:Fragment FragmentManager FragmentTransaction 深入理解

日常开发中我们经常使用 Fragment 管理布局,使用起来非常方便,但是在简单的 API 背后隐藏了什么操作,很多人恐怕不了解。如果你回答不出这些问题,那这篇文章可能就对你有些帮助: Fragment FragmentManager FragmentTransaction 的关系和作用 Fragment 如何实现布局的添加替换 嵌套 Fragment 的原理 读完本文你将了解:Fragment 的

张拭心的博客 shixinzhang 3万+

Cadence Allegro实战:如何精准导入结构DXF文件避免安装偏差(附图层配置技巧)

本文详细讲解了在Cadence Allegro中精准导入结构DXF文件以避免安装偏差的实战技巧。核心在于导入前的单位校准、创建专用图层结构,以及基于坐标基准点的精确对齐方法。文章还分享了将DXF图形转化为正式板框和禁布区、高效管理图层以及向结构工程师导出DXF的完整流程,帮助PCB工程师确保设计与机械结构完美契合。

1a2s3d4f5g的博客 506

FragmentTrasaction replace()无效

这个问题困扰了我一下午,从外面走一趟回来终于解决了。方法的原理我就不讲了,百度上面太多,我讲不赢他们,即使他们讲得再好,反正我看完他们的也没解决我的问题。那么想解决这个问题请保证你的replace()方法的书写流程是对的FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction transaction = f

a4384142的专栏 2866

从YOLOv8到RTDETR:如何将训练后的YOLO指标无缝转换为COCO格式

本文详细介绍了如何将训练后的YOLOv8指标无缝转换为COCO格式,特别适用于RTDETR模型的评估。通过数据准备、指标转换流程和实际项目经验,帮助开发者解决YOLO与COCO指标差异问题,提升模型评估的准确性和权威性。

weixin_29085151的博客 378

在线迭代RLHF实战:从原理到实现,复现超越官方指令模型的工作流

大语言模型(LLM)的对齐技术是提升其与人类意图一致性的关键。其中,基于人类反馈的强化学习(RLHF)通过引入人类偏好信号,指导模型优化生成策略,是实现模型“有用”与“无害”的核心方法。其技术价值在于将抽象的“对齐”目标转化为可优化的奖励信号,从而显著提升模型在对话、推理等任务中的表现。然而,传统的离线RLHF存在数据分布偏移和奖励黑客等瓶颈。在线迭代RLHF通过构建“生成-评估-学习”的动态数据循环,让模型能够利用自身最新生成的数据进行持续优化,有效克服了上述问题,成为当前提升指令模型性能的前沿方向。本文

weixin_28725037的博客 368

Fragment使用过程中遇到的一些问题

先看下 Fragment 的基础用法,这是Fragment动态用法四部曲 1.获得FragmentManager对象,通过getSupportFragmentManager() 2.获得FragmentTransaction对象,通过fm.beginTransaction() 3.调用add()方法或者repalce()方法加载Fragment; 4.最后调用commit()方法提交事务 FragmentManager fragmentManager = getSupportFragmentManag

lollo01的博客 1022

2025统计建模大赛完整论文

参赛队号:(参赛队无须填写,参赛队号由大赛官网自动生成)2025年(第十一届)全国大学生统计建模大赛参 赛 作 品参赛学校:XXXXXX大学论文题目:海洋叶绿素含量影响因素与预测——基于机器学习与大数据分析预测参赛队员:指导老师:国家知识产权局 统计分析成果 知识产权统计数据公开查询指引(2024版)随着全球气候变化的加剧,海洋碳汇的作用愈发受到重视,尤其是海洋生物通过光合作用吸收二氧化碳的过程,对于全球碳循环和温室气体减排具有重要意义。

2301_79579117的博客 9316

android面试之fragment,当你面试的时候,被问到关于Fragment的种种

前言不知道你们都没有自己特别的学习的方法,我是有吧所有的整理成笔记的习惯比如今天讲解的关于Fragment的我会做成笔记由于文章有些地方代码过于太长了繁琐,所以部分省略掉了,敲了一下午眼睛和手脖子都酸了,至于省略的部分,对这些笔记,面试内容感兴趣的可以看笔记研究,欢迎留言相关内容后续GitHub更新,想冲击金三银四的小伙伴可以找找看看,欢迎star(顺手留下GitHub链接,需要获取相关面试等内容...

weixin_39960503的博客 233

Unity之OpenXR+XR Interaction Toolkit实现 Gaze眼部追踪

在虚拟现实(VR)和增强现实(AR)应用中,眼动追踪是一项强大而受欢迎的技术。它可以让开发者更好地理解用户的注意力和行为,并创造出更加沉浸和智能的体验。在本文中,我们将探讨如何使用 Unity OpenXR 实现Gaze眼部追踪功能。

TxNet 1751

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

当你面试的时候,被问到关于Fragment的种种,前方高能

FragmentManager 定义的任务是由 FragmentManagerImpl 实现的。 主要成员: final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory { ArrayList mPendingActions; Runnable[] mTmpActions; boolean mExecutingActions; ArrayList mActive; ArrayList mAd

m0_65320833的博客 182

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

当你面试的时候,被问到关于Fragment的种种,移动app定制开发

if (mDestroyed || mHost == null) { throw new IllegalStateException(“Activity has been destroyed”); } if (mPendingActions == null) { mPendingActions = new ArrayList<>(); } mPendingActions.add(action); scheduleCommit(); } } private void scheduleCommit(

wqwq_22的博客 158

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

当你面试的时候,被问到关于Fragment的种种(1)

这次面试问的还是还是有难度的,要求当场写代码并且运行,也是很考察面试者写代码因为Android知识体系比较庞大和复杂的,涉及到计算机知识领域的方方面面。在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

2401_84048149的博客 730

当你面试的时候,被问到关于Fragment的种种,android入门基础

public int getBreadCrumbTitleRes(); @StringRes public int getBreadCrumbShortTitleRes(); public CharSequence getBreadCrumbTitle(); public CharSequence getBreadCrumbShortTitle(); } 可以看到 BackStackEntry 的接口比较简单,关键信息就是 ID 和 Name。 //在 Fragment 回退栈中有变化时回调 public

m0_65320833的博客 155

当你面试的时候,被问到关于Fragment的种种,2024年最新应届毕业生硬件工程师面试题库

中定义的方法如下://开启一系列对 Fragments 的操作//FragmentTransaction.commit() 是异步执行的,如果你想立即执行,可以调用这个方法//根据 ID 找到从 XML 解析出来的或者事务中添加的 Fragment//首先会找添加到 FragmentManager 中的,找不到就去回退栈里找//跟上面的类似,不同的是使用 tag 进行查找//弹出回退栈中栈顶的 Fragment,异步执行的//立即弹出回退栈中栈顶的,直接执行哦。

2401_84024576的博客 468

Android Fragment展示Unity场景,【面试总结

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。上面分享的百度、腾讯、网易、字节跳动、阿里等公司2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。Android学习PDF+学习视频+面试文档+知识点笔记【Android思维脑图(技能树)】知识不体系?

2401_87361592的博客 2185

android面试之fragment,Android面试题之Fragment篇

Fragment篇 前言Fragment1.如何切换 fragement(不重新实例化)2.Fragment 的的优点3.Fragment 如何实现类似 Activity 栈的压栈和出栈效果4.Fragment 的 replace 和 add 方法的区别5.Fragment与Activity之间是如何传值的6.Fragment生命周期7.ViewPager对Fragment生命周期的影响关于整理问...

weixin_35980011的博客 226

Android面试必备——Fragment

Android面试中Fragment也是会经常被问到的知识点,本文介绍一下Fragment。 概述 Fragment是Activity中用户界面的一个行为或者是一部分。主要是支持在大屏幕上动态和更为灵活的去组合或是交换UI组件,通过将Activity的布局分割成若干个Fragment,可以在运行时编辑Activity的呈现,并且那些变化会被保存在由Activity管理的后台栈里面。 Fragmen...

ai-exception的博客 1027

面试专题之一Fragment的生命周期

面试的时候,如果被面试官问到Fragment的生命周期,想必大家直接脱口而出:onCreate()、onCreateView()、onActivityCreated()、on……,然后就没有然后了。学习生命周期不是为了应付面试,背个执行顺序就完了,要理解每个方法的含义,而它们的真正含义,只有通过不断做实验,把每种情况都实验一遍才能得出答案,过程是漫长又繁琐的。下面的结果就是博主不断实验的结果,当然

u013519989的博客 3504
上一篇: 做开发的过程中,搞着搞着出现异常了,这可怎么办
下一篇: 面试必问的一个知识点,关于HandlerThread的使用场景以及怎样使用 HandlerThread?
初壹十五a
博客等级 码龄8年 146粉丝 257原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值