2016-02-22 6 views
16

私の活動の中で奇妙な問題が発生しました。 私はonActivityResultの写真/ビデオの撮影から戻ってくるときに、ユーザーがカメラに名前を付けることができるダイアログを表示しています。 ユーザーが[OK]を押すと、ファイルをコピーする要求されたファイル名を持つサブジェクトにonNext()を送信します(進行状況ダイアログが表示されます)。subscribeOn()が別のスレッドで呼び出されていても、メインスレッドで観測可能な実行が行われます

何らかの理由で、私がsubscribeOn(Schedulers.io())を呼び出したにもかかわらず、コピーを行うmap()関数が常にメインスレッドで呼び出されます。 observeOn(Schedulers.io())からsubscribeOn(Schedulers.io())呼び出しを変更

@Override 
protected void onActivityResult(final int requestCode, int resultCode, Intent intent) { 
    ... 

    final PublishSubject<String> subject = PublishSubject.create();` 

    mSubscription = subject 
      .subscribeOn(Schedulers.io()) 
      .map(new Func1<String, String>() { 
       @Override 
       public String call(String fileName) { 
        Log.I.d(TAG,"map"); 
        return doSomeIOHeavyFuncition(); 
       } 
      }) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(new Action1<String>() { 
       @Override 
       public void call(final String fullPath) { 
        Log.d(TAG,"onNext"); 
        doSomethingOnUI(fullPath); 

        subject.onCompleted(); 
       } 
      }, new Action1<Throwable>() { 
       @Override 
       public void call(Throwable throwable) { 
        ... 
       } 
      }, new Action0() { 
       @Override 
       public void call() { 
        ... 
       } 
      }); 

    final AlertDialog dialog = new AlertDialog.Builder 
    .... 
    .create() 
      .show(); 

    dialog.getButton(DialogInterface.BUTTON_POSITIVE) 
      .setOnClickListener(new View.OnClickListener() { 
       @Override 
       public void onClick(View view) { 
        String someString = getStringFromDialog(dialog); 

        dialog.dismiss(); 
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 
        imm.hideSoftInputFromWindow(input.getWindowToken(), 0); 

        showProgressDialog(); 
        subject.onNext(someString); 
       } 
      }); 
} 

問題を解決しました。 まだ動作しなかった理由を知りたいのですが...

答えて

33

subscribeOnobserveOnはほとんど混乱しているオペレータがあります。前者は、指定されたスケジューラー(スレッド)でサブスクリプションの副作用が発生することを確認していますが、その値がそのスレッドでポップアップすることを意味するものではありません。

たとえば、Observerがサブスクリプションに参加したときにネットワーク接続を開くと、そのサブスクリプションをメインスレッドで実行したくないため、サブスクリプションとネットワーク接続の場所を指定するにはsubscribeOnが必要です作成した。

データが最終的に到着すると、放出スレッドはスケジューラのいずれかまたはバックグラウンドの普通の古いスレッドになります。私たちはそのスレッドを知らない、あるいは好きではないので、データの観察を別のスレッドに移したいと思っています。これはobserveOnの動作です:オペレータが指定されたスケジューラでonNextロジックを実行した後にオペレータを確実にします。 Android開発者は、値の観測をメインスレッドに戻すために既にそれを使用しています。ユース複数observeOn事業者:稀にかかわらず、説明しない何

あなたは再びメインスレッド上で、最終的な結果の土地の前にメインスレッドオフにいくつかの余分な計算をしたいときに何が起こるかである

私のために何か新しいものをだ
source 
.observeOn(Schedulers.computation()) 
.map(v -> heavyCalculation(v)) 
.observeOn(Schedulers.io()) 
.doOnNext(v -> { saveToDB(v); }) 
.observeOn(AndroidSchedulers.mainThread()) 
... 
+1

。 RxJavaをしばらく使用すると、 'subscribeOn'スレッドが、最初の' observeOn'までのすべてのダウンストリーム演算子または指定されたスケジューラーを持つ演算子に適用されていることが確かめられました。それは真実ではありませんか?この場合、 'subscribeOn'の後のスレッド選択のルールは何ですか? – AndroidEx

+0

'subscribeOn'エフェクトは上流に行き、イベントのソースに近づきます。それをこれと考えてください。ソースはありますが、別のスレッドで購読したいと思っています。 'new thread(() - > source.subscribe(s))。start();'と書くといいでしょう。このようなことは 'subscribeOn'で起こります。スケジューラは、そのソースにサブスクライブするときに何が起こるかに基づいて選択されました。直ちにネットワーク接続を開くか、長いファイルの読み込みを開始すると、 'Schedulers.io()'に行きます。それが大きく計算を開始するなら、あなたは 'comput()'を行います。 – akarnokd

+3

ありがとうございます。私がsubscribeOnの後に何が起こるかにもっと関心がありましたが、次の演算子がどのスレッドに適用されていますか。あなたの言葉からは、subscribeOnで指定されたスレッドであることが保証されていないという印象があります。 – AndroidEx

関連する問題