如何在Android应用程序中传递活动之间的数据?

1533

我有这样一个情况,通过登录页面登录后,每个活动页面上都会有一个“退出”按钮

点击“退出”后,我将传递已登录用户的会话ID以进行注销。 有人能指导我如何使会话ID在所有活动中可用吗?

这种情况是否有任何替代方案?


18
我使用了sharedpreference,它对于在“记住密码”功能中保存登录数据也很有用。 - shareef
这对我有效。 感谢Darshan Computing。 - matasoy
这篇回答可能会对您有所帮助:https://dev59.com/RHE85IYBdhLWcg3whD7k#37774966 - Yessy
对于这种情况,尝试使用commonUtils类和sharedpreferences方法... 这将使代码保持清晰,并将相关数据放在一个地方。您将能够仅通过清除特定的偏好文件的一个方法来清除特定集合的数据,而不会清除任何默认应用程序数据... - Muahmmad Tayyib
53个回答

1518

在您当前的 Activity 中,创建一个新的 Intent

String value="Hello world";
Intent i = new Intent(CurrentActivity.this, NewActivity.class);    
i.putExtra("key",value);
startActivity(i);

然后在新的Activity中检索这些值:

Bundle extras = getIntent().getExtras();
if (extras != null) {
    String value = extras.getString("key");
    //The key argument here must match that used in the other activity
}

使用这种技术可以将变量从一个 Activity 传递到另一个 Activity。


76
对于像我这样盲目的人来说,提供一个信息:如果您在当前活动中放置了一个整数,那么您必须通过 extras.getInt("new_variable_name") 在新活动中获取它。 如果您尝试通过 getString() 获取它,Android 会认为它是一个整数并返回 null! - bish
7
如果某个活动已经在运行,那么是否需要执行 startActivity(i); 呢?我的意思是,我能否让“活动A”调用“活动B”,然后将数据返回给“活动A”?我是否有些困惑? - Francisco Corrales Morales
3
这是一个不错的例子,展示了如何设置和获取Intent额外信息。链接为:http://www.codota.com/android/scenarios/52fcbcffda0ace249b7bce8e/android.content.Intent?tag=dragonfly - drorw
1
我更喜欢字符串变量。你总是可以稍后将字符串转换为整数或浮点数。 - user914425
@FranciscoCorralesMorales 你找到什么了吗? - Chagai Friedlander
有没有办法在所有活动之间传递变量? - Sonny P.

1459

最简单的方法是将会话ID传递给你用来启动活动的Intent中的signout活动:

Intent intent = new Intent(getBaseContext(), SignoutActivity.class);
intent.putExtra("EXTRA_SESSION_ID", sessionId);
startActivity(intent);

在下一个活动中访问该意图:

String sessionId = getIntent().getStringExtra("EXTRA_SESSION_ID");

Intent的文档提供了更多信息(查看标题为“Extras”的部分)。


8
是的,您需要使会话 ID 可在您希望允许用户退出登录的每个活动中使用。或者,您可以将其存储在 Application 对象中,但这样您就需要管理会话状态(在使用之前检查其是否有效等)。 - Erich Douglass
如果目标活动已在后台运行,这是否有效?我的onResume函数总是只保留第一个意图。 - wutzebaer
1
请注意,文档指出以下内容:向意图添加扩展数据。名称必须包括包前缀,例如应用程序com.android.contacts将使用类似于“com.android.contacts.ShowAll”的名称。 - Serguei Fedorov
1
而要从其他Activity读取数据,请使用Long session_ids=getIntent().getExtras().getLong("EXTRA_SESSION_IDS"); - Farid
1
我们如何使用setData传递数据,并且这两种方法有什么区别?哪一种更好? - Hosein Aqajani
显示剩余5条评论

150

如 Erich 所说,传递 Intent extras 是个好方法。

Application 对象也是另一种方式,有时处理多个活动之间相同状态(而不是到处获取/放置它),或更复杂的对象比原始类型和字符串更容易。你可以扩展 Application,然后设置/获取任何你想要的内容,并使用 getApplication() 从任何 Activity (在同一个应用程序中) 访问。

还要记住,你可能看到的其他方法(如静态方法)可能会导致内存泄漏。Application 也有助于解决这个问题。


9
支持这个静态问题。可能可以通过将单例与Application类的onCreate/onTerminate方法结合起来来解决清理问题。 - Syd
13
嗨,我知道这个帖子是一段时间之前的了,但是提供的链接现在已经失效了。有没有其他地方可以找到这个例子? - JuiCe
@JuiCe《Android Developers》关于内存泄漏的博客文章已经不再无效。 - Edric

107

源类:

Intent myIntent = new Intent(this, NewActivity.class);
myIntent.putExtra("firstName", "Your First Name Here");
myIntent.putExtra("lastName", "Your Last Name Here");
startActivity(myIntent)

