如何宣布全球的变量。
-
22-08-2019 - |
题
我创造一个应用程序,它要求登录。我创造了主和登录的活动。
在主要活动 onCreate
方法我加入以下条件:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
loadSettings();
if(strSessionString == null)
{
login();
}
...
}
的 onActivityResult
方法是执行当登录的形式终止是这样的:
@Override
public void onActivityResult(int requestCode,
int resultCode,
Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode)
{
case(SHOW_SUBACTICITY_LOGIN):
{
if(resultCode == Activity.RESULT_OK)
{
strSessionString = data.getStringExtra(Login.SESSIONSTRING);
connectionAvailable = true;
strUsername = data.getStringExtra(Login.USERNAME);
}
}
}
问题是登录的形式有时出现两次(在 login()
方法是所谓的两次)和也当的手机键盘上的滑梯的登录的形式再次出现的和我想的问题是变量 strSessionString
.
任何人都不会知道如何设置的可变全球以避免登录的形式出现之后的用户已经成功地进行身份验证?
解决方案
我写了这个答案回'09当机是相对较新,且有许多不确立区域在安卓发展。我已经增加了一个长期增编的员额,解决了一些批评,并详细说明一个哲学分歧,我已使用的单身人士而不是继承的应用程序。读它在你自己的风险。
原来的回答:
更为一般的问题,你遇到的是如何保存国家在多个活动及所有部分应用程序。一个静态的变量(例如,一个单一实例)是一个共同Java的方式实现这一目标。我们发现的是,一个更优雅的方式在安卓是将你的状态应用的上下文。
如你所知,每个活动也是一个上下文,这是关于其执行环境中的广泛的意义。你的应用程序也具有一背景下,安卓保证,它将存在,作为一个单一实例在你的应用程序。
这样做的方法是创建自己的子 序。应用程序。应用程序, 然后指定这类中的应用程序的标签在你的清单。现在机器人将自动创建一个实例,类,并使其可用于整个应用程序。你可以从任何 context
使用 Context.getApplicationContext()
方法(Activity
还提供了一种方法 getApplication()
它具有完全相同的效果)。以下是一个非常简化的例子,说明如下:
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
这基本上具有相同的效果,如使用静态变或单独,但集颇有进入现有的安卓框架。注意,这不会的工作程序(应你的程序是一个罕见的那些有多个过程)。
东西从上面的例子;假设我们不是做这样的:
class MyApp extends Application {
private String myState = /* complicated and slow initialization */;
public String getState(){
return myState;
}
}
现在这个缓慢的初始化(例如打盘、打击网络中,任何东西阻塞等等)将执行的每一次应用的实例!你可能会觉得,嗯,这是仅有一次的进程,我将必须支付的成本不管怎么说,对吗?例如,作为黛安Hackborn提到以下,这完全是可能的对你进程要实例只是处理一背景广播事件。如果你的广播处理具有不需要用于这种状态下,你有可能只是做一个完整的系列复杂和缓慢的操作什么。懒惰的实例是游戏的名字在这里。以下是一个稍微更加复杂的方式使用应用程序,这使得更有意义的东西,但是最简单的用途:
class MyApp extends Application {
private MyStateManager myStateManager = new MyStateManager();
public MyStateManager getStateManager(){
return myStateManager ;
}
}
class MyStateManager {
MyStateManager() {
/* this should be fast */
}
String getState() {
/* if necessary, perform blocking calls here */
/* make sure to deal with any multithreading/synchronicity issues */
...
return state;
}
}
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyStateManager stateManager = ((MyApp)getApplicationContext()).getStateManager();
String state = stateManager.getState();
...
}
}
虽然我喜欢申请继承使用单在这里作为更优雅的方案,我宁愿的开发人员使用的单身如果真的有必要在不想在所有通过性和多线程的影响的相关国家,与应用程序的子类。
注1: 还为anticafe评论说,为了正确地配合你的应用程序的复盖到应用程序的一个标签是必要的清单的文件。再见卓docs更多的信息。一个例子:
<application
android:name="my.application.MyApp"
android:icon="..."
android:label="...">
</application>
注2: user608578问下这是怎么运作与管理机对象的生命周期。我不是高速度上使用机代码与安卓有丝毫的,我没有资格回答如何,将进行交互与我的解决方案。如果有人没有回答这个,我愿意以信用他们,并将这些信息放在这个岗位于最大的能见度。
增编:
因为有些人已经指出的,这是 不 一个解决方案 持久性 状态,这东西我或许应该有更强调在原来的答案。I.e。这是不是意味着是一个解决方案,用于节能的用户或其他信息,就是要坚持跨应用程序的使用寿命。因此,我认为大多数批评以下有关的应用被杀害在任何时间,等...,没有实际意义,因为任何以往任何时候都需要保留到磁盘中不应存储通过应用的亚类。它意味着是一个解决方案,用于存储临时性的,很容易重新创建的应用状态(不论是一个用户登录在例如)和元件这个实例(应用程序的网络管理实例)(不 单身!) 在自然界中。
Dayerman已经够指出一个有趣的 对话与Reto尔和戴安娜Hackborn 在其使用的应用程序类不赞成单独的模式。Somatik还指出东西的这种性质前,我虽然没看到它的时候。因为雷托和戴安娜的作用在维持的,我不能在诚信的建议忽视了他们的意见。他们说什么,去。我希望不同意的意见,表示方面宁愿单独超过应用程序的子类。在我不同意,我将使用的概念最好的解释 这个回答#解释的单独的设计图案, 我没有定义条款中的这个答案。我强烈鼓励掠的链接之前继续进行。点点:
Dianne国,"没有理由的子类,从应用程序。这不是不同于制作一个单独的..."这一要求是不正确的。主要有两个原因。1)应用程序类提供一个更好的生保证应用程序开发者;这是保证有用寿命。一个单一实例是不明确绑生的应用程序(虽然它是有效的).这可能是一个非问题般应用程序开发,但是我认为正是这种类型的合同安卓API应提供的,它提供了更多的灵活性,以卓系统以及通过最大限度地减少生的相关数据。2)应用程序类提供应用程序开发者与一个单一实例的持有人为国家,这是非常不同的一个单独的持有人的状态。用于清单的差异,看到单独解释。
戴安娜的继续,"...只是可能的东西你感到遗憾的是,在未来为你找到你应用程序的对象,成为这个大的纠缠混乱的应该是什么独立应用程序的逻辑。" 这当然是不正确的,但这不是一个原因选择单独遍应用的亚类。没有戴安娜的辩论提供一个原因是,使用一个单一实例是好于一个应用程序类中,所有她试图建立是,使用一个单一实例是没有比一个应用程序的子类,我认为这是错误的。
她继续说,"这导致更多的当然怎样你应该管理这些东西-初始化他们的需求。" 这忽略了一个事实,即没有理由不能初始化上的需求使用的应用程序的子类。再次,没有差别。
Dianne结束"的框架本身具有成吨的单对所有的点共享数据它维持的应用程序,例如缓存的装载资源,游泳池的对象,等等。它的伟大工程。" 我不认为使用单身不能工作或是不合法的替代方案。我认为单没有提供作为强劲的合同的系统使用的应用程序的子类,并进一步使用单一般点不灵活设计,这是不容易修改,并导致许多问题。恕我直言,强合同安卓API提供开发的应用程序是一个最有吸引力的和令人愉悦的方面编程与安卓,并且帮助导致早期开发人员通过其驾驶平台,它的成功有今天。这表明使用单一实例是隐含地移动的距离从一个强大的API合同,并且在我看来,削弱了卓框架。
戴安娜出了评论如下,提及一个额外的缺点使用的应用程序子类,它们可能会鼓励或使其更易于编写不绩效代码。这是非常真实的,并且我编辑这个答案强调的重要性,考虑到perf这里,并采取正确的做法如果使用的应用程序子类化。因为黛安的国家,重要的是要记住,你的应用程序类将实例每次你进程是载入(可能是多次在一次,如果应用程序运行在多个进程!) 即使该过程仅载于一份背景的广播活动。因此,重要的是使用的应用程序类更多的储存库为指针,以共享的组成部分应用,而不是作为一个地方做任何处理!
我留给你的下列缺点单,作为被盗从较早的回答#链接:
- 无法使用的抽象或接口类;
- 无力的子类;
- 高耦合应用程序(难修改);
- 难以测试(可以不假/模拟在单元的测试);
- 难以并行的情况下可变的状态(需要广泛的锁定);
并加入我自己的:
- 不清和难以控制的终生合同不适用于安卓(或大多数其他)的发展;
其他提示
创建这个子类
public class MyApp extends Application {
String foo;
}
在AndroidManifest.xml中添加机器人:名称
示例强>
<application android:name=".MyApp"
android:icon="@drawable/icon"
android:label="@string/app_name">
保持的状态下用于该应用程序的建议通过Soonil方式是良好的,但是它有一个薄弱点 - 存在这样的情况OS杀死整个应用程序时。下面是在此的文档 - 进程和生命周期
考虑这样一种情况 - 你的应用程序进入后台,因为有人给你打电话(手机应用程序在前台现)。在这种情况下&&一些其他的条件下(查看上面的链接,它们可能是什么)操作系统可能会杀死你的应用程序,包括Application
子类的实例。因此,该状态会丢失。当您稍后返回给应用程序,那么操作系统将恢复其活性堆栈和Application
子类的实例,但是myState
字段将null
。
AFAIK,以保证安全性的状态的唯一的方法是使用持续的状态下,例如任何种类使用专用的应用程序文件或SharedPrefernces
(它最终使用专用于内部文件系统的应用程序文件)。
只是说明..
添加:
android:name=".Globals"
或任何你叫你的子类的现有 <application>
标签。我一直试图另一个<application>
标签添加到清单,并会得到一个异常。
我找不到如何可以指定应用程序的标签,但是很多谷歌搜索后,从清单文件文档变得越来越明显:采用Android:名称,除了在应用程序节默认的图标和标签。
机器人:名称 为应用程序实现的Application子类的全名。当开始应用过程中,这个类是之前的任何应用程序的组件的实例化。
子类是可选的;大多数应用程序并不需要一个。在不存在子类,Android使用的碱的应用类的一个实例。
要确保本机内存的收集与这样的全球结构是什么?
活动具有真实时破坏被称为onPause/onDestroy()
方法,但应用类没有等价物。建议使用哪些机制,以确保全球结构(尤其是天然存储器那些含有参考)的垃圾收集适当的应用程序被杀死或任务堆栈放置在后台当?
只要你需要定义像下面这些应用程序的名称将工作:
<application
android:name="ApplicationName" android:icon="@drawable/icon">
</application>
像有上述操作系统讨论可以杀死没有任何通知应用程序(不存在的onDestroy事件),所以没有办法保存这些全局变量。
SharedPreferences可能是一个解决办法,除非你有复杂的结构性变量(在我的情况下,我不得不整型数组来存储用户已经办理的ID)。与SharedPreferences的问题是,它难以存储和检索,这些结构中的每个值所需要的时间。
在我来说,我有一个后台服务,所以我可以移动这个变量那里,因为该服务具有的onDestroy的事件,我可以很容易地保存这些值。
如果一些变量存储在SQLite和您必须在大多数活动在您的应用程序中使用它们。 然后,应用程序也许是最好的方式来实现它。 从数据库中查询的变量时,启动应用程序,并将它们存储在一个领域。 然后,您可以在活动中使用这些变量。
所以找到合适的方式,并没有最好的方法。
您可以有一个静态字段来存储这种状态。或者把它放到资源包,并从那里的onCreate(捆绑savedInstanceState)恢复。只要确保你完全理解Android应用程序生命周期管理(例如为什么登录()被调用键盘上的方向改变)。
不要使用另一个<application>
标签清单中file.Just不要在现有<application>
标签一个变化,加入这一行android:name=".ApplicationName"
其中,ApplicationName
将是你的子类的名称(可以用来存储全局)的是,你是要创建。
所以,最后您的 ONE AND ONLY 清单文件<application>
标签应该是这样的: -
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:name=".ApplicationName"
>
可以使用意图,SQLite的,或共用首选项。当涉及到媒体存储,如文档,照片和视频,您可以创建新的文件,而不是。
你可以做这种使用两种方法:
- 使用的应用程序类
使用共同的喜好
使用的应用程序类
例如:
class SessionManager extends Application{
String sessionKey;
setSessionKey(String key){
this.sessionKey=key;
}
String getSessisonKey(){
return this.sessionKey;
}
}
你可以使用上述类实现登录在您的重置如下。代码看起来像这样的东西:
@override
public void onCreate (Bundle savedInstanceState){
// you will this key when first time login is successful.
SessionManager session= (SessionManager)getApplicationContext();
String key=getSessisonKey.getKey();
//Use this key to identify whether session is alive or not.
}
这种方法将作为临时储存。你真的不知道当时的操作系统是会杀了应用程序,因为低存储器。当应用程序的背景和用户浏览过的其他应用程序,它要求更多的存储器运行,那么你的应用程序将以来被杀害的操作系统给予更多的优先前景进程的比的背景。因此,你的应用对象将是空前的用户登录。因此,为了这个,我建议使用第二种方法规定的上述。
使用共同的偏好。
String MYPREF="com.your.application.session" SharedPreferences pref= context.getSharedPreferences(MyPREF,MODE_PRIVATE); //Insert key as below: Editot editor= pref.edit(); editor.putString("key","value"); editor.commit(); //Get key as below. SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE); String key= getResources().getString("key");
在活动结果,在恢复之前调用。所以移动您登录检查,在恢复,一旦secomd活动返回一个积极的结果你的第二个登录会被阻止。在恢复被称为每次所以没有它的担忧没有被称为第一次。
子类的方法也被使用的BARACUS框架。从我的观点来看的子类强>应用的目的随着Android的生命周期的工作;这是任何应用程序容器一样。而不是全局的,然后,我注册了豆这种情况下的让他们beeing注入任何类上下文管理。每次注射bean实例实际上是一个单例。
为什么做手工的工作,如果你能有这么多?
class GlobaleVariableDemo extends Application {
private String myGlobalState;
public String getGlobalState(){
return myGlobalState;
}
public void setGlobalState(String s){
myGlobalState = s;
}
}
class Demo extends Activity {
@Override
public void onCreate(Bundle b){
...
GlobaleVariableDemo appState = ((GlobaleVariableDemo)getApplicationContext());
String state = appState.getGlobalState();
...
}
}
您可以创建一个扩展Application
类的类,然后声明您的变量作为类的字段和用于将其提供getter方法。
public class MyApplication extends Application {
private String str = "My String";
synchronized public String getMyString {
return str;
}
}
和然后访问在活动变量,使用:
MyApplication application = (MyApplication) getApplication();
String myVar = application.getMyString();