2012-08-03 146 views
3

应用程序(目标API级别必须为7)具有FragmentActivity,它在onCreate处分析作为额外传递的片段密钥。组织片段活动导航堆栈

现在需要重新排序已经使用给定片段关键字创建的活动。

让我们假设带有不同片段密钥的FragmentActivityFA1,FA2FA3 - 每个是具有不同片段的相同活动类实例。

现在在堆栈FA1>FA2>FA3我想在默认情况下,让使用的意图,而不是后退按钮去FA2,:

FA1>FA2>FA3>新FA2

我想获得任何FA1>FA3>FA2作为FA3可能有一些等待的操作,FA1>FA2没以前好了,但肯定比默认更好。

如果有多个活动,我会使用FLAG_ACTIVITY_REORDER_TO_FRONT标志作为意图,但这不适用于这种情况。


FA1, FA2, FA3, etc.是同一类MyFA的所有实例,这就是为什么我不能够使用意图标志和FragmentManager似乎是出于帮助,直到有一个标准的全球片段缓存。


里程碑(目前正在和有待提高)的解决方案有一件事我今天所学到的activity-alias这使得做出几个别名以作为ID的不同意图演员相同的活动。现在,REORDER_TO_FRONT标志按照我的意愿工作。

解决方案反馈该解决方案没有低级操作,我喜欢的不仅仅是挖掘任务或后端堆栈。现在缺点是每个这样的活动都需要一个单独的硬编码路径别名,我不太喜欢它。

要求(赏金在这里)不管谁来体面的优化需要 300饼干。不错 ?任何其他固体解决方案也非常感谢。

目前我在应用程序清单中有10个别名,例如,

<activity 
     android:name=".activity.FragmentActivity" 
     android:configChanges="orientation" 
     android:screenOrientation="portrait" > 
     <intent-filter> 
      <category android:name="android.intent.category.DEFAULT" /> 

      <action android:name="com.company.name.intent.FragmentActivity" /> 
     </intent-filter> 
    </activity> 

    <activity-alias 
     android:name="com.company.name.intent.FragmentActivity.FragmentedOne" 
     android:targetActivity=".activity.FragmentActivity" > 
     <intent-filter> 
      <action android:name="com.company.name.intent.FragmentActivity.FragmentedOne" /> 

      <category android:name="android.intent.category.DEFAULT" /> 
     </intent-filter> 

     <meta-data 
      android:name="fragment_key_extra" 
      android:value="FragmentOne" /> 
    </activity-alias> 
    <activity-alias 
     android:name="com.company.name.intent.FragmentActivity.FragmentedTwo" 
     android:targetActivity=".activity.FragmentActivity" > 
     <intent-filter> 
      <action android:name="com.company.name.intent.FragmentActivity.FragmentedTwo" /> 

      <category android:name="android.intent.category.DEFAULT" /> 
     </intent-filter> 

     <meta-data 
      android:name="fragment_key_extra" 
      android:value="FragmentTwo" /> 
    </activity-alias> 

然后将活动重新排序与

Intent intent = new Intent(
"com.company.name.intent.FragmentActivity.FragmentedOne"); 
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 
startActivity(intent); 
+0

任何运气? – 2012-10-26 02:50:04

+0

您是否介意对您的活动别名进行阐述?我有一个活动,其中有一个片段可以在8个不同的视图(活动)之间切换。我希望能够使用REORDER前后来回。 – VicVu 2012-10-29 18:09:10

+1

Hi @ Vee,我已经添加了部分清单文件和一小段代码,希望它可以帮助你 - 它应该可以工作。可能会有一些拼写错误,因为我不得不稍微更改文本。 – 2012-10-29 19:20:24

回答

1

根据您的使用activity-alias来解决这个问题的想法,我写了一个Historian class,将做到以下几点:

  • 扫描活动列表中查看产品包装以别名,您的具体活动。
  • 设置每个别名映射到一个Intent的查找表。
  • 提供一个startActivity()activityDestroyed()方法,将做一些簿记所以查找表可以用于一个别名动态地分配基于所述意图的行驶活动。

下面是关于如何使用它的一个例子:

  • 在AndroidManifest

    。XML

    <activity android:name=".MyFragmentActivity"> 
        <intent-filter> 
         <action android:name="android.intent.action.MAIN" /> 
         <category android:name="android.intent.category.LAUNCHER" /> 
        </intent-filter> 
    </activity> 
    <activity-alias android:name=".Alias0" android:targetActivity=".MyFragmentActivity" /> 
    <activity-alias android:name=".Alias1" android:targetActivity=".MyFragmentActivity" /> 
    <activity-alias android:name=".Alias2" android:targetActivity=".MyFragmentActivity" /> 
    <activity-alias android:name=".Alias3" android:targetActivity=".MyFragmentActivity" /> 
    <activity-alias android:name=".Alias4" android:targetActivity=".MyFragmentActivity" /> 
    
  • 您的活动类中

    public class MyFragmentActivity extends FragmentActivity 
         implements Historian.Host { 
    
        private Historian<MyFragmentActivity> mHistorian; 
    
        // ... 
    
        @Override 
        protected void onCreate(Bundle savedInstanceState) { 
         super.onCreate(savedInstanceState); 
    
         mHistorian = new Historian<MyFragmentActivity>(this); 
    
         // ... 
        } 
    
        @Override 
        protected void onDestroy() { 
         super.onDestroy(); 
         mHistorian.activityDestroyed(this); 
        } 
    
        @Override 
        public boolean matchIntent(Intent intent0, Intent intent1) { 
         if (intent0 == null || intent1 == null) return false; 
         final String title0 = intent0.getStringExtra("title"); 
         final String title1 = intent1.getStringExtra("title"); 
         return title0.equals(title1); 
        } 
    
        // ... 
    
    } 
    