目标类(NewActivity类):

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.view);

    Intent intent = getIntent();

    String fName = intent.getStringExtra("firstName");
    String lName = intent.getStringExtra("lastName");
}

3
意图是否可能为空?我们是否应该检查它不为空? - Micro
这是一个重复的问题,与3年前的最高票答案Sahil Mahajan Mj的答案Mayank Saini的答案相同。 - Murmel

90
你只需要在调用意图时发送额外的内容。
像这样:

你只需要在调用意图时发送额外的内容。

就像这样:

Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
intent.putExtra("Variable name", "Value you want to pass");
startActivity(intent);

现在在您的SecondActivityOnCreate方法中,您可以像这样获取额外信息。

如果您发送的值是long:

long value = getIntent().getLongExtra("Variable name which you sent as an extra", defaultValue(you can give it anything));

如果你发送的值是一个字符串

String value = getIntent().getStringExtra("Variable name which you sent as an extra");

如果您发送的值是 Boolean 类型:

Boolean value = getIntent().getBooleanExtra("Variable name which you sent as an extra", defaultValue);

4
请注意,文档指出以下内容:向意图添加扩展数据。名称必须包括包前缀,例如应用程序 com.android.contacts 将使用类似于“com.android.contacts.ShowAll”的名称。 - Serguei Fedorov
这是一个重复的答案,与排名最高的答案相同,该答案在此之前已经存在了2年,并且与Sahil Mahajan Mj的答案相同,只有一个区别:对于booleanlong getter的示例,这值得评论,但不是一个答案。 - Murmel

76

它帮助我在上下文中看待事物,这里有两个例子。

向前传递数据

输入图像描述

主活动

  • 使用键值对将要发送的数据放入Intent中。有关键名称约定,请参见此答案
  • 使用startActivity启动第二个活动。

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // "Go to Second Activity" button click
    public void onButtonClick(View view) {

        // get the text to pass
        EditText editText = (EditText) findViewById(R.id.editText);
        String textToPass = editText.getText().toString();

        // start the SecondActivity
        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra(Intent.EXTRA_TEXT, textToPass);
        startActivity(intent);
    }
}

第二个活动

  • 使用getIntent()方法获取启动第二个活动的Intent。然后,您可以使用getExtras()方法和在第一个活动中定义的键提取数据。由于我们的数据是一个字符串,因此我们将在此处仅使用getStringExtra方法。

SecondActivity.java

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        // get the text from MainActivity
        Intent intent = getIntent();
        String text = intent.getStringExtra(Intent.EXTRA_TEXT);

        // use the text in a TextView
        TextView textView = (TextView) findViewById(R.id.textView);
        textView.setText(text);
    }
}

传递数据回来

enter image description here

主活动

  • 使用startActivityForResult启动第二个活动,并提供任意结果代码。
  • 覆盖onActivityResult。这将在第二个活动完成时调用。您可以通过检查结果代码确保它实际上是第二个活动。(当您从同一个主活动启动多个不同的活动时,这很有用。)
  • 提取从返回的Intent中获取的数据。使用键值对提取数据。我可以为键使用任何字符串,但由于我正在发送文本,因此将使用预定义的Intent.EXTRA_TEXT

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private static final int SECOND_ACTIVITY_REQUEST_CODE = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // "Go to Second Activity" button click
    public void onButtonClick(View view) {

        // Start the SecondActivity
        Intent intent = new Intent(this, SecondActivity.class);
        startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE);
    }

    // This method is called when the second activity finishes
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // check that it is the SecondActivity with an OK result
        if (requestCode == SECOND_ACTIVITY_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {

                // get String data from Intent
                String returnString = data.getStringExtra(Intent.EXTRA_TEXT);

                // set text view with string
                TextView textView = (TextView) findViewById(R.id.textView);
                textView.setText(returnString);
            }
        }
    }
}

第二个活动

  • 将要返回到上一个活动的数据放入Intent中。使用键值对将数据存储在Intent中,我选择使用Intent.EXTRA_TEXT作为我的键。
  • 将结果设置为RESULT_OK并添加保存数据的意图。
  • 调用finish()关闭第二个活动。

SecondActivity.java

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

    // "Send text back" button click
    public void onButtonClick(View view) {

        // get the text from the EditText
        EditText editText = (EditText) findViewById(R.id.editText);
        String stringToPassBack = editText.getText().toString();

        // put the String to pass back into an Intent and close this activity
        Intent intent = new Intent();
        intent.putExtra(Intent.EXTRA_TEXT, stringToPassBack);
        setResult(RESULT_OK, intent);
        finish();
    }
}

