Java 片段和通知:针对不同于通知的活动;取决于屏幕配置 问题:

Java 片段和通知:针对不同于通知的活动;取决于屏幕配置 问题:,java,android,android-fragments,android-notifications,Java,Android,Android Fragments,Android Notifications,如果目标可能取决于配置(屏幕大小、方向等),如何决定应启动的活动a通知;当一个人使用Fragments时通常会出现这种情况 细节: 让我们考虑一下如何使用片段>代码>来生成一个应用程序,它可以很好地处理多个屏幕大小和方向。此应用程序的结构如下所示: AHeadlinesFragment 文章片段 “主要”活动(NewsReaderActivity)。在双窗格模式下,此活动包含两个片段。在单窗格模式下,它仅包含标题行片段 文章活动。此活动仅在单窗格模式下使用;它包含文章片段 现在,假设我要增

如果目标可能取决于配置(屏幕大小、方向等),如何决定应启动的
活动
a
通知
;当一个人使用
Fragment
s时通常会出现这种情况


细节:

让我们考虑一下如何使用<代码>片段>代码>来生成一个应用程序,它可以很好地处理多个屏幕大小和方向。此应用程序的结构如下所示:

  • A
    HeadlinesFragment
  • 文章片段
  • “主要”活动(
    NewsReaderActivity
    )。在双窗格模式下,此活动包含两个片段。在单窗格模式下,它仅包含
    标题行片段
  • 文章活动
    。此活动仅在单窗格模式下使用;它包含
    文章片段
现在,假设我要增强这个应用程序,添加一个后台
服务
,它监听新闻更新,并在出现新新闻时通过状态栏通知用户。合理的需求清单可能是这样的:

  • 如果有多个新闻更新,单击通知应始终将用户带到标题列表
  • 如果只有一个更新,点击通知应该会打开全新的新闻文章
  • 请注意,这些需求根据当前配置转化为不同的目标活动。特别是,

  • 任何一种模式下的要求(1)=
    NewsReaderActivity
  • 双窗格模式下的要求(2)=
    NewsReaderActivity
  • 单窗格模式下的要求(2)=
    ArticleActivity
  • 实现上述(2)和(3)的优雅方式是什么?我认为可以安全地排除
    服务
    探测当前配置的可能性,以确定使用
    挂起内容
    的目标活动

    我想到的一个解决方案是跳过(2)并始终执行(3)-即,如果只有一个新闻更新,则始终启动
    ArticleActivity
    。ArticleActivity中的这段代码看起来很有希望:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //...
        //...
        // If we are in two-pane layout mode, this activity is no longer necessary
        if (getResources().getBoolean(R.bool.has_two_panes)) {
            finish();
            return;
        }
    
        //...
        //...
    }
    
    此代码确保,如果正在查看
    ArticleActivity
    ,但切换到不再需要的配置(例如从纵向切换到横向);然后活动simple关闭

    然而,这在我们的案例中不起作用,因为意图将设置
    标志\u活动\u新任务
    标志;我们将创建一个新任务,并且堆栈上没有“先前”活动。因此,调用
    finish()
    只会清除整个堆栈


    那么,如果要启动的活动取决于屏幕配置,那么如何决定从通知启动哪些活动呢?

    这是一个非常好的问题

    我认为可以安全地排除对当前配置进行服务探测的可能性,以确定使用PendingEvent的目标活动

    我同意在UI层保留UI决策会更好,但是让服务做出决策肯定是一个权宜之计。您可以在UI层类上使用静态方法将决策代码从技术上保持在服务之外(例如,服务用于构建其
    通知的
    NewsReaderActivity
    上的静态
    CreateArticlePendingEvent()
    方法)

    那么,如果要启动的活动取决于屏幕配置,那么如何从通知中确定要启动的活动呢

    通知
    中使用
    getActivity()
    挂起内容
    作为
    NewsReaderActivity
    的一部分,并添加足够的额外内容,以便
    NewsReaderActivity
    知道它在“显示文章”场景中。在调用
    setContentView()
    之前,让它确定
    ArticleActivity
    是否是正确答案。如果是这样,
    NewsReaderActivity
    调用
    startActivity()
    来启动
    ArticleActivity
    ,然后调用
    finish()
    来摆脱自身(如果您想从文章返回到
    NewsReaderActivity

    或者,在您的
    通知中为
    活动
    使用
    getActivity()
    pendingent
    <代码>活动
    主题。节点显示
    ,因此它没有UI。它决定是否启动
    NewsReaderActivity
    ArticleActivity
    ,对正确答案调用
    startActivity()
    ,然后调用
    finish()
    。与前面的解决方案相比,该解决方案的优点是,如果最终目的地是
    ArticleActivity
    ,则不会出现短暂的
    NewsReaderActivity
    闪烁

    或者,使用我在回答的第一段中提到的
    createArticlePendingContent()
    选项


    可能还有其他选择,但我想到的就是这些。

    当我在应用程序中使用双窗格/单窗格方法时,我只使用一个活动。在这种情况下,它意味着摆脱活动。以下是您可以继续操作的方法:

    首先,通过使用不同配置的XML布局来控制片段的外观,例如:

    单窗格(分辨率/布局):

    然后,当您处于单窗格模式(detailsFragment不存在)并希望显示详细信息屏幕时,您只需再次启动相同的活动,但在意图中包含一个参数,以告知需要哪些内容:

    void onViewDetails() {
        Intent i = new Intent(this, NewsReaderActivity.class);
        i.putExtra("showDetails", true);
        startActivity(i);
    }
    
    在活动的onCreate()中,根据以下参数选择片段:

    boolean isDetailFragment = (findViewById(R.id.detailsFragment) != null);
    if (!isDetailFragment) {
        boolean showDetails = getIntent().getBooleanExtra("showDetails", false);
        if (showDetails) {
           mainFragment = new DetailsFragment();
        }
        else {
           mainFragment = new ListFragment();
        }
    }
    
    现在,当您最终从通知启动活动时,您就不在乎了 关于当前的屏幕方向了

    只需将“showDetails”标志包含在您的in中即可
    boolean isMainFragment = (findViewById(R.id.mainFragment) != null);
    if (isMainFragment) {
        mainFragment = new ListFragment();
    }
    
    boolean isDetailFragment = (findViewById(R.id.detailsFragment) != null);
    if (isDetailFragment) {
        detailFragment = new DetailsFragment();
    }
    
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    if (isMainFragment ) {
        transaction.add(R.id.mainFragment, mainFragment);
    }
    if (isDetailFragment ) {
        transaction.add(R.id.detailFragment, detaislFragment);
    }  
    transaction.commit();
    
    void onViewDetails() {
        Intent i = new Intent(this, NewsReaderActivity.class);
        i.putExtra("showDetails", true);
        startActivity(i);
    }
    
    boolean isDetailFragment = (findViewById(R.id.detailsFragment) != null);
    if (!isDetailFragment) {
        boolean showDetails = getIntent().getBooleanExtra("showDetails", false);
        if (showDetails) {
           mainFragment = new DetailsFragment();
        }
        else {
           mainFragment = new ListFragment();
        }
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //...
        //...
        // If we are in two-pane layout mode, this activity is no longer necessary
        if (getResources().getBoolean(R.bool.has_two_panes)) {
            finish();
            return;
        }
    
        //...
        //...
    }