如何使用 SharedPreferences 正确处理数据管理?
How to correctly handle data management with SharedPreferences?
现在,我正在 "optimizing" 我的应用程序中。我仍然是初学者,所以我所做的基本上是将方法从我的 MainActivity.class 转移到它们单独的 class。我相信它叫Encapsulation
(如有错误请指正).
我的申请需要:
- 从 YouTube 应用获取 YouTube 播放列表 Link(带有 Intent,
android.intent.action.SEND
)。
- 使用 link 通过 YouTubeApi 和 Volley 从 Google 服务器获取数据。
- 读取接收到的数据并将其添加到
arrayList<String>
。
我的 YouTubeUsage.java
class 应该做的是使用 YouTubeApi 和 Volley 获取数据,然后使用 SharedPreferences 存储数据。保存数据后,在为我的 listView 设置适配器之前,使用我的方法 getVideoIds()
在我的 ConvertActivity.class
中读取数据(它是专门为 android.intent.action.SEND
创建的 activity)在我的 createRecyclerView()
方法中。
YouTubeUsage.java
public class YoutubeUsage {
private Boolean results = false;
private String mResponse;
private ArrayList<String> videoIds = new ArrayList<>();
String Url;
public String getUrl(String signal) {
String playlistId = signal.substring(signal.indexOf("=") + 1);
this.Url = "https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails%2C%20snippet%2C%20id&playlistId=" +
playlistId + "&maxResults=25&key=" + "API_KEY";
return this.Url;
}
public void fetch(String Url, final Context context){
RequestQueue queue = Volley.newRequestQueue(context);
StringRequest request = new StringRequest(Request.Method.GET, Url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
sharedPreferences(response, context);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("VolleyError", Objects.requireNonNull(error.getMessage()));
}
});
queue.add(request);
}
private void sharedPreferences(String response, Context context){
SharedPreferences m = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = m.edit();
if (m.contains("serverResponse")){
if (!m.getString("serverResponse", "").equals(response)){
editor.remove("serverResponse");
editor.apply();
updateSharedPreferences(response, context);
}
} else{
updateSharedPreferences(response, context);
}
}
private void updateSharedPreferences(String mResponse, Context mContext){
SharedPreferences m = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = m.edit();
editor.putString("serverResponse", mResponse);
editor.apply();
}
}
ConvertActivity.java
public class ConvertActivity extends AppCompatActivity {
YoutubeUsage youtubeUsage = new YoutubeUsage();
ArrayList<String> videoIDs = new ArrayList<>();
String Url = "";
ListView listView;
MyCustomAdapter myCustomAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_convert);
listView = findViewById(R.id.listview_convert);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) {
Url = youtubeUsage.getUrl(Objects.requireNonNull(intent.getStringExtra("android.intent.extra.TEXT")));
}
//I would like to avoid the try/catch below
try {
videoIDs = getVideoIDs(Url, this);
createRecyclerView(videoIDs);
Log.i("ResponseVideoIDs", String.valueOf(videoIDs.size()));
} catch (JSONException e) {
e.printStackTrace();
}
}
private ArrayList<String> getVideoIDs(String Url, Context context) throws JSONException {
ArrayList<String> rawVideoIDs = new ArrayList<>();
youtubeUsage.fetch(Url, context);
SharedPreferences m = PreferenceManager.getDefaultSharedPreferences(context);
String serverResponse = m.getString("serverResponse", "");
JSONObject jsonObject = new JSONObject(serverResponse);
JSONArray jsonArray = jsonObject.getJSONArray("items");
for (int i = 0; i<jsonArray.length(); i++){
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
JSONObject jsonVideoId = jsonObject1.getJSONObject("contentDetails");
rawVideoIDs.add(jsonVideoId.getString("videoId"));
}
return rawVideoIDs;
}
private void createRecyclerView(ArrayList<String> videoIDs){
myCustomAdapter = new MyCustomAdapter(this, videoIDs);
listView.setAdapter(myCustomAdapter);
myCustomAdapter.notifyDataSetChanged();
}
}
一切正常,但是,我的 sharedPreferences 永远不会更新。这意味着,如果我将 YouTube 应用程序中包含 3 个项目的 YouTube 播放列表共享到我的应用程序,它会正常工作。 Listview 将显示 3 个项目及其相应的 ID。但是,如果我再次分享 YouTube 播放列表,我的应用程序仍会保留我之前分享的播放列表的数据(即使我关闭它),显示项目编号和之前的 ID link。如果我继续一遍又一遍地共享同一个播放列表,它最终会显示正确的项目数和正确的 ID。
我完全可以将 YouTubeUsage.java
中的所有方法都放在我的 ConvertActivity.class
中,以防止我使用 SharedPreferences 在两个 java class 之间传输数据。但是,JSON 抛出异常。这意味着我必须用 try/catch 封装我的代码。我想避免这些,因为我需要对 Volley 刚刚收到的数据进行大量操作(检查 class 大小,查找某些字符串)。我发现在 try/catch 中这样做并不像我想要的那样工作。 (即在 try/catch 之外,即使我在 try/catch 中更新它们,这些值仍然保持不变)。
我想知道两件事。
- 我该如何解决这个问题?
- 这是最有效的方法吗(优化)? (我想也许
使用 Gson 将 VolleyResponse 转换为字符串,然后存储字符串文件,但我不知道这是否是最好的方法,因为它应该是
临时数据。感觉更像了)。
谢谢!
关于事件顺序的假设存在问题。 Volley 会异步处理请求,所以这里建议实现观察者模式。
创建一个新的 Java 文件只包含:
interface MyNetworkResponse {
void goodResponse(String responseString);
}
然后确保 ConvertActivity
implements MyNetworkResponse
和创建方法:
void goodResponse(String responseString) {
// handle a positive response here, i.e. extract the JSON and send to your RecyclerView.
}
在你的 Activity.
在您的 YoutubeUsage
构造函数中,传入 Activity 上下文 (YoutubeUsage),然后将其存储在名为 ctx
的 YoutubeUsage
实例变量中。
在onCreate
中创建一个YoutubeUsage
的实例并传入this
.
在 onResponse
中调用 ctx.goodResponse(response)
.
将以下块修改为:
if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) {
Url = youtubeUsage.getUrl(Objects.requireNonNull(intent.getStringExtra("android.intent.extra.TEXT")));
youtubeUsage.fetch(Url);
}
从 onCreate
中删除 try/catch
。
而且根本不需要使用 SharedPreferences
。
更新
试试这个代码:
MyNetworkResponse.java
interface MyNetworkResponse {
void goodResponse(String responseString);
void badResponse(VolleyError error);
}
YoutubeUsage.java
class YoutubeUsage {
private RequestQueue queue;
private MyNetworkResponse callback;
YoutubeUsage(Object caller) {
this.callback = (MyNetworkResponse) caller;
queue = Volley.newRequestQueue((Context) caller);
}
static String getUrl(String signal) {
String playlistId = signal.substring(signal.indexOf("=") + 1);
return "https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails%2C%20snippet%2C%20id&playlistId=" + playlistId + "&maxResults=25&key=" + "API_KEY";
}
void fetch(String url){
StringRequest request = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
callback.goodResponse(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.badResponse(error);
}
});
queue.add(request);
}
}
ConvertActivity.java
public class ConvertActivity extends AppCompatActivity implements MyNetworkResponse {
YoutubeUsage youtubeUsage;
ArrayList<String> videoIDs = new ArrayList<>();
ListView listView;
MyCustomAdapter myCustomAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_convert);
listView = findViewById(R.id.listview_convert);
youtubeUsage = new YoutubeUsage(this);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) {
String url = YoutubeUsage.getUrl(Objects.requireNonNull(intent.getStringExtra("android.intent.extra.TEXT")));
youtubeUsage.fetch(url);
}
}
private ArrayList<String> getVideoIDs(String serverResponse) throws JSONException {
ArrayList<String> rawVideoIDs = new ArrayList<>();
JSONObject jsonObject = new JSONObject(serverResponse);
JSONArray jsonArray = jsonObject.getJSONArray("items");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
JSONObject jsonVideoId = jsonObject1.getJSONObject("contentDetails");
rawVideoIDs.add(jsonVideoId.getString("videoId"));
}
return rawVideoIDs;
}
private void createRecyclerView(ArrayList<String> videoIDs) {
myCustomAdapter = new MyCustomAdapter(this, videoIDs);
listView.setAdapter(myCustomAdapter);
myCustomAdapter.notifyDataSetChanged();
}
@Override
public void goodResponse(String responseString) {
Log.d("Convert:goodResp", "[" + responseString + "]");
try {
ArrayList<String> rawVideoIDs = getVideoIDs(responseString);
createRecyclerView(rawVideoIDs);
} catch (JSONException e) {
// handle JSONException, e.g. malformed response from server.
}
}
@Override
public void badResponse(VolleyError error) {
// handle unwanted server response.
}
}
现在,我正在 "optimizing" 我的应用程序中。我仍然是初学者,所以我所做的基本上是将方法从我的 MainActivity.class 转移到它们单独的 class。我相信它叫Encapsulation
(如有错误请指正).
我的申请需要:
- 从 YouTube 应用获取 YouTube 播放列表 Link(带有 Intent,
android.intent.action.SEND
)。 - 使用 link 通过 YouTubeApi 和 Volley 从 Google 服务器获取数据。
- 读取接收到的数据并将其添加到
arrayList<String>
。
我的 YouTubeUsage.java
class 应该做的是使用 YouTubeApi 和 Volley 获取数据,然后使用 SharedPreferences 存储数据。保存数据后,在为我的 listView 设置适配器之前,使用我的方法 getVideoIds()
在我的 ConvertActivity.class
中读取数据(它是专门为 android.intent.action.SEND
创建的 activity)在我的 createRecyclerView()
方法中。
YouTubeUsage.java
public class YoutubeUsage {
private Boolean results = false;
private String mResponse;
private ArrayList<String> videoIds = new ArrayList<>();
String Url;
public String getUrl(String signal) {
String playlistId = signal.substring(signal.indexOf("=") + 1);
this.Url = "https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails%2C%20snippet%2C%20id&playlistId=" +
playlistId + "&maxResults=25&key=" + "API_KEY";
return this.Url;
}
public void fetch(String Url, final Context context){
RequestQueue queue = Volley.newRequestQueue(context);
StringRequest request = new StringRequest(Request.Method.GET, Url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
sharedPreferences(response, context);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("VolleyError", Objects.requireNonNull(error.getMessage()));
}
});
queue.add(request);
}
private void sharedPreferences(String response, Context context){
SharedPreferences m = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = m.edit();
if (m.contains("serverResponse")){
if (!m.getString("serverResponse", "").equals(response)){
editor.remove("serverResponse");
editor.apply();
updateSharedPreferences(response, context);
}
} else{
updateSharedPreferences(response, context);
}
}
private void updateSharedPreferences(String mResponse, Context mContext){
SharedPreferences m = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = m.edit();
editor.putString("serverResponse", mResponse);
editor.apply();
}
}
ConvertActivity.java
public class ConvertActivity extends AppCompatActivity {
YoutubeUsage youtubeUsage = new YoutubeUsage();
ArrayList<String> videoIDs = new ArrayList<>();
String Url = "";
ListView listView;
MyCustomAdapter myCustomAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_convert);
listView = findViewById(R.id.listview_convert);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) {
Url = youtubeUsage.getUrl(Objects.requireNonNull(intent.getStringExtra("android.intent.extra.TEXT")));
}
//I would like to avoid the try/catch below
try {
videoIDs = getVideoIDs(Url, this);
createRecyclerView(videoIDs);
Log.i("ResponseVideoIDs", String.valueOf(videoIDs.size()));
} catch (JSONException e) {
e.printStackTrace();
}
}
private ArrayList<String> getVideoIDs(String Url, Context context) throws JSONException {
ArrayList<String> rawVideoIDs = new ArrayList<>();
youtubeUsage.fetch(Url, context);
SharedPreferences m = PreferenceManager.getDefaultSharedPreferences(context);
String serverResponse = m.getString("serverResponse", "");
JSONObject jsonObject = new JSONObject(serverResponse);
JSONArray jsonArray = jsonObject.getJSONArray("items");
for (int i = 0; i<jsonArray.length(); i++){
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
JSONObject jsonVideoId = jsonObject1.getJSONObject("contentDetails");
rawVideoIDs.add(jsonVideoId.getString("videoId"));
}
return rawVideoIDs;
}
private void createRecyclerView(ArrayList<String> videoIDs){
myCustomAdapter = new MyCustomAdapter(this, videoIDs);
listView.setAdapter(myCustomAdapter);
myCustomAdapter.notifyDataSetChanged();
}
}
一切正常,但是,我的 sharedPreferences 永远不会更新。这意味着,如果我将 YouTube 应用程序中包含 3 个项目的 YouTube 播放列表共享到我的应用程序,它会正常工作。 Listview 将显示 3 个项目及其相应的 ID。但是,如果我再次分享 YouTube 播放列表,我的应用程序仍会保留我之前分享的播放列表的数据(即使我关闭它),显示项目编号和之前的 ID link。如果我继续一遍又一遍地共享同一个播放列表,它最终会显示正确的项目数和正确的 ID。
我完全可以将 YouTubeUsage.java
中的所有方法都放在我的 ConvertActivity.class
中,以防止我使用 SharedPreferences 在两个 java class 之间传输数据。但是,JSON 抛出异常。这意味着我必须用 try/catch 封装我的代码。我想避免这些,因为我需要对 Volley 刚刚收到的数据进行大量操作(检查 class 大小,查找某些字符串)。我发现在 try/catch 中这样做并不像我想要的那样工作。 (即在 try/catch 之外,即使我在 try/catch 中更新它们,这些值仍然保持不变)。
我想知道两件事。
- 我该如何解决这个问题?
- 这是最有效的方法吗(优化)? (我想也许 使用 Gson 将 VolleyResponse 转换为字符串,然后存储字符串文件,但我不知道这是否是最好的方法,因为它应该是 临时数据。感觉更像了)。
谢谢!
关于事件顺序的假设存在问题。 Volley 会异步处理请求,所以这里建议实现观察者模式。
创建一个新的 Java 文件只包含:
interface MyNetworkResponse {
void goodResponse(String responseString);
}
然后确保 ConvertActivity
implements MyNetworkResponse
和创建方法:
void goodResponse(String responseString) {
// handle a positive response here, i.e. extract the JSON and send to your RecyclerView.
}
在你的 Activity.
在您的 YoutubeUsage
构造函数中,传入 Activity 上下文 (YoutubeUsage),然后将其存储在名为 ctx
的 YoutubeUsage
实例变量中。
在onCreate
中创建一个YoutubeUsage
的实例并传入this
.
在 onResponse
中调用 ctx.goodResponse(response)
.
将以下块修改为:
if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) {
Url = youtubeUsage.getUrl(Objects.requireNonNull(intent.getStringExtra("android.intent.extra.TEXT")));
youtubeUsage.fetch(Url);
}
从 onCreate
中删除 try/catch
。
而且根本不需要使用 SharedPreferences
。
更新
试试这个代码:
MyNetworkResponse.java
interface MyNetworkResponse {
void goodResponse(String responseString);
void badResponse(VolleyError error);
}
YoutubeUsage.java
class YoutubeUsage {
private RequestQueue queue;
private MyNetworkResponse callback;
YoutubeUsage(Object caller) {
this.callback = (MyNetworkResponse) caller;
queue = Volley.newRequestQueue((Context) caller);
}
static String getUrl(String signal) {
String playlistId = signal.substring(signal.indexOf("=") + 1);
return "https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails%2C%20snippet%2C%20id&playlistId=" + playlistId + "&maxResults=25&key=" + "API_KEY";
}
void fetch(String url){
StringRequest request = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
callback.goodResponse(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
callback.badResponse(error);
}
});
queue.add(request);
}
}
ConvertActivity.java
public class ConvertActivity extends AppCompatActivity implements MyNetworkResponse {
YoutubeUsage youtubeUsage;
ArrayList<String> videoIDs = new ArrayList<>();
ListView listView;
MyCustomAdapter myCustomAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_convert);
listView = findViewById(R.id.listview_convert);
youtubeUsage = new YoutubeUsage(this);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) {
String url = YoutubeUsage.getUrl(Objects.requireNonNull(intent.getStringExtra("android.intent.extra.TEXT")));
youtubeUsage.fetch(url);
}
}
private ArrayList<String> getVideoIDs(String serverResponse) throws JSONException {
ArrayList<String> rawVideoIDs = new ArrayList<>();
JSONObject jsonObject = new JSONObject(serverResponse);
JSONArray jsonArray = jsonObject.getJSONArray("items");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
JSONObject jsonVideoId = jsonObject1.getJSONObject("contentDetails");
rawVideoIDs.add(jsonVideoId.getString("videoId"));
}
return rawVideoIDs;
}
private void createRecyclerView(ArrayList<String> videoIDs) {
myCustomAdapter = new MyCustomAdapter(this, videoIDs);
listView.setAdapter(myCustomAdapter);
myCustomAdapter.notifyDataSetChanged();
}
@Override
public void goodResponse(String responseString) {
Log.d("Convert:goodResp", "[" + responseString + "]");
try {
ArrayList<String> rawVideoIDs = getVideoIDs(responseString);
createRecyclerView(rawVideoIDs);
} catch (JSONException e) {
// handle JSONException, e.g. malformed response from server.
}
}
@Override
public void badResponse(VolleyError error) {
// handle unwanted server response.
}
}