4
哇,谢谢!这正是我在寻找的。当使用相机或其他外部设备时,期望有返回结果是显而易见的,但我没有想到可以在内部使用它。你是第一个如此公开地提出这个想法的人。 - user3195231

50

更新:请注意,我曾经提到过使用SharedPreference。它有一个简单的API,并且可在应用程序的所有活动中访问。但是这种方法很笨拙,并且如果传递敏感数据时会存在安全风险。最好使用意图(intents)。它具有广泛的重载方法列表,可用于在活动之间更好地传输许多不同的数据类型。请查看intent.putExtra。这个链接很好地介绍了putExtra的使用。

在活动之间传递数据时,我的首选方法是为相关活动创建静态方法,该方法包括所需的参数并启动意图。然后可以轻松设置和检索参数。因此,它可能看起来像这样:

public class MyActivity extends Activity {
    public static final String ARG_PARAM1 = "arg_param1";
...
public static getIntent(Activity from, String param1, Long param2...) {
    Intent intent = new Intent(from, MyActivity.class);
        intent.putExtra(ARG_PARAM1, param1);
        intent.putExtra(ARG_PARAM2, param2);
        return intent;
}

....
// Use it like this.
startActivity(MyActvitiy.getIntent(FromActivity.this, varA, varB, ...));
...

然后您可以为预期的活动创建一个意图,并确保您拥有所有参数。您也可以针对片段进行适应。上面是一个简单的示例,但您可以理解这个想法。


2
我最喜欢你的答案了... 通过Intent传递意味着几乎在我启动一个活动的任何地方,你都必须记得包含sessionId。将其放入SharedPreferences中,您可以随时从任何活动中获取它。 :0) - bytebender
@bytebender 我知道回复有点晚了,感谢你喜欢我的原始答案的简洁性,但是我会小心存储会话ID在共享首选项中。如果必须将其存储在硬存储中,则请使用加密。如果可以使用采用JWT的身份验证框架,则它将包括refreshTokens,这对于长期存储更安全,然后将当前会话令牌作为自定义应用程序对象的公共属性保留以轻松访问身份验证令牌,并减少活动意图签名的开销。 - angryITguy

41

尝试按照以下步骤操作:

创建一个简单的“帮助程序”类(用于创建Intents的工厂),例如:

import android.content.Intent;

public class IntentHelper {
    public static final Intent createYourSpecialIntent(Intent src) {
          return new Intent("YourSpecialIntent").addCategory("YourSpecialCategory").putExtras(src);
    }
}

这将是您所有意图的工厂。每次需要新的Intent时,请在IntentHelper中创建一个静态工厂方法。要创建新的Intent,您只需像这样说:

IntentHelper.createYourSpecialIntent(getIntent());
在你的活动中,当你想要在“会话”中“保存”一些数据时,请使用以下代码:
IntentHelper.createYourSpecialIntent(getIntent()).putExtra("YOUR_FIELD_NAME", fieldValueToSave);

然后发送此Intent。在目标Activity中,您的字段将可用作:

getIntent().getStringExtra("YOUR_FIELD_NAME");

现在我们可以像在servlet或JSP中一样使用Intent。


32

你也可以通过创建一个可传递的类来传递自定义类对象。最好的方法是编写您的类,然后将其粘贴到诸如http://www.parcelabler.com/之类的站点上,以使其变成可传递的。单击“生成”按钮,您将获得新代码。复制所有内容并替换原始类内容。

Intent intent = new Intent(getBaseContext(), NextActivity.class);
Foo foo = new Foo();
intent.putExtra("foo", foo);
startActivity(intent);

并在NextActivity中获取结果,如下所示 -

Foo foo = getIntent().getExtras().getParcelable("foo");
现在,您可以像以前一样使用foo对象。

25
另一种方法是使用公共静态字段来存储数据,例如:
public class MyActivity extends Activity {

  public static String SharedString;
  public static SomeObject SharedObject;

//...

5
我很想知道为什么你的建议没有得到投票,它更简单实用。 - Porizm
7
这是否违反了面向对象原则? - Christian Vielma
2
@ChristianVielma 嗯,这更像是一个灰色地带...你可以用很多方法来做,对我来说,它似乎是一个干净的“逃避”,所以...由你(开发者)决定是否适合你,我喜欢这种方式,因为它更容易跟踪,但它也可能变得非常混乱... - user497849
2
为什么你说这个会变得混乱?iOS不是通过设置“属性”来传递视图控制器之间的数据吗?这比使用意图容易多了。 - Terry Bu
2
是的,你可以在视图控制器之间传递数据,但不要使用静态属性。问题在于它不是所需活动实例上的属性。通过startActivity()启动Android活动的方式,它不会立即实例化对象并允许开发人员设置实例变量。这真的很烦人... - Shawn
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接