JAVA / Как сделать асинхронный обратный вызов c, используя comletable-future? - PullRequest
0 голосов
/ 01 февраля 2020

Я получаю данные из выделенного файла HttpHandler. Это работает, я называю мой класс HttpHandler фрагментом с именем HomeFragment.

Я хотел бы использовать эти данные в своем HomeFragment. Мне посоветовали взглянуть на comptable-futur и asyn c вычисления.

Что я сделал, я нашел статью об этом. Но как реализовать то, что у меня есть, совершенно размыто.

Любая помощь будет оценена.

HomeFragment. java

public class HomeFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        HttpHandler req = new HttpHandler();

        // The blurry part => 
        CompletableFuture.supplyAsync(req.fetchData())
                .thenAccept(Log.d("ok","ok"));

        return inflater.inflate(R.layout.fragment_home, container, false);
    }
}

HttpHandler. java

    public class HttpHandler {

    private OkHttpClient httpClient;
    private static final String TAG = "TagActivity";

    public HttpHandler() {
        fetchData();
    }

    private void fetchData() {
        httpClient = new OkHttpClient.Builder().build();
        Request request = new Request.Builder()
                .url("https://api.imgur.com/3/gallery/user/rising/0.json")
                .header("Authorization","Client-ID bb0c749c6403fd2")
                .header("User-Agent","epicture")
                .build();

        httpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e(TAG, "An error has occurred " + e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    JSONObject data = new JSONObject(response.body().string());
                    JSONArray items = data.getJSONArray("data");
                    final List<Photo> photos = new ArrayList<Photo>();
                    for(int i=0; i<items.length();i++) {
                        JSONObject item = items.getJSONObject(i);
                        Photo photo = new Photo();
                        if(item.getBoolean("is_album")) {
                            photo.id = item.getString("cover");
                        } else {
                            photo.id = item.getString("id");
                        }
                        photo.title = item.getString("title");
                        photos.add(photo);
                        Log.d(TAG, photo.title);

                    }
                }
                catch (Exception e) {
                    Log.e("JSONerr" , "Something went wrong.");
                }
            }
        });
    }

    private static class Photo {
        String id;
        String title;
    }
}

Ответы [ 2 ]

0 голосов
/ 01 февраля 2020

Я думаю { ссылка } - хорошее решение для вашего ответа. Если у вас возникла ошибка с этими кодами, вы можете увидеть полный код этого ответа здесь .

0 голосов
/ 01 февраля 2020

Основная проблема с вашим кодом состоит в том, что fetchData возвращает void, и поэтому у вас нет доступа к извлеченным данным, ни синхронным, ни асинхронным.

Таким образом, самый логичный выход - сделать fetchData возвращать данные и желательно в асинхронной форме, так как она наиболее гибкая. Точный тип возвращаемого результата может отличаться, но я выбираю CompletableFuture в качестве стандарта:

public class HttpHandler {

public HttpHandler() {
    // do not call fetchData() here
}

public CompletableFuture<String> fetchData() {
    OkHttpClient httpClient = new OkHttpClient.Builder().build();
    Request request = new Request.Builder()
            .url("https://api.imgur.com/3/gallery/user/rising/0.json")
            .header("Authorization","Client-ID bb0c749c6403fd2")
            .header("User-Agent","epicture")
            .build();
    CompletableFuture<String> result = new CompletableFuture<String>();
    httpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            result.completeExceptionally(e);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            result.complete(response.body().string());
        }
    });
    return result;
}
}

Всю обработку данных лучше выполнять в HomeFragment. Во-первых, мы сохраняем универсальность HttpHandler. Во-вторых, мы не владеем вычислительными ресурсами, которые вызывают обратный вызов, поэтому лучше использовать их минимально.

public class HomeFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        HttpHandler req = new HttpHandler();
        CompletableFuture<String> data = req.fetchData();
        try {
            JSONObject data = new JSONObject(data.get());  // get() can throw IOException, handled below
            JSONArray items = data.getJSONArray("data");
            final List<Photo> photos = new ArrayList<Photo>();
            for(int i=0; i<items.length();i++) {
                JSONObject item = items.getJSONObject(i);
                Photo photo = new Photo();
                if(item.getBoolean("is_album")) {
                    photo.id = item.getString("cover");
                } else {
                    photo.id = item.getString("id");
                }
                photo.title = item.getString("title");
                photos.add(photo);
                Log.d(TAG, photo.title);
           }
        } catch (IOException e) {
            Log.e("IO Error" , e.toString());
        } catch (JSONException e) {
            Log.e("JSONerr" , e.toString);
        }
        return inflater.inflate(R.layout.fragment_home, container, false);
    }
}
...