【问题标题】:Android best practices to connect activities连接活动的 Android 最佳实践
【发布时间】:2014-04-24 11:35:09
【问题描述】:

我有一个已经实现的应用程序。在这个应用程序中。用户可以从任何其他活动开始任何活动。

我想做什么:

如果请求启动的活动已经存在于历史堆栈中。应该重新启动堆栈上的那个活动,并且应该完成堆栈中在它之前存在的所有活动。

例如:A->B->C->D->E->F 现在我们要启动 D. A B C D 应该完成并且应该开始一个新的 D 实例并保持在堆栈 E->F->D

谢谢,

【问题讨论】:

    标签: android memory-management navigation android-activity


    【解决方案1】:

    为此你有片段:

    我还想推荐使用抽屉式导航实现。

    对于导航抽屉: Navigation drawer link

    片段示例:

    Fragments in android developers

    【讨论】:

      【解决方案2】:

      为什么不使用片段而不是活动?

      【讨论】:

      • 因为应用已经实现了,从Activity到fragment需要大量的工作
      【解决方案3】:

      我在 Tooleap SDK 上工作,还需要同时管理多个活动。这是与我所做的类似的事情。 您可以创建自己的活动管理器类。 每次您的活动开始时,它都会向您的活动管理器注册,如下所示:

      public class ActivityA extends Activity {
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              myActivityManager.register(this)
          }
      }
      

      您的活动管理器类将保存所有已启动活动的数组,并对之前调用的每个活动调用完成,并将它们从数组中删除。请注意,您应该对 Activity 类持有 WeakReferences,以防止上下文泄漏。

      public class MyActivityManager {
      static List<WeakReference<Activity>> sManagedActivityInstances = new ArrayList<WeakReference<Activity>>();
      
          static void register(Activity activity) {
      
              if (isActivityContainedInList()) {
      
                  for (Iterator<WeakReference<Activity>> iterator = sManagedActivityInstances.iterator(); iterator.hasNext(); )
                  {
                     WeakReference<Activity> activityWeakRef = iterator.next();
                     if (isSameActivity(activity, activityWeakRef))
                     {
                         iterator.remove();
      
                         if (activityWeakRef != null) {
                             activityWeakRef.finish();
                         }
                     }
                  }
              }
          }
      }
      

      【讨论】:

      • 您的解决方案也很好用。但是,其他的更详细,他们已经做了更多的努力。谢谢你的回答。
      • 很遗憾我不能分红:)
      • 没关系。很乐意提供帮助:)
      【解决方案4】:

      我也推荐Fragment来满足这个要求,但是由于你的应用程序已经实现了,你可以使用这种方法。

       all the activities that exists before it in the stack should be finished.
      

      Android 没有提供任何标志来清除下面的所有Activities,例如使用clearTop 清除顶部Activities。如果我们有clearBottom 会很简单:)

      好的。如果您的目标是Android API version from 16,这种方法将以优化的方式提供帮助。对于其他较低版本,您需要分别完成每个Activity

      创建一个BaseActivity,它将所有Activity实例添加到HashMap中(类似于添加Fragments to back Stack)。但这里只是记住堆栈中的Activities。您也可以使用ActivityManager.RunningTaskInfo 检查堆栈中的Activities,但我不想让它变得更复杂。

      声明一个静态变量。我更喜欢在我的Application class 中做。

       public class MyApp extends Application {
          public static HashMap<String , CommonActivity > mBackStackActivities
                         = new HashMap<String, CommonActivity>();
        }
      

      现在,当 Activity created 将其实例添加到 HashMap

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          MyApp.mBackStackActivities.put(getComponentName().getClassName(), this);
      }
      

      并且,当Activity destroy删除它

      @Override
      protected void onDestroy(){
          MyApp.mBackStackActivities.remove(getComponentName().getClassName());
          super.onDestroy();
      }
      

      现在,Override base Activity class 中的 startActivity 方法以及 Activity 启动时check if theActivityexists inHashMap. If existsfinishall the belowActivityusingfinishAffinity`。 >

       @Override
      public void startActivity(Intent intent) {
          if(MyApp.mBackStackActivities
              .containsKey(intent.getComponent().getClassName())){
              if(android.os.Build.VERSION.SDK_INT >= 16) {
                  Activity activity = MyApp.mBackStackActivities.get(intent.getComponent().getClassName());
                  // finish the activity as well as all the below Activities.
                  activity.finishAffinity(); // supported from API 16
              }else {
                  // loop through all the below activity and finish it
              }
          }
          super.startActivity(intent);
      }
      

      最后,如果您需要在清单中为所需的Activities 设置android:taskAffinity,默认情况下所有Activities 将具有相同的关联名称(包名称)。如果您希望覆盖您的所有 Activities,则可以保留此信息。

          <activity
              android:name="com.example.app.activities.MainActivity"
              android:label="@string/title_activity_common"
              android:taskAffinity="@string/task_affinity_name">
          </activity>
      

      在字符串 xml 中

      <string name="task_affinity_name">com.example.app.affinity</string>
      

      注意:如上面所说的低版本,您需要单独完成每个Activity`

      在这里找到完整的源代码https://gist.github.com/androidbensin/7d9261fd148c15575dd1

      【讨论】:

      • 我没有完全实现你的方法。我使用 BroadcastReceiver 在 increate 和 ondestroy 方法内的基本活动中注册和取消注册活动。每次我开始一项活动时,我都会向每个已注册的活动发送一条消息,其中包含即将开始的活动。活动本身检查它是否具有相同类型的类,并使用 setResult 将结果发送到下面的每个活动。每个活动都会自行完成,直到开始活动不应该完成,但只有在主题或语言发生变化时才会重新加载。
      • 我喜欢你的方法。我会试试这个。我希望你已经在 manifest 中注册了接收广播事件的活动,因为如果我们在代码中注册并且当活动处于暂停状态时将不会接收到广播事件。
      【解决方案5】:

      如果您打算针对旧版本的 android,那么片段可能不是其他人规定的最佳选择。因为 Android 3.0 或 Honeycomb 带来了基本的用户界面变化,最引人注目的是 Fragment API 的形式。

      如果您只想从历史堆栈中删除活动并完成活动,同时将意图传递给另一个活动是您的需要,那么

      您可以从您的 AndroidManifest.xml 文件中实现它,只需通过 在你想要的那些中添加 android:noHistory="true" 属性

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-07
        • 2012-10-10
        • 2011-12-26
        • 1970-01-01
        • 1970-01-01
        • 2015-03-25
        • 2023-04-08
        • 1970-01-01
        相关资源
        最近更新 更多