草庐IT

Android 优雅地管理来自 Activity 的 fragment

coder 2023-11-22 原文

关于我想要完成的事情的描述: 我有一个应用程序,它使用 FragmentActivity 和 LinearLayout 作为 fragment 的容器。我单击 FragmentActivity UI 上的不同按钮,并向 FragmentActivity 中的容器添加和删除 fragment 。除了在 FragmentActivity UI 上单击按钮外,每个 Fragment 还具有可以单击的按钮,这些按钮将删除当前 fragment 并在其位置添加不同的 fragment 。

我所理解的 Android 做事方式: 我一直在阅读有关如何执行此操作的信息,据我所知,“正确”的做事方式是将 FragmentActivity 用作中继站,并让每个 fragment 回调 FragmentActivity 以传达事件并处理他们。

场景: 因此,假设 FragmentActivity 正在显示 fragment A,当用户单击 FragmentA 中的按钮时,我想停止显示 FragmentA 并开始显示 FragmentB。为此,我在 FragmentA 中创建了一个名为 AListener 的接口(interface)。在 FragmentA 的 onAttach() 方法中,我使用了建议的方法来检查 FragmentActivity 是否实现了 AListener。单击 FragmentA 中的按钮时,我使用 AListener 中的一种回调方法将单击事件传递给 FragmentActivity。在 FragmentActivity 中,我创建了一个 FragmentB 实例并将其添加到 FragmentActivity 中的容器中。然后,如果 FragmentB 中发生了某些事件,我将使用相同的方案将事件传递给 FragmentActivity 并做一些有趣的事情。

那么问题是什么? 对于我的应用程序,我发现这种让 Fragments 回调 FragmentActivity 然后让 FragmentActivity 创建新 fragment 或调用现有 fragment 的方案非常麻烦。我有很多 FragmentActivity 需要显示的 fragment ,因此我为需要显示的每种类型的 fragment 实现了一个接口(interface)(每个 fragment 都不同,所以它们都有自己的接口(interface))。当我有两个具有相同方法签名的接口(interface)并且我被迫重命名其中一个方法时,这会导致冲突。

例如,如果我想使用 fragment 的 onAttach() 方法将监听器附加到 fragment ,那么我的 FragmentActivity 必须实现该接口(interface)。我发现了几个实例,其中我的回调方法具有相同的名称(或者由于 namespace 冲突,我被迫将它们命名为相似但不同的名称)。一种解决方案是使用匿名类作为回调,而不是让 FragmentActivity 实现接口(interface)。这似乎工作得很好,但违背了 Android 文档中关于使用 onAttach() 方法设置监听器的内容。

有什么优雅的方法可以解决这个问题吗?在我看来,权衡是你要么强制 FragmentActivity 为你想在其中显示的每个 Fragment 实现一个接口(interface),要么让注意方法签名冲突的有趣问题,或者您违反 Android 文档并使用匿名类来处理回调(不确定其含义)。

我是 Java 的新手,感觉我可能在这里遗漏了一个可以解决我的问题的概念。谁能告诉我如何优雅地解决这个问题?

最佳答案

我完全理解你的问题,因为我已经处理了很长时间。这是我现在提出的解决方案!它可能需要根据您的需要进行一些修改,但我效果很好。

首先,为了让您的应用程序中的事件通信更容易,请使用 EventBus!这是最著名的https://goo.gl/nAEW6 事件总线允许您从任何地方向任何地方发送事件,而无需担心实现接口(interface)、广播接收器、线程等。

然后将 FragmentOrganizer 添加到您的应用中。它是所有 fragment 管理器的基类。基本上每项 Activity 都需要一个。这是代码

public abstract class FragmentOrganizer {

protected FragmentManager fragmentManager;

public FragmentOrganizer(FragmentManager fragmentManager) {
    this.fragmentManager = fragmentManager;
    openFragment(getInitialFragment());
    EventBus.getDefault().register(this);
}

protected abstract Fragment getInitialFragment();
protected abstract void onEvent(Object event);
public abstract boolean handleBackNavigation();

public void freeUpResources(){
    EventBus.getDefault().unregister(this);
}


protected Fragment getOpenFragment(){
    String tag = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() -1).getName();
    return fragmentManager.findFragmentByTag(tag);
}


protected boolean isFragmentOpen(Fragment fragment){
    return isFragmentOpen(fragment, true);
}

