我有一个奇怪的问题。我环顾网络但没有找到答案。我还是android编程的初学者。让我们走吧:
我想做的就是用一些数据调用第二个Activity。它适用于小数据,但如果数据变大,第二个Activity将不会显示,第一个Activity将完成。 这是调用方法的代码:
Intent intent = new Intent(ActivitySearch.this,ActivityResults.class);
Bundle bundle = new Bundle();
bundle.putParcelableArrayList("data", searchList);
intent.putExtras(bundle);
startActivity(intent);
接收数据的部分并不重要。即使我不尝试读取该包,也不会调用该活动。我用以下几行测试了这个:
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d("DEBUG","ActivityResult::onCreate()");
super.onCreate(savedInstanceState);
OnCreate()
永远不会被召唤。
也许你的一个人有个主意...... 谢谢你的帮助!
编辑:至少我忘了:这只发生在ICS下。该应用程序就像一个姜饼和froyo的魅力。
Edit2:Logcat
10-10 14:49:46.951: D/OpenGLRenderer(21696): Flushing caches (mode 0)
10-10 14:49:47.011: V/ActivityThread(22429): com.example.amazonsearch white listed for hwui
10-10 14:49:50.821: W/IInputConnectionWrapper(21696): showStatusIcon on inactive InputConnection
答案 0 :(得分:42)
您可能正在获得TransactionTooLargeException
根据Google android guide的建议,您可以使用静态字段或单例在活动之间共享数据。
他们推荐“用于短时间共享复杂的非持久性用户定义对象”
从您的代码中看来,这正是您所需要的。
因此,您在ActivitySearch.class中的代码可能如下所示:
ActivityResults.data = searchList;
Intent intent = new Intent(ActivitySearch.this,ActivityResults.class);
startActivity(intent);
然后,您可以在ActivityResults活动启动后从任何位置访问ActivityResults.data。
对于需要在用户会话之间共享的数据,不建议使用静态字段,因为当app在后台运行时(如果框架需要释放资源),应用程序进程可以被android框架杀死并重新启动。在这种情况下,将重新初始化所有静态字段。
答案 1 :(得分:28)
我更喜欢传递大数据的方式是使用枚举。 这种方法的一些优点:
以下是一个例子:
package com.jyvee.arguments;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class SomeActivity extends Activity {
// Names for the arguments we pass to the
// activity when we create it
private final static String ARG_STRING = "ARG_STRING";
private final static String ARG_INT = "ARG_INT";
private String stringField;
private int intField;
private List<Object> arrayField;
private enum DataHolder {
INSTANCE;
private List<Object> mObjectList;
public static boolean hasData() {
return INSTANCE.mObjectList != null;
}
public static void setData(final List<Object> objectList) {
INSTANCE.mObjectList = objectList;
}
public static List<Object> getData() {
final List<Object> retList = INSTANCE.mObjectList;
INSTANCE.mObjectList = null;
return retList;
}
}
@Override
protected void onCreate(final Bundle savedState) {
super.onCreate(savedState);
// Get the activity intent if there is a one
final Intent intent = getIntent();
// And retrieve arguments if there are any
if (intent.hasExtra(ARG_STRING)) {
stringField = intent.getExtras().getString(ARG_STRING);
}
if (intent.hasExtra(ARG_INT)) {
intField = intent.getExtras().getInt(ARG_INT);
}
// And we retrieve large data from enum
if (DataHolder.hasData()) {
arrayField = DataHolder.getData();
}
// Now stringField, intField fields are available
// within the class and can be accessed directly
}
/**
* /** A static method for starting activity with supplied arguments
*
* @param contextA
* context that starts this activity
* @param stringArg
* A string argument to pass to the new activity
* @param intArg
* An int argument to pass to the new activity
* @param objectList
* An object list argument to pass to the new activity
*/
public static void startActivity(final Context context, final String stringArg,
final int intArg, final List<Object> objectList) {
// Initialize a new intent
final Intent intent = new Intent(context, SomeActivity.class);
// To speed things up :)
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
// And add arguments to the Intent
intent.putExtra(ARG_STRING, stringArg);
intent.putExtra(ARG_INT, intArg);
// Now we put the large data into our enum instead of using Intent extras
DataHolder.setData(objectList);
context.startActivity(intent);
}
}
更多信息here。
答案 2 :(得分:3)
如果您将一个大型信息从一个活动传递到另一个活动,那么可能会使App慢一些
但使用Global Class来存储使用您可以轻松获取或设置任何值的变量
在全局文件中声明
请看这个链接:
http://androidresearch.wordpress.com/2012/03/22/defining-global-variables-in-android/
答案 3 :(得分:2)
据我所知,直到API-8(Froyo),在通过意图传递parcelable对象时存在一些限制(如1MB)。但是,您可以简单地将您的parcelable数据写入文件,并通过bundle将文件路径发送到下一个活动。稍后,编写第二个活动代码以从文件中读取数据并在之后将其删除。
答案 4 :(得分:1)
我不知道为什么它不适用于大数据,但如果你找不到任何解决方法,我建议你使用自定义全局应用程序like here。 (还要检查正确答案以使其有效)
答案 5 :(得分:1)
我最近遇到了这个TransactionTooLargeException
问题,并且正在寻找一种避免这种情况的解决方案。最后,我找不到任何可行的方法。在大多数答案中,您会发现人们在推荐各种方法来避免出现此异常,但是没有合适的示例。
这是我为解决此问题所做的工作,在某些地方这可能不是理想的解决方案,并且也有一定的局限性。
步骤1- 编写一个类,该类将把包转换成字符串并将其存储在Shared Preference中。
public class ActivityBridge {
private static final String KEY_ACTIVITY_BRIDGE = "ACTIVITY_BRIDGE";
private final Context context;
private SharedPreferences sharedPreferences;
public ActivityBridge(Context context) {
this.context = context;
sharedPreferences = context.getSharedPreferences(KEY_ACTIVITY_BRIDGE, Context.MODE_PRIVATE);
}
@SuppressLint("ApplySharedPref")
public void putData(Bundle bundle, Intent intent) {
sharedPreferences.edit()
.putString(
intent.toString(),
Base64.encodeToString(bundleToBytes(bundle), 0)
)
.commit();
}
@SuppressLint("ApplySharedPref")
public Bundle getData(Intent intent) {
Bundle bundle;
final String bundleString = sharedPreferences.getString(intent.toString(), "");
if (TextUtils.isEmpty(bundleString)) {
return null;
} else {
bundle = bytesToBundle(Base64.decode(bundleString, 0));
}
sharedPreferences.edit()
.clear()
.commit();
return bundle;
}
public byte[] bundleToBytes(Bundle bundle) {
Parcel parcel = Parcel.obtain();
parcel.writeBundle(bundle);
byte[] bytes = parcel.marshall();
parcel.recycle();
return bytes;
}
public Bundle bytesToBundle(byte[] bytes) {
Parcel parcel = Parcel.obtain();
parcel.unmarshall(bytes, 0, bytes.length);
parcel.setDataPosition(0);
Bundle bundle = parcel.readBundle(context.getClassLoader());
parcel.recycle();
return bundle;
}
}
第2步- 使用情况
创建意图时
Intent intent = new Intent(ActivityA.this, ActivityB.class);
Bundle bundle = new Bundle();
bundle.putString("<KEY>", "<VALUE>");
new ActivityBridge(ActivityA.this).putData(bundle, intent);
startActivity(intent);
在提取捆绑包时
Bundle bundle = new ActivityBridge(this).getData(getIntent());
注意:此解决方案在读取后清除存储的Bundle,并且如果重新创建Activity,则不会返回Bundle。这是一种解决方法,任何建议或问题将不胜感激。
答案 6 :(得分:0)
问题:按照Google android指南的建议,将大量数据传递给第二个Activity,您可以使用静态字段或单例在活动之间共享数据。您可以通过3种方式在应用程序中的活动之间传递数据。意图;共享首选项;应用;意向传递数据有一些限制。对于大量数据,您可以使用应用程序级别的数据共享,并将其存储在SharedPreference中可以使您的应用程序大小增加
How to pass large data between activities in Android ?,此示例演示了如何在Android中的活动之间传递大数据步骤1-在Android Studio中创建新项目,请转到在Android中的活动之间发送数据是用于触发其他Android活动中的操作的对象。 Intent最常见的用途之一是在您的应用中打开一个新的Activity。通常,您会希望将信息传递给新的活动。
如何在活动和保障之间传递大量数据,请使用ORM android数据库lib +1。如Realm或DBFlow或其他ORM。图像从何而来?通过意图传递图像意味着将它们保存在片段之间的传递数据中。从Fragment 1.3.0-alpha04开始,每个FragmentManager都实现FragmentResultOwner。这意味着FragmentManager可以充当片段结果的中央存储。
答案 7 :(得分:0)
我选择将有效负载写入文件,然后在子活动中将其读回,因为:
下面的这个类 (DataReference
) 允许在文件中保存和加载 Serializable
"Payload
"。 DataReference
本身是 Serializable
,因此可以将其写入 Bundle
或 Intent
以传递给新的 Activity
...
只需确保在 saveInstanceState
期间也保存此文件,并在 onCreate
期间重新加载...
/**
* provides a means to pass around a large resource via a bundle. instead of storing the [Payload] in
* the bundle, only a [sessionId], and [directoryName] is stored in a bundle, that can be used to
* retrieve the actual [Payload] at a later time.
*/
class DataReference<Payload : Serializable>(
private val directoryName: String,
private val sessionId: String = randomAlphaNumericString()
) : Serializable {
private fun directory(context: Context) = context.applicationContext.getDir(directoryName, Context.MODE_PRIVATE)
private fun sessionIdFile(context: Context) = File(directory(context), "sessionId")
private fun payloadFile(context: Context) = File(directory(context), "payload")
/**
* if the [sessionId] is valid, reads the [Payload] from persistent memory, and returns it to
* the caller, or null, if no existing [Payload] exists; otherwise, if [sessionId] is invalid,
* the [Payload] is deleted from persistent memory (if any exists), and null is returned to the
* caller.
*/
fun load(context: Context, payloadKClass: KClass<Payload>): Payload? {
return if (sessionId == sessionIdFile(context).readObject(String::class)) {
payloadFile(context).readObject(payloadKClass)
} else {
sessionIdFile(context).deleteFileIfExists()
payloadFile(context).deleteFileIfExists()
null
}
}
/**
* overwrites any existing [Payload] with the new [payload], which is only accessible from
* [load] when the [sessionId] passed into [load] matches the [sessionId] passed into this call
* to [save].
*/
fun save(context: Context, payload: Payload) {
// delete files if they exist
sessionIdFile(context).deleteFileIfExists()
payloadFile(context).deleteFileIfExists()
// write the payload & session id to the file
ObjectOutputStream(sessionIdFile(context).outputStream()).use { oos ->
oos.writeObject(sessionId)
oos.flush()
}
ObjectOutputStream(payloadFile(context).outputStream()).use { oos ->
oos.writeObject(payload)
oos.flush()
}
}
private fun File.deleteFileIfExists(): Boolean {
isFile && delete()
return !exists()
}
private fun <T:Any> File.readObject(tKClass: KClass<T>): T? = if (isFile) {
ObjectInputStream(inputStream()).use { ois ->
tKClass.safeCast(ois.readObject())
}
} else {
null
}
}