而不是开始你的活动这样一个新的实例:

Intent intent = new Intent(this, MyFragmentActivity.class); 
    intent.putExtra("title", newActivityTitle); 
    intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 
    startActivity(intent); 

你这样做:

Intent intent = new Intent(this, MyFragmentActivity.class); 
    intent.putExtra("title", newActivityTitle); 
    intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 
    mHistorian.startActivity(this, intent); 

因此,您仍然需要手动添加几个activity-alias到您的清单中(作为池使用)并在您的Activity中实施matchIntent()方法(以帮助检测两个Intent是否等于您),但其余部分是动态处理的由史学家阶级。

我还没有详尽地测试代码,但它似乎在我做的一些简单的测试中工作正常。这个想法其实很相似,my answerother question(只需要使用FLAG_ACTIVITY_CLEAR_TOP代替FLAG_ACTIVITY_REORDER_TO_FRONT有),但使用activity-alias而不是内部的子类使它更清洁:)

+0

它看起来不错,您是否在支持Android 2.1的应用程序中使用Historian?我对它的性能和稳定性感兴趣。 – 2012-11-01 11:31:07

+0

我在2.1版的模拟器上测试过它,并且与2.3/4.0上运行时相比没有发现任何区别。在性能方面,我认为与涉及onActivityResult()的解决方案相比,它应该更高效,因为我们不需要经历中间活动的生命周期事件。虽然我没有真正测试过这么多:) – Joe 2012-11-01 13:46:20

2

你可以考虑使用由FragmentManager提供的功能。它具有功能,如popBackStack

您还可以使用FragmentTransaction将碎片添加到后台堆栈。您可以使用addToBackStack来完成此操作。

因此,如果需要这两个类,您应该可以在堆栈中重新排序碎片。

+0

我很抱歉,目标API级别必须是第7位,谢谢您的建议。 – 2012-08-03 14:11:50

+0

我相信所有的片段类都可以通过支持库获得:http://developer.android.com/reference/android/support/v4/app/package-summary.html – Nick 2012-08-03 14:28:59

+0

这很酷,所以我会尝试使片段关键是它的标记,这可能会做到这一点。 – 2012-08-03 14:41:28

4

这个答案是价值300种饼干:-D MMMMM

  1. 扩展应用程序,所以我们可以有一个全球范围内创造我们自己的背部栈名单。

    import android.app.Application; import android.content.Intent;

    类MyApp的扩展应用{

    //This is our very own back stack. 
    private ArrayList<Intent> backStack = new ArrayList<Intent>(); 
    
    public void reorderBackStack(){ 
        //Do what you want to the order of your backstack 
        //You can read the value of your intent extras from here. 
    } 
    
    public void addIntent(Intent i){ // this gets called from our activities onCreate 
        backStack.add(i); 
    } 
    
    public void goBack(){ 
        if(backStack.size() >= 2){ // can go back 
         backStack.remove(backStack.size() - 1); // drop the last item in stack if you want. This is how Android does it. (no forward capability) 
         this.startActivity(backStack.get(backStack.size() - 1)); 
        } 
    } 
    

    }

  2. 增加提及我们自定义的回堆在我们的活动。

    public class MainActivity extends Activity {0} {0} {0} {0} MyApp myapp;

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
        myapp = ((MyApp)getApplicationContext()); 
        myapp.addIntent(this.getIntent()); //add the intent for this instance to backStack. 
        myapp.reorderBackStack(); // call this anytime we need to reorder the back stack. 
    } 
    
    @Override 
    public void onNewIntent(Intent newIntent){ 
        this.setIntent(newIntent); 
        myapp.addIntent(this.getIntent()); 
    } 
    
    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
        getMenuInflater().inflate(R.menu.activity_main, menu); 
        return true; 
    } 
    
    @Override 
    // We won't be using the back stack we will be using our own list of intents as a back stack so we need to override the back button. 
    public boolean onKeyDown(int keyCode, KeyEvent event) { 
        if (keyCode == KeyEvent.KEYCODE_BACK) { 
         myapp.goBack(); 
         return true; 
        } 
        return super.onKeyDown(keyCode, event); 
    } 
    

    }

  3. 覆盖的后退按钮,所以我们可以用我们自己的背部栈,而不是Android的。

编辑