protected boolean isFragmentOpen(Fragment fragment, boolean useArgs){
    String fragmentTag = createFragmentTag(fragment, useArgs);

    if (fragmentManager.getBackStackEntryCount() != 0) {
        String name = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName();

        if(!useArgs)
            name = name.substring(0, name.indexOf("-"));

            return name.equals(fragmentTag);
    }

    return false;
}


private String createFragmentTag(Fragment fragment, boolean addArgs) {
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(fragment.getClass().getSimpleName());
    if(addArgs) {
        stringBuilder.append("-");
        if (fragment.getArguments() != null)
            stringBuilder.append(fragment.getArguments().toString());
    }
    return stringBuilder.toString();
}

public void openFragment(Fragment fragment) {
    if(isFragmentOpen(fragment))
        return;

    String fragmentTag = createFragmentTag(fragment, true);


    FragmentTransaction transaction = fragmentManager.beginTransaction();
    transaction.replace(R.id.activity_main_fragment_container, fragment, fragmentTag);
    transaction.addToBackStack(fragmentTag).commit();
}


}

现在您需要创建从 FragmentOrganizer 继承的 fragment 管理器并实现 3 个必需的方法。这里是样本

public class MainFragmentOrganizer extends FragmentOrganizer {

public MainFragmentOrganizer(FragmentManager fragmentManager) {
    super(fragmentManager);
}

@Override
protected Fragment getInitialFragment() {
    return HomeFragment.newInstance();
}

@Override
public void onEvent(Object event){
    if(event instanceof ClickedOnPhotoEvent){
        String photoCode = ((ClickedOnPhotoEvent) event).photoCode;
        openFragment(PhotoFragment.newInstance(photoCode));
    }
}

@Override
public boolean handleBackNavigation(){
    Fragment fragment = getOpenFragment();


    if (fragment instanceof HomeFragment){
        return false;
    } else {
        fragmentManager.popBackStack();
        return true;
    }

}
}

在您的 Activity 中,您只需要让您的 FragmentManager 充满活力,让它发挥魔力!

fragmentManager = getSupportFragmentManager();
fragmentOrganizer = new          MainFragmentOrganizer(getSupportFragmentManager());
@Override
public void onBackPressed() {
    //first let fragment organizer handle back. If it does not activity takes cares of it! 
    if(!fragmentOrganizer.handleBackNavigation()){
        finish();
    }
}
@Override
protected void onDestroy() {
    fragmentOrganizer.freeUpResources();
    super.onDestroy();
}

它可能看起来有很多代码,但正如您所看到的,大部分代码都封装在 FragmentOrganizer 基类中,并且它完成了所有常规工作,因此您只需将此文件从一个项目复制到另一个项目。

正如我一开始所说的,我现在才想出这个解决方案,所以它可能并不完美。我计划在我的下一个项目中使用它,希望你能这样做。如果你这样做,我真的很感激你分享你的想法。玩得开心

关于Android 优雅地管理来自 Activity 的 fragment ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20080163/

有关Android 优雅地管理来自 Activity 的 fragment的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  4. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  5. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  6. ruby - (Ruby || Python) 窗口管理器 - 2

    我想用这两种语言中的任何一种(最好是ruby​​)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生

  7. ruby-on-rails - 事件管理员和自定义方法 - 2

    这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什

  8. ruby - 如何更优雅地记下这三种情况? - 2

    是否可以让这段代码更紧凑?我在这里错过了什么吗?ifvaluemax_ratemax_rateelsevalueend 最佳答案 这里有一些完全不同的东西:[min_rate,value,max_rate].sort[1] 关于ruby-如何更优雅地记下这三种情况?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/13309740/

  9. ruby - 可以正常中断的来自 Rake 的长时间运行的 shell 命令? - 2

    在几个项目中,我希望有一个类似rakeserver的rake任务,它将通过任何需要的方式开始为该应用程序提供服务。这是一个示例:task:serverdo%x{bundleexecrackup-p1234}end这行得通,但是当我准备停止它时,按Ctrl+c并没有正常关闭;它中断了Rake任务本身,它说rakeaborted!并给出堆栈跟踪。在某些情况下,我必须执行Ctrl+c两次。我可能可以用Signal.trap写一些东西来更优雅地中断它。有没有更简单的方法? 最佳答案 trap('SIGINT'){puts"Yourmessa

  10. ruby-on-rails - (Ruby,Rails) 基于角色的身份验证和用户管理...? - 2

    我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源

随机推荐