Как правильно управлять данными с помощью SharedPreferences? - PullRequest
0 голосов
/ 08 мая 2020

Прямо сейчас я нахожусь в процессе «оптимизации» своего приложения. Я все еще новичок, поэтому в основном перемещаю методы из моего MainActivity.class в их отдельный класс. Я считаю, что он называется Encapsulation (поправьте меня, если я ошибаюсь) .

Моему приложению необходимо:

  1. Получить ссылку на плейлист YouTube от приложение YouTube (с намерением, android.intent.action.SEND).
  2. Используйте ссылку для получения данных с серверов Google с помощью YouTubeApi и Volley.
  3. Прочитать полученные данные и добавить их в arrayList<String>.

То, что должен делать мой класс YouTubeUsage.java, - это выборка данных с помощью YouTubeApi и Volley, а затем сохранение данные с помощью SharedPreferences. После сохранения данных данные считываются в моем ConvertActivity.class (это действие, специально созданное для android.intent.action.SEND) с помощью моего метода getVideoIds() перед установкой адаптера для моего listView в моем методе 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 из приложения YouTube в свое приложение с тремя элементами, он будет работать нормально. Listview покажет 3 элемента с соответствующими идентификаторами, как и должно. Но если я снова предоставлю общий доступ к плейлисту YouTube, мое приложение по-прежнему будет хранить данные предыдущего плейлиста, которым я поделился (даже если я его закрою), показывая номер элемента и идентификаторы предыдущей ссылки. Если я буду продолжать использовать один и тот же плейлист снова и снова, он в конечном итоге покажет правильное количество элементов и правильные идентификаторы. меня от использования SharedPreferences для передачи данных между двумя java классами. Однако JSON вызывает исключение. Это означает, что я должен инкапсулировать свой код с помощью try / catch. Я бы хотел избежать этого, так как мне нужно выполнять множество операций с данными, только что полученными Volley (проверьте размер класса, найдите определенные строки). Я обнаружил, что выполнение этого в этих методах try / catch не работает так, как я хочу. (т.е. вне try / catch значения остаются такими же, даже если я обновил их в try / catch).

Я хочу знать две вещи.

  1. Как я могу исправить эту проблему?
  2. Это самый эффективный способ сделать это (оптимизация)? (Я подумал, что, возможно, преобразовал VolleyResponse в строку с помощью Gson, а затем сохраню файл String, но я не знаю, лучший ли это способ сделать это, поскольку это должны быть предварительные данные. Это похоже на то же самое).

Спасибо!

1 Ответ

1 голос
/ 11 мая 2020

Возникла проблема с предположениями о порядке событий. 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.
}

в своей деятельности.

В конструкторе YoutubeUsage передайте контекст действия (YoutubeUsage), а затем сохраните его в экземпляре YoutubeUsage переменная с именем ctx.

В 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);
}

Удалите try/catch из onCreate.

И не нужно использовать 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.
}

}

...