我放在一起概念证明。

  • 优点
    • 否别名
    • 完全动态的和可重复使用的
    • 低电平控制
    • 易于使用(扩展CustomBackStackActivity代替FragmentActivity或活性)
  • 缺点
    • 不是开箱即用的解决方案。将需要调整和调试。
我的谷歌驱动器上

.apk is Here

完整project folder is here

拉链downloadable project folder is here

请不要抱怨我的代码。我知道我使用了字符串,我应该使用常量,并且我重复了代码而不是分离它,并且我的间距不够完美,并且我使用了过多的循环和对象。我还没有整理出savedInstanceState。再次,这只是一个概念证明。它的工作原理,我认为这可能有助于某人。

+0

可以扩展此解决方案以添加您的应用所需的任何功能。 – 2012-10-24 02:49:31

+0

谢谢,我喜欢这种风格,但看不到它对避免或优化别名有什么帮助。该问题的主要观点是关于使用REORDER_TO_FRONT或自定义解决方案具有相同的行为,该应用程序具有用于几乎所有全屏视图的主要Activity类。关于如何不产生一组子类活动或声明一组静态别名?我想尽可能地让它变得动态和美丽。 – 2012-10-24 04:36:35

+0

编辑添加onNewIntent – 2012-10-24 05:34:12

2

这里是解决方案:

1.在你FragmentActivity实施Interface从片段到活动回调。

2.当您启动任何片段把它放在后面栈的说法或标签(addToBackStack(String arg0))与帮助,您可以用标签弹出。

3.当你需要重新排列片段然后调用你用正确的参数按规定执行,然后使用popBackStack(String arg1, String arg2)让你把它放在堆栈中的标签片段接口的方法。

+0

谢谢,这是更清楚解释,但与第一个答案相同,因为我解释它似乎没有工作,因为新的Intent处理后,我得到了'FragmentActivity'实例的新片段backStack。我的意思是,如果只有backStack可以共享,但我会创建新的活动来展示。 – 2012-10-26 13:30:05

+0

您无需为此方法使用onNewIntent。 – 2012-10-26 14:29:47

+0

我没有在任何地方使用'onNewIntent',而是'onCreate'根据'Extra'值选择要显示的片段。这给了我一个片段的FragmentActivities堆栈,但他们共享围绕片段的UI代码,并且还使用了其他活动类,所以我真的更喜欢有活动堆栈。如果我必须同时管理碎片和活动堆栈重新排序,那将是一个小小的灾难。 – 2012-10-29 14:59:12

1

我已经回答了类似的东西,但解决的办法不是最好的FA1> FA2> FA3将带你到FA1> FA2而不是FA1> FA3> FA2。

My answer was for question : How to tag Activity

反正我编辑的代码位使用“标签”,这将是一个字符串,但我认为你可以使用使用整数索引的主要解决方案。总之,这应该允许你在fallBackToActivity的某个TAG。我不确定每个活动将如何决定它的标记是什么,但同样,在我之前的回答中,它只是一个增量整数的简单问题。

package sherif.android.stack.overflow; 

import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 

public class SuperActivity extends FragmentActivity { 
    private static String EXTRA_INDEX = "SUPER_INDEX"; 
    private static int RESULT_FALLBACK = 0x123456; 
    private String tag; //this is your tag 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     if(getIntent()!=null) { 
      tag = getIntent().getStringExtra(EXTRA_INDEX, "default_tag"); 
     } 
    } 
    protected final String getIndex() { 
     return tag; 
    } 
    protected final void fallBackToActivity(String tag) { 
     Intent intent = new Intent(); 
     intent.putExtra(EXTRA_INDEX, tag); 
     setResult(RESULT_FALLBACK, intent); 
     finish(); 
    } 
    //@Override 
    //public void startActivityForResult(Intent intent, int requestCode) { 
    // intent.putExtra(EXTRA_INDEX, getIndex()); 
    // super.startActivityForResult(intent, requestCode); 
    //} 
    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 
     if(resultCode == RESULT_FALLBACK) { 
      if(!data.getStringExtra(EXTRA_INDEX, "default_tag").equals(getIndex())) { 
       setResult(RESULT_FALLBACK, data); 
       finish(); 
      } 
     } 
    } 
} 
+0

这是否意味着我需要在开始之前活动的意图之前调用'fallBackToActivity'?我的意思是堆栈是动态的,可能'fallBackToActivity'方法应该返回状态回调。感谢您的回答,请让我知道您对这个小小的澄清的看法。 – 2012-10-29 11:29:51

+0

你需要开始一个新的意图吗?这将返回到具有指定标签的活动。如果fallBackToActivity TAG1,它将返回到tag = TAG1的活动,并且onActivityResult将与您在'setResult'中设置的Intent一起被调用?这不会起作用? – 2012-10-29 12:27:45

+0

正如我所说,堆栈是动态的,我无法预测目标活动是否存在 - 这意味着我可能要开始一个新的而不是回落。如果没有'fallBackToActivity'的回调,我怎么理解新的活动是应该开始还是以前在顶部? – 2012-10-29 14:57:12