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

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

ただいまの
回答率

90.48%

  • Android Studio

    3803questions

    Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

OneDriveAPIでの複数ファイルの非同期ダウンロードを制御したい

解決済

回答 1

投稿 編集

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

rafiene3249

score 39

いつもお世話になっております。OneDriveAPIでの複数ファイルの非同期ダウンロードを制御したいのですが、
上手く行かず困っていて皆様のお知恵をお借りしたい所存です。

latch.awaitをしなければ複数ファイルの非同期ダウンロード自体は出来るのですが、
該当月の全ファイルをダウンロードし終わった時に表示を更新する処理を行いたいので
latchを使い全ファイルをダウンロードし終わったのを監視しようとした所、
ダウンロードをせずにlatch.awaitが先に働いてしまい何も出来ない状態になります。

1:latchを組み込む前のログ

D/デバッグ: initializeControl が呼ばれました
D/デバッグ: 20170929.txt を削除しました
D/デバッグ: DrawMainActivity.onPostExecute
D/デバッグ: DrawMainActivity.sendBroadcast
D/デバッグ: BroadcastReceiver : mDrawReceiver が呼ばれました
D/デバッグ: DrawMonthlyCalendar : dayTextList.size()=42
D/デバッグ: 20170929.txt ちゃん、見~つけた
D/デバッグ: 20170929.txt(main_data) をダウンロードしています...
D/デバッグ: 20170929.txt をダウンロードしました

ダウンロードより先に描画が走っています
これをなんとかする為にlatchを組み込んだのですが

2:下記のコードを実機にて実行した時のログ

D/デバッグ: initializeControl が呼ばれました
D/デバッグ: 全ファイルのダウンロード待ちに入ります

ダウンロードを始める前に待ちに入ってしまい、そのまま動かなくなります。
どの様に修正すればlatchで全ファイルのダウンロードを監視出来るかご教授頂けると助かります。

MainActivity.java(抜粋)

    public void hoge(int offset) {

        //カレンダーテーブル作成
        CalendarInfo cl = new CalendarInfo(currentYear, currentMonth);
        final CountDownLatch latch = new CountDownLatch(cl.lastDate);    ← lastDateには月の末日が帰ってきます

        Hoge hoge2 = new Hoge();
        hoge2.setmLatch(latch);
        hoge2.setmYear(this.currentYear);
        hoge2.setmMonth(this.currentMonth);
        hoge2.run();
    }
Hoge.java(一部省略)

public class Hoge {
    private static CountDownLatch mLatch;
    private static int mYear;
    private static int mMonth;
    private static int row;
    private static int col;

    public void run()
    {
        final CountDownLatch latch = new CountDownLatch(42);

        //カレンダーテーブル作成
        final CalendarInfo cl = new CalendarInfo(Hoge.mYear, Hoge.mMonth);

        row = 0;
        col = 0;
        for (int i = 0; i < 42; i++) {
            if (cl.calendarMatrix[row][col] != 0) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            final App app = (App) getsApplication();
                            String DataFileName = String.format("%04d%02d%02d.txt", Hoge.mYear, Hoge.mMonth, cl.calendarMatrix[row][col]);

                            // OneDriveからスケジュールファイルを取得する前にスケジュールファイルを削除する
                            File file = new File(getsApplication().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), DataFileName);
                            if (file.exists()) {
                                file.delete();
                                Log.d("デバッグ", String.format("%s を削除しました", DataFileName));
                            }

                            final DownloadFiles schedule = new DownloadFiles();
                            // DownloadTaskを実行する
                            // 引数がdoInBackground()メソッドに渡される
                            schedule.setCountDownLatch(Hoge.mLatch);
                            schedule.execute(DataFileName, "main_data", null, null);
                        } catch (NullPointerException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
            col += 1;
            if (col == 7) {
                row += 1;
                col = 0;
            }
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 全ファイルのダウンロード待ち
                    Log.d("デバッグ", "全ファイルのダウンロード待ちに入ります");
                    mLatch.await();
                    Log.d("デバッグ", "全ファイルのダウンロード待ちから抜けました");
                } catch(InterruptedException e) {
                }
            }
        }).start();

    }
}
DownloadFiles.java(一部省略)

public final class DownloadFiles extends AsyncTask<String,Void,Boolean> {

    private static CountDownLatch mLatch;

    public static void setCountDownLatch(CountDownLatch latch ) {
        mLatch = latch;
    }

    @Override
    protected Boolean doInBackground(final String... param) {
        String FileName = param[0];
        String Mode = param[1];
        download_file(FileName, Mode);

        return true;
    }

