Android 系列 6.4通过将视图从模型中去耦来处理配置更改
2017-01-11 09:09
363 查看
6.4通过将视图从模型中去耦来处理配置更改
问题
当设备的配置更改(最常见的是因为方向更改)时,您的活动将被销毁并重新创建,从而使状态信息难以维护。
解
将您的用户界面从数据模型中分离,以便销毁活动不会影响您的状态数据。
讨论
这是一种情况,每个Android开发人员(除了那些谁阅读本书的这部分时间)与他们的第一个应用程序:“我的应用程序工作很好,但是当我改变我的手机的方向一切都重置!
根据设计,当设备的配置(读取:方向)更改时,Android UI框架会销毁当前活动并为新配置重新创建。
这使得设计者能够针对不同的屏幕取向和尺寸优化布局。然而,这对于希望维持活动的状态的开发者造成问题,因为它在取向改变破坏屏幕之前。
尝试解决这个问题可能导致许多复杂的解决方案,一些比其他更优雅。但如果我们退后一步,明智地设计我们的应用程序,我们可以编写更干净,更强大的代码,使生活更容易为每个人。
图形用户界面(GUI)正是其名称所描述的。它是底层数据模型的图形表示,允许用户与数据接口并操作数据。它不是数据模型本身。让我们通过一个例子来说明为什么这是一个重要的要点。
考虑一个井字游戏应用程序。一个简单的主要活动,这将最有可能包括在最低限度一个GridView(使用适当的适配器)显示板和一个TextView告诉用户的轮到它。当用户单击网格中的正方形时,在该网格单元中放置适当的X或O。作为新的Android开发人员,我们发现逻辑上还包括一个二维数组,其中包含了一个表示板的数据来存储数据,这样我们可以确定游戏是否结束,如果是的话,谁赢了(见例6-3 )。
实例6-3。 TicTacToe活动类的第一版本
在阅读示例6-3中的代码时,您可能对自己说,“嘿,Bundle savedInstanceState看起来很有前途!”你说得对。对于这个痛苦,几乎刑事简单的例子,你可以把你的板数据到捆绑,并使用它来重新加载您的屏幕。甚至有一对方法,onRetainNonConfigurationInstance()和getLastNonConfigurationInstance(),让你传递任何你想要的对象从旧的,销毁的活动,到你新创建的。对于这个例子,你可以传递你的mBoardState数组到你的新Activity,你会被设置。但是我们每天都会写出大的,成功的,令人惊叹的应用程序,而且这些应用程序不能很好地适用于复杂的接口。我们可以做得更好!
这就是为什么将GUI从数据模型中分离得那么方便。您的GUI可以被销毁,重新创建和更改,但基础数据可以通过尽可能多的UI更改无懈可击,你可以抛出它。让我们将我们的游戏状态分成一个单独的数据类(见例6-4)。
实施例6-4。 TicTacToe类分
这不仅有助于我们保持我们的应用程序状态,但它通常只是良好的面向对象的设计。
现在我们的数据安全地在volatile Activity之外,我们如何访问它来构建我们的界面?有两种常见的方法:1)将TicTacToeGame中的所有变量声明为静态,并通过静态方法访问它们; 2)将TicTacToeGame设计为单例,允许访问一个全局实例以在我们的应用程序中使用。
我更喜欢第二个选项纯粹从设计的角度。我们可以将TicTacToeGame转换为单例,方法是将构造函数设为private,并在类的顶部添加以下几行:
现在我们要做的是获取游戏数据,并设置我们的UI元素以适当地显示数据。最有用的是将其封装在自己的function-refreshUI()中,以便在Activity对数据进行更改时使用。例如,当用户单击板的单元格时,监听器只需要两行代码:一次调用修改数据模型(通过我们的TicTacToeGame单例),一次调用刷新UI。
这可能是显而易见的,但值得一提的是,只要应用程序的进程正在运行,您的数据类就会继续存在。如果它被用户或系统杀死,自然数据丢失。这种情况需要通过文件系统或数据库进行更持久的存储,并且超出了本文的范围。
这种方法非常有效地将数据的视觉表示与数据本身分离,并使取向变化无关紧要。只需在onCreate(Bundle)方法中调用refreshUI()就足以确保当Activity被销毁和重新创建时,它可以访问数据模型并正确显示它。
作为一个额外的好处,你现在正在练习更好的面向对象的设计,并将看到你的代码基础变得更干净,更可扩展,更容易维护。
问题
当设备的配置更改(最常见的是因为方向更改)时,您的活动将被销毁并重新创建,从而使状态信息难以维护。
解
将您的用户界面从数据模型中分离,以便销毁活动不会影响您的状态数据。
讨论
这是一种情况,每个Android开发人员(除了那些谁阅读本书的这部分时间)与他们的第一个应用程序:“我的应用程序工作很好,但是当我改变我的手机的方向一切都重置!
根据设计,当设备的配置(读取:方向)更改时,Android UI框架会销毁当前活动并为新配置重新创建。
这使得设计者能够针对不同的屏幕取向和尺寸优化布局。然而,这对于希望维持活动的状态的开发者造成问题,因为它在取向改变破坏屏幕之前。
尝试解决这个问题可能导致许多复杂的解决方案,一些比其他更优雅。但如果我们退后一步,明智地设计我们的应用程序,我们可以编写更干净,更强大的代码,使生活更容易为每个人。
图形用户界面(GUI)正是其名称所描述的。它是底层数据模型的图形表示,允许用户与数据接口并操作数据。它不是数据模型本身。让我们通过一个例子来说明为什么这是一个重要的要点。
考虑一个井字游戏应用程序。一个简单的主要活动,这将最有可能包括在最低限度一个GridView(使用适当的适配器)显示板和一个TextView告诉用户的轮到它。当用户单击网格中的正方形时,在该网格单元中放置适当的X或O。作为新的Android开发人员,我们发现逻辑上还包括一个二维数组,其中包含了一个表示板的数据来存储数据,这样我们可以确定游戏是否结束,如果是的话,谁赢了(见例6-3 )。
实例6-3。 TicTacToe活动类的第一版本
public class TicTacToeActivity extends Activity { private TicTacToeState[][] mBoardState; private GridView mBoard; private TextView mTurnText; @Override public void onCreate(Bundle savedInstanceState) { setContentView(R.layout.main); mBoardState = new TicTacToeState[3][3]; mBoard = (GridView)findViewById(R.id.board); mTurnText = (TextView)findViewById(R.id.turn_text); // ... Set up Adapter, OnClickListeners, etc., for mBoard. } }这很容易想象和实现,一切都很好。除了当你把你的手机侧身在一个强烈的一轮井字游戏的中间,你有一个新的板,盯着你的脸,你的不可避免的胜利被推迟。如前所述,UI框架刚刚销毁了您的Activity并重新创建它,调用onCreate()和重置板数据。
在阅读示例6-3中的代码时,您可能对自己说,“嘿,Bundle savedInstanceState看起来很有前途!”你说得对。对于这个痛苦,几乎刑事简单的例子,你可以把你的板数据到捆绑,并使用它来重新加载您的屏幕。甚至有一对方法,onRetainNonConfigurationInstance()和getLastNonConfigurationInstance(),让你传递任何你想要的对象从旧的,销毁的活动,到你新创建的。对于这个例子,你可以传递你的mBoardState数组到你的新Activity,你会被设置。但是我们每天都会写出大的,成功的,令人惊叹的应用程序,而且这些应用程序不能很好地适用于复杂的接口。我们可以做得更好!
这就是为什么将GUI从数据模型中分离得那么方便。您的GUI可以被销毁,重新创建和更改,但基础数据可以通过尽可能多的UI更改无懈可击,你可以抛出它。让我们将我们的游戏状态分成一个单独的数据类(见例6-4)。
实施例6-4。 TicTacToe类分
public class TicTacToeGame { private TicTacToeState[][] mBoardState; public TicTacToeGame() { mBoardState = new TicTacToeState[3][3]; // ... Initialize } public TicTacToeState getCellState(int row, int col) { return mBoardState[row][col]; } public void setCellState(int row, int col, TicTacToeState state) { mBoardState[row][col] = state; } // ... Other utility methods to determine whose turn it is, if the game is over, etc. }
这不仅有助于我们保持我们的应用程序状态,但它通常只是良好的面向对象的设计。
现在我们的数据安全地在volatile Activity之外,我们如何访问它来构建我们的界面?有两种常见的方法:1)将TicTacToeGame中的所有变量声明为静态,并通过静态方法访问它们; 2)将TicTacToeGame设计为单例,允许访问一个全局实例以在我们的应用程序中使用。
我更喜欢第二个选项纯粹从设计的角度。我们可以将TicTacToeGame转换为单例,方法是将构造函数设为private,并在类的顶部添加以下几行:
private static TicTacToeGame instance = new TicTacToeGame(); public static TicTacToeGame getInstance() { return instance; };
现在我们要做的是获取游戏数据,并设置我们的UI元素以适当地显示数据。最有用的是将其封装在自己的function-refreshUI()中,以便在Activity对数据进行更改时使用。例如,当用户单击板的单元格时,监听器只需要两行代码:一次调用修改数据模型(通过我们的TicTacToeGame单例),一次调用刷新UI。
这可能是显而易见的,但值得一提的是,只要应用程序的进程正在运行,您的数据类就会继续存在。如果它被用户或系统杀死,自然数据丢失。这种情况需要通过文件系统或数据库进行更持久的存储,并且超出了本文的范围。
这种方法非常有效地将数据的视觉表示与数据本身分离,并使取向变化无关紧要。只需在onCreate(Bundle)方法中调用refreshUI()就足以确保当Activity被销毁和重新创建时,它可以访问数据模型并正确显示它。
作为一个额外的好处,你现在正在练习更好的面向对象的设计,并将看到你的代码基础变得更干净,更可扩展,更容易维护。
相关文章推荐
- cocos2d-x通过build_natice.sh编译成android时不用每次更改Android.mk文件处理
- 菜鸟学android——配置更改导致应用异常的处理方案
- 数学之美 系列三 -- 隐含马尔可夫模型在语言处理中的应用
- [原创]手动配置Ubuntu Linux系列6:通过ssh远程管理服务器
- 【Android开发学习系列】(1)——Windows下Android开发环境配置
- 处理模型——通过定义一个自定义的TypeWriter和TypeReader直接处理顶点位置数据
- 处理模型——通过扩展模型处理器直接处理每个ModelMesh的顶点位置数据
- iBatisnet系列(二) 配置运行环境和日志处理
- android HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理 (1)
- 不通过SPS对象模型更改文档扩展字段的方法
- 系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- 通过machineKey配置解决asp.net验证视图状态MAC失败的问题
- 通过链接服务器查询视图得到“意外的Null值(MessageID:7342)”错误的处理方法
- 系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- 系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- 轻量级ORM开发系列:缓存类信息以及配置文件的处理
- .NET 2.0 中的自定义配置处理——编程模型
- 系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- iBatisnet系列(二) 配置运行环境和日志处理
- enoeht的Java源码系列(3)--处理配置文件