質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

Android:1回の処理内で連続でAPI接続を行う

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 573

score 5

お世話になります。

色々と試行錯誤してみましたが、Log.d("urlB",urlB)の時点で想定のURLが取得できていません。
お手数ですが、ご教示のほどよろしくお願い致します。

※追記
実現方法としては、AsyncTaskを継承したクラスファイルをAPIの処理毎に用意(3つ)して、
外部API(1)処理のcreateListener1()のonSuccess()内で、
外部API(2)処理のcreateListener2()を呼び出し、
createListener2()のonSuccess()内でcreateListener3()を呼び出す形となりますでしょうか。
開発素人のため、そもそも誤っていたら指摘ください。

実現したいこと

  1. ボタンをクリック
  2. EditTextに入力された内容をもとにURLを作成
  3. 外部API(1)に接続してXMLを取得
  4. 取得したXMLを解析し、それをもとにURLを作成
  5. 外部API(2)に接続してXMLを取得
  6. 取得したXMLを解析し、それをもとにURLを作成
  7. 外部API(3)に接続してXMLを取得
  8. 取得したXMLを解析

ソースコード

public void onClick(View view) {
        final EditText aaa = findViewById(R.id.aaa);
        final EditText bbb = findViewById(R.id.bbb);

        String testA = aaa.getText().toString();
        String testB = bbb.getText().toString();

        String urlA = TO_API1 + "request_data1=“" + aaa + "&request_data2=" + bbb;

        Log.d("urlA",urlA);

        getAsyncTask = new GetAsyncTask(this);
        getAsyncTask.setListener(createListener1());
        getAsyncTask.execute(urlA);

        String urlB = TO_API2 + "api_id=" + API_ID + str1 + str2 + "&lang=" + LANG;

        Log.d("urlB",urlB);

        getAsyncTask = new GetAsyncTask(this);
        getAsyncTask.setListener(createListener2());
        getAsyncTask.execute(urlB);

        String urlC = TO_API3 + "request_data1=“" + str1 + "&request_data2=" + str2;

        Log.d("urlC",urlC);

        getAsyncTask = new GetAsyncTask(this);
        getAsyncTask.setListener(createListener3());
        getAsyncTask.execute(urlC);
    }
    private GetAsyncTask.Listener createListener1() {
        return new GetAsyncTask.Listener() {
            @Override
            public void onSuccess(InputStream xml) {
                try {
                    getXMLContents(xml);
                    testA = responseData1;
                    testB = responseData2;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }
    private GetAsyncTask.Listener createListener2() {
        return new GetAsyncTask.Listener() {
            @Override
            public void onSuccess(InputStream xml) {
                try {
                    getXMLContents(xml);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }
    private GetAsyncTask.Listener createListener3() {
        return new GetAsyncTask.Listener() {
            @Override
            public void onSuccess(InputStream xml) {
                try {
                    getXMLContents(xml);
                    str1 = responseData1;
                    str2 = responseData2;
                    saveSharedPreferences();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }

    public void getXMLContents(InputStream is) throws  Exception{
        try{
            Document document= DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);

            Element rootElement=document.getDocumentElement();
            NodeList nodeListData1 = rootElement.getElementsByTagName("data1");
            NodeList nodeListData2 = rootElement.getElementsByTagName("data2");

            for (int i = 0; i < nodeListData1.getLength(); i++) {
                Element elem = (Element) nodeListData1.item(i);
                responseData1 = elem.getAttribute("response_data1");
            }
            for (int i = 0; i < nodeListData2.getLength(); i++) {
                Element elem = (Element) nodeListData2.item(i);
                responseData2 = elem.getAttribute("response_data2");
            }

        }catch(Exception e){
            throw e;
        }
    }
public class GetAsyncTask extends AsyncTask<Object, Void, Object> {
    private Context context;
    private final WeakReference<Activity> w_Activity;
    private Listener listener;

    GetAsyncTask(Activity activity) {
        this.w_Activity = new WeakReference<>(activity);
    }

    @Override
    protected Object doInBackground(Object[] data) {

        String url = (String)data[0];

        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder().url(url).get().build();

        Call call = client.newCall(request);
        String result = "";

        try {
            Response response = call.execute();
            ResponseBody body = response.body();
            if (body != null) {
                result = body.string();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
private GetAsyncTask.Listener createListener1() {
        return new GetAsyncTask.Listener() {
            @Override
            public void onSuccess(InputStream xml) {
                try {
                    getXMLContents(xml);
                    testA = responseData1;
                    testB = responseData2;

            String urlB = TO_API2 + "api_id=" + API_ID + str1 + str2 + "&lang=" + LANG;
            getAsyncTask = new GetAsyncTask(MainActivity.this);
               getAsyncTask.setListener(createListener2());
               getAsyncTask.execute(urlB);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hoshi-takanori

    2020/02/13 18:00

    onClick で実行した非同期処理の結果が返ってくるのは onClick メソッドを抜けた後になります。このため、onClick で 3 つの非同期処理を開始するとそれらは並行して走ることになります。API1 の結果を API2 で利用するには、API1 の結果が返ってきてから(つまり、createListener1 の onSuccess の中で)API2 を開始する必要があります。

    キャンセル

  • noname1234

    2020/02/13 18:34

    ご回答頂きありがとうございます。ソースコード修正版を記載しました。
    記載の内容で問題ないでしょうか。

    キャンセル

  • hoshi-takanori

    2020/02/14 01:05

    onClick では getAsyncTask.execute(urlA); とその準備だけを行い、createListener1 の onSuccess で getAsyncTask.execute(urlB);、createListener2 の onSuccess で getAsyncTask.execute(urlC); とする必要があると思います。

    キャンセル

  • jimbe

    2020/02/14 02:22

    ご提示のコードはちゃんと動作しているモノから得られた部分なのでしょうか.

    >String testA = aaa.getText().toString();
    >String testB = bbb.getText().toString();
    >String urlA = TO_API1 + "request_data1=“" + aaa + "&request_data2=" + bbb;

    の個所だけでもおかしな状態なのですが.

    キャンセル

回答 1

0

動かして確認してはいませんが, 例えば Future.get() が (Callable が値を返すまで) 待機することを利用して以下のようにすると, 順番にやっているように書けて良いのではと思います.

  @Override
  public void onClick(View v) {
    EditText aaa = findViewById(R.id.aaa);
    String testA = aaa.getText().toString();

    EditText bbb = findViewById(R.id.bbb);
    String testB = bbb.getText().toString();

    Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        ExecutorService es = Executors.newSingleThreadExecutor();
        try {
          //入力値を使ってアクセスを行う
          String urlA = TO_API1 + "request_data1=" + testA + "&request_data2=" + testB;
          Future<ResponseA> futureA = es.submit(new XMLAcquirer(urlA, root -> new ResponseA(root)));
          ResponseA resA = futureA.get();

          //resA のデータを使って次のアクセスを行う
          String urlB = TO_API2 + "api_id=" + API_ID + resA.api_id1 + resA.api_id2 + "&lang=" + LANG;
          Future<ResponseB> futureB = es.submit(new XMLAcquirer(urlB, root -> new ResponseB(root)));
          ResponseB resB = futureB.get();

          //さらに resB のデータを使って次のアクセスを行う
          String urlC = TO_API3 + "request_data1=" + resB.data1 + "&request_data2=" + resB.data2;
          Future<ResponseC> futureC = es.submit(new XMLAcquirer(urlC, root -> new ResponseC(root)));
          ResponseC resC = futureC.get();

          // resC のデータを保存する?
          saveSharedPreferences(resC);

        } catch(InterruptedException e) {
          e.printStackTrace();
        } catch(ExecutionException e) {
          e.printStackTrace();
        }
      }
    });
    thread.start();
  }
  //urlA の XML を解析して必要なデータを内部に保持する
  static class ResponseA {
    ResponseA(Element rootElement) {
      NodeList nodeListData1 = rootElement.getElementsByTagName("data1");
      for (int i = 0; i < nodeListData1.getLength(); i++) {
        Element elem = (Element) nodeListData1.item(i);
        api_id1 = elem.getAttribute("response_data1");
      }
      NodeList nodeListData2 = rootElement.getElementsByTagName("data2");
      for (int i = 0; i < nodeListData2.getLength(); i++) {
        Element elem = (Element) nodeListData2.item(i);
        api_id2 = elem.getAttribute("response_data2");
      }
    }
    String api_id1;
    String api_id2;
  }
  //urlB の XML を解析して必要なデータを内部に保持する
  static class ResponseB {
    ResponseB(Element rootElement) {
      NodeList nodeListData1 = rootElement.getElementsByTagName("data1");
      for (int i = 0; i < nodeListData1.getLength(); i++) {
        Element elem = (Element) nodeListData1.item(i);
        data1 = elem.getAttribute("response_data1");
      }
      NodeList nodeListData2 = rootElement.getElementsByTagName("data2");
      for (int i = 0; i < nodeListData2.getLength(); i++) {
        Element elem = (Element) nodeListData2.item(i);
        data2 = elem.getAttribute("response_data2");
      }
    }
    String data1;
    String data2;
  }
  //urlC の XML を解析して必要なデータを内部に保持する
  static class ResponseC {
    ResponseC(Element rootElement) {
      NodeList nodeListData1 = rootElement.getElementsByTagName("data1");
      for (int i = 0; i < nodeListData1.getLength(); i++) {
        Element elem = (Element) nodeListData1.item(i);
        data1 = elem.getAttribute("response_data1");
      }
      NodeList nodeListData2 = rootElement.getElementsByTagName("data2");
      for (int i = 0; i < nodeListData2.getLength(); i++) {
        Element elem = (Element) nodeListData2.item(i);
        data2 = elem.getAttribute("response_data2");
      }
    }
    String data1;
    String data2;
  }

  interface ResponseFactory<T> {
    T createResponse(Element root);
  }
  static class XMLAcquirer<T> implements Callable<T> {
    private String url;
    private ResponseFactory<T> factory;
    XMLAcquirer(String url, ResponseFactory<T> factory) {
      this.url = url;
      this.factory = factory;
    }
    @Override
    public T call() throws Exception {
      return parseHttpResponse(getHttpResponse(url));
    }
    private InputStream getHttpResponse(String url) throws IOException {
      OkHttpClient client = new OkHttpClient();
      Request request = new Request.Builder().url(url).get().build();
      ResponseBody body = client.newCall(request).execute().body();
      if(body == null) throw new IOException(url+" return Null.");
      return body.byteStream();
    }
    private T parseHttpResponse(InputStream is) throws Exception {
      Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
      return factory.createResponse(document.getDocumentElement());
    }
  }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る