    private void DownloadWait(String FileName, String Mode) {
        Log.d("デバッグ", String.format("%s(%s) をダウンロードしています...", FileName, Mode) );

        try {
            while(true) {
                File file = new File(getsApplication().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), FileName );
                if( file.exists() && file.length() > 0 ) {
                    final App app = (App)getsApplication();
                    if( Mode.equals("set_staff") ) {
                    //略
                    }
                    else if( Mode.equals("sub_staff") ) {
                    //略
                    }
                    else if( Mode.equals("sub_data") ) {
                    //略
                    }
                    else if( Mode.equals("main_data") ) {
                        Log.d("デバッグ", String.format("%s をダウンロードしました", FileName) );
                        // ダウンロードしたファイルの読み込みはしない
                        // 画面の更新はしない
                        mLatch.countDown();
                        Log.d("デバッグ", String.format("latch count:%d", mLatch.getCount() ));
                    }
                    break;
                }
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            Log.d("デバッグ", String.format("%s", e.getMessage() ) );
        }
    }

    private ICallback<Item> getDownloadCallback(final App context, final String filename, final String mode ) {
        return new DefaultCallback<Item>(context) {
            @Override
            public void success(final Item item) {
                if (item.children == null || item.children.getCurrentPage().isEmpty()) {
                    Log.d("デバッグ","OneDrive 空なんですけど・・");
                } else {
                    boolean findflag;
                    findflag = false;
                    for (final Item childItem : item.children.getCurrentPage()) {
                        if( childItem.name.equals(filename) ) {
                            findflag = true;
                            Log.d("デバッグ", String.format("%s ちゃん、見~つけた", filename));
                            final DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
                            final String downloadUrl = childItem.getRawObject().get("@content.downloadUrl").getAsString();
                            final DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));
                            request.setTitle(childItem.name);
                            Resources res = context.getResources();
                            request.setDescription(res.getString(R.string.file_from_onedrive));
                            request.allowScanningByMediaScanner();
                            if (childItem.file != null) {
                                request.setMimeType(childItem.file.mimeType);
                            }
                            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

                            File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), filename);
                            request.setDestinationUri(Uri.fromFile(file));

                            downloadManager.enqueue(request);
                            //toast( res.getString(R.string.starting_download_message), Toast.LENGTH_SHORT );

                            DownloadWait(filename, mode);

                            break;
                        }
                    }
                    if ( findflag == false ) {
                        Log.d("デバッグ", String.format("%s ちゃん、居ませんでした", filename));
                        mLatch.countDown();
                        Log.d("デバッグ", String.format("latch count:%d", mLatch.getCount() ));
                    }
                }
            }

            @Override
            public void failure(final ClientException error) {
                Log.d("デバッグ","Itemが見つかんねぇ");
            }
        };
    }

    private void download_file( String filename, String mode ) {
        final App app = (App)getsApplication();

        try {
            final IOneDriveClient oneDriveClient = getOneDriveClient();
            final ICallback<Item> itemCallback = getDownloadCallback(app, filename, mode);

            final String itemId;
            itemId = "root";

            oneDriveClient
                    .getDrive()
                    .getItems(itemId)
                    .buildRequest()
                    .expand(getExpansionOptions(oneDriveClient))
                    .get(itemCallback);
        } catch ( RuntimeException e ) {
            Log.d("デバッグ", String.format("%s", e.getMessage()) );
        }
    }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

check解決した方法

0

結論から言うと、UIスレッドでfor文で時間のかかる非同期処理を行うスレッドを
複数個作成しようとしたのがそもそも間違いでした。

UIスレッドでスレッドを作成し、そのスレッド内でfor文を回し時間のかかる非同期処理を
複数回呼ぶよう変更した所、思った様な挙動が得られました。

尚、確認作業を単純化する為に元のソースを弄らずに、
スレッドとラッチの動作確認の為の新規プロジェクトを作成し、
今回上手く動作しなかったプロジェクトのモデルケースを作成。
時間のかかる非同期処理はsleep()で擬似的に再現して動作を確認し、
元のプロジェクトと同様の挙動をする事を確認出来たので、
その後上記修正を行い思った様な挙動が得られた為、
元のソースに変更内容を反映して最終的な動作確認を行い修正完了となりました。

以下はモデルケースのソースです。

Hoje.java(抜粋)

public class Hoge {

    public void run() {
        Log.d("デバッグ", String.format("Hoge() latch Count : %02d", latch.getCount()) );
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.d("デバッグ", "スレッド呼び出し開始" );
                    for (int i = 0; i < 31; i++) {
                        String DataFileName = String.format("%04d%02d%02d.txt", 2017, 9, i);

                        DownHoge dh = new DownHoge();
                        dh.execute(DataFileName, null, null);
                    }
                    Log.d("デバッグ", "スレッド呼び出し終了" );
                } catch (NullPointerException e) {
                    Log.d("デバッグ", e.getMessage() );
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 全ファイルのダウンロード待ち
                    Log.d("デバッグ", "全ファイルのダウンロード待ちに入ります");
                    latch.await();
                    Log.d("デバッグ", "全ファイルのダウンロード待ちから抜けました");
                } catch(InterruptedException e) {
                    Log.d("デバッグ", e.getMessage() );
                }
            }
        }).start();
    }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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

  • Android Studio

    3803questions

    Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。