在活动之间导航时如何在不加载数据的情况下保留数据
How to preserve the data without it being loaded when navigated between Activities
如何防止来自另一个意图的数据被再次加载。例如,我有一个 MainActivity
,我在其中对 onCreate()
方法中的 API 进行 GET 调用。我单击其中一张卡片,它会触发另一张名为 CardActivity
的 activity。
当我从这个 CardActivity
回击时,正在再次加载数据。我也尝试了 onPause()
方法,但运气不好。如何防止在活动之间导航时加载的数据。
谁能指导我如何实现这一点?
我正在使用 Volley 库进行 HTTP 调用。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestQueue = MySingleton.getInstance(this.getApplicationContext()).getRequestQueue();
getRedditDefaultData();
getGoogleHeadlinesData();
}
private void getRedditDefaultData() {
final String url = "https://example.com"
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
...
dataset.add(new StaggeredCustomCard(
redditUserProfilePic,
redditUserName,
redditPostDateTime,
redditPostTitle,
null,
redditPostDescription));
}
if (dataset != null) {
staggeredGridAdapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// TODO: Handle error
progressBar.setVisibility(View.GONE);
}
});
retryPolicy(jsonObjectRequest);
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
}
这个问题有很多可能的答案。您可以将数据本地存储在 SQLite 数据库中,然后可以在需要时从那里读取数据。如果您的数据可能会经常更改,那么这不是一个好主意。您可以考虑使用 Volley
附带的缓存系统。要了解 Volley 的缓存是如何实现的,您可以参考 。
另一种方法是将数据作为对象在活动之间传递。如果在 activity 转换期间数据不太可能更改,我认为这是个好主意。这样,您就不会每次都从网络加载数据。因此,一旦在 MainActivity
中读取数据,就可以将其作为对象或意图传递给 CardActivity
。
你可以考虑将你的MainActivity设置为SingleTop启动模式,然后让CardActivity在按下后退按钮时通过intent启动MainActivity。
这将导致调用 onNewIntent() 而不是 onCreate()。
onNewIntent
Added in API level 1
protected void onNewIntent (Intent intent)
This is called for activities that set launchMode to "singleTop" in
their package, or if a client used the Intent#FLAG_ACTIVITY_SINGLE_TOP
flag when calling startActivity(Intent). In either case, when the
activity is re-launched while at the top of the activity stack instead
of a new instance of the activity being started, onNewIntent() will be
called on the existing instance with the Intent that was used to
re-launch it.
An activity can never receive a new intent in the resumed state. You
can count on onResume() being called after this method, though not
necessarily immediately after the completion this callback. If the
activity was resumed, it will be paused and new intent will be
delivered, followed by onResume(). If the activity wasn't in the
resumed state, then new intent can be delivered immediately, with
onResume() called sometime later when activity becomes active again.
Note that getIntent() still returns the original Intent. You can use
setIntent(Intent) to update it to this new Intent.
这是我根据@Reaz Murshed 的建议尝试的。 Medium 上的这个 article 帮助我实现了缓存方法。
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
...
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
...
}
}) {
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);
if (cacheEntry == null) {
cacheEntry = new Cache.Entry();
}
final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background
final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely
long now = System.currentTimeMillis();
final long softExpire = now + cacheHitButRefreshed;
final long ttl = now + cacheExpired;
cacheEntry.data = response.data;
cacheEntry.softTtl = softExpire;
cacheEntry.ttl = ttl;
String headerValue;
headerValue = response.headers.get("Date");
if (headerValue != null) {
cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
headerValue = response.headers.get("Last-Modified");
if (headerValue != null) {
cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
cacheEntry.responseHeaders = response.headers;
final String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString), cacheEntry);
} catch (UnsupportedEncodingException | JSONException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(JSONObject response) {
super.deliverResponse(response);
}
@Override
public void deliverError(VolleyError error) {
super.deliverError(error);
}
@Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
return super.parseNetworkError(volleyError);
}
};
希望这对某人有所帮助
如何防止来自另一个意图的数据被再次加载。例如,我有一个 MainActivity
,我在其中对 onCreate()
方法中的 API 进行 GET 调用。我单击其中一张卡片,它会触发另一张名为 CardActivity
的 activity。
当我从这个 CardActivity
回击时,正在再次加载数据。我也尝试了 onPause()
方法,但运气不好。如何防止在活动之间导航时加载的数据。
谁能指导我如何实现这一点?
我正在使用 Volley 库进行 HTTP 调用。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestQueue = MySingleton.getInstance(this.getApplicationContext()).getRequestQueue();
getRedditDefaultData();
getGoogleHeadlinesData();
}
private void getRedditDefaultData() {
final String url = "https://example.com"
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
...
dataset.add(new StaggeredCustomCard(
redditUserProfilePic,
redditUserName,
redditPostDateTime,
redditPostTitle,
null,
redditPostDescription));
}
if (dataset != null) {
staggeredGridAdapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// TODO: Handle error
progressBar.setVisibility(View.GONE);
}
});
retryPolicy(jsonObjectRequest);
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
}
这个问题有很多可能的答案。您可以将数据本地存储在 SQLite 数据库中,然后可以在需要时从那里读取数据。如果您的数据可能会经常更改,那么这不是一个好主意。您可以考虑使用 Volley
附带的缓存系统。要了解 Volley 的缓存是如何实现的,您可以参考
另一种方法是将数据作为对象在活动之间传递。如果在 activity 转换期间数据不太可能更改,我认为这是个好主意。这样,您就不会每次都从网络加载数据。因此,一旦在 MainActivity
中读取数据,就可以将其作为对象或意图传递给 CardActivity
。
你可以考虑将你的MainActivity设置为SingleTop启动模式,然后让CardActivity在按下后退按钮时通过intent启动MainActivity。
这将导致调用 onNewIntent() 而不是 onCreate()。
onNewIntent
Added in API level 1
protected void onNewIntent (Intent intent)
This is called for activities that set launchMode to "singleTop" in their package, or if a client used the Intent#FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent). In either case, when the activity is re-launched while at the top of the activity stack instead of a new instance of the activity being started, onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it.
An activity can never receive a new intent in the resumed state. You can count on onResume() being called after this method, though not necessarily immediately after the completion this callback. If the activity was resumed, it will be paused and new intent will be delivered, followed by onResume(). If the activity wasn't in the resumed state, then new intent can be delivered immediately, with onResume() called sometime later when activity becomes active again.
Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.
这是我根据@Reaz Murshed 的建议尝试的。 Medium 上的这个 article 帮助我实现了缓存方法。
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
...
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
...
}
}) {
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);
if (cacheEntry == null) {
cacheEntry = new Cache.Entry();
}
final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background
final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely
long now = System.currentTimeMillis();
final long softExpire = now + cacheHitButRefreshed;
final long ttl = now + cacheExpired;
cacheEntry.data = response.data;
cacheEntry.softTtl = softExpire;
cacheEntry.ttl = ttl;
String headerValue;
headerValue = response.headers.get("Date");
if (headerValue != null) {
cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
headerValue = response.headers.get("Last-Modified");
if (headerValue != null) {
cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
cacheEntry.responseHeaders = response.headers;
final String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString), cacheEntry);
} catch (UnsupportedEncodingException | JSONException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(JSONObject response) {
super.deliverResponse(response);
}
@Override
public void deliverError(VolleyError error) {
super.deliverError(error);
}
@Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
return super.parseNetworkError(volleyError);
}
};
希望这对某人有所帮助