2016-05-10 5 views
0

私が作成したネットワーク接続クラスに苦労しています。作成したRunnableの結果、サーバーから必要なすべての情報を含むJSONオブジェクトが返されます。スレッドは実行され、データを完全に受信しますが、もちろん、プログラムは実行中のままです。その結果、JSONExceptionがNULLになります。クラスメソッドのコールバックの作成

Net.createNetworkThread(SignupActivity.this, requestURI, formVars); 
JSONObject jsonResponse = Net.jsonResponse; 

Iは、以下の方法を有するNetworkManagerと呼ばれるクラス(jsonResponseはクラスの開始時に初期化される)

JSONObject jsonResponse; 

public void createNetworkThread(Context context, final String requestURI, final RequestBody formParameters) { 

    Runnable runnable = new Runnable() { 
     @Override 
     public void run() { 
      OkHttpClient client = new OkHttpClient(); 
      Request request = new Request.Builder().url(requestURI).post(formParameters).build(); 

      Response response = null; 

      try { 
       response = client.newCall(request).execute(); 
       String stringResponse = response.body().string(); 
       NetworkManager.this.jsonResponse = new JSONObject(stringResponse); 

       // This works perfectly, "message" is received and printed to the log // 
       Log.d("Net", NetworkManager.this.jsonResponse.getString("message")); 

      } catch (IOException e) { 
       Log.d("Net", "Failed"); 
       e.printStackTrace(); 
      } catch (JSONException e) { 
       e.printStackTrace(); 
      } 
     } 
    }; 

    Thread thread = new Thread(runnable); 
    thread.start(); 
} 

上記のように、アクティビティから呼び出された作成しました

JSONオブジェクトjsonResponseは、スレッドが依然として応答用のサーバーにアクセスしているため、NULLとして戻しています。

jsonResponseオブジェクトがNULLを戻さないようにするためにスレッドが完了するまでNet.jsonResponseによってデータが取り込まれるのを止める方法を理解する必要があります。

助けが必要ですか?

+1

あなたはOKHttpのドキュメントを読んでください...コールバックを持つCall.executeの非同期バージョンがあります(コールバックはバックグラウンドスレッドでも呼び出されます)https://github.com/square/okhttp/wiki/Recipes #asynchronous-get – Selvin

+0

あなたはAsyncTask、http://developer.android.com/reference/android/os/AsyncTask.htmlを使用する必要があります。一般的なスレッディングについて少しお読みください。 – anders

+0

スレッドは非同期で実行されます。 AsyncTaskを代わりに使用する – Pooya

答えて

1

私はあなたの質問のコメントに同意し、あなたがここで何ができるかをあなたに知らせます。

ネットワーク通話を行うためのメインUIスレッドを取得するだけのスレッドを作成する場合は、おそらくOkHttp機能を使用して、ネットワークからの呼び出しをスレッドから取得し、結果を得るためのコールバックを提供する機能を使用します。このようなもの。あなたは、いくつかの例here

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

    client.newCall(request).enqueue(new Callback() { 
     @Override 
     public void onFailure(Request request, IOException e) { 

     } 

     @Override 
     public void onResponse(Response response) throws IOException { 
     // this is the callback which tells you the network call was successful, If like to make some changes to UI, you should call `runOnUiThread`. 

     "YourClassName".this.runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 

       } 
      }); 
     } 
    }); 

をチェックすることもできますし、また、メインUIスレッドをオフに行わあなたの仕事を取得し、あなたのコールバックで結果を与えるAsyncTaskを使用することができます。ここ

private class MyTask extends AsyncTask<Void, Void, Void> { 

//you can change the Type Void, Void, Void here to something which you want 
//First Void belongs to doInBackground(Void... avoid) 
//Second Void belongs to onProgressUpdate(Void... progress) 
//Third Void belongs to onPostExecute(Void result) 
// you may change these as you fit, 
//when you want to start this class with your argument you can do something like this. 
//new MyTask().execute("your argument to doInBackground"); 


    @Override 
    protected void onPreExecute() { 
     super.onPreExecute(); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
    // this is the method where you provide your implementation for doing a task off the main UI thread. 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void aVoid) { 
     super.onPostExecute(aVoid); 
    // in this callback you are back in the main UI thread to make changes to UI depending on your response 
    } 
} 

は、メインスレッドの負荷を軽減したい場合は、並列タスクが、それは一般的に、時間の任意の金額を言えば、後に実行だ終えることができましたことを考慮すべきであるAsyncTask

+0

ありがとうございました。私はAsyncTaskを読んだことがありますが、答えより多くの質問があります。どのように引数を渡すのですか? – mwieczorek

+0

私は新しいMyTask()の答えを更新しました。execute( "doInBackgroundへのあなたの引数"); –

0

の一例です。確かに、(join()を使って)子スレッドが終了するメインスレッドを待つことができますが、これはスピードの点では疑問です。私は、スレッドがNULLを返すからそれを止める するために完了するまでNet.jsonResponseによって移入 であることからjsonResponseオブジェクトを停止する方法を把握する必要があり

とにかく、あなたの質問に答えます。

メインスレッドが効果的に完全になりますので、私はあなたが

public Thread createNetworkThread(... 
{ 
... 
    Thread thread = new Thread(runnable); 
    thread.start(); 
    return thread; 
} 

、その結果

Thread t = Net.createNetworkThread(SignupActivity.this, requestURI, formVars); 
t.join(); // Wait until 't' finishes -- try-catch is omitted for the sake of demo. 
JSONObject jsonResponse = Net.jsonResponse; 

これに

public void createNetworkThread(... 

を変更示唆、明らかに、パフォーマンスの問題を開きますチルまで 't.join()'によってブロックされていますdスレッドが終了します。

トピックの質問に答える:

package multithreaded; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

public class Multithreaded { 

    public static void main(String[] args) throws Exception { 
     Logger logger = LoggerFactory.getLogger("Main"); 

     Worker<String, String> worker = new Worker<String, String>(
      (String s) -> 
      { // This is actual call-back code. 
       // It will be called by method 'apply' of interface 'Function' in the 'Worker'. 
       // It will accept String parameter and pass it in this block as variable 's' 
       logger.info("Embrace the beauty and power of Java 8! "+s); // yes, we can use local variables of the parent thread. 
       return "Call-Back "+s; 
      } 
     ); 

     logger.info("Application starts new Worker."); 
     worker.start(); 
     logger.info("Worker is running in background."); 

     Thread.currentThread().sleep(500); // Simulate some activity here... 
     logger.info("Result is unpredictable (could be null): "+worker.getResult()); 

     // Wait here until worker is fully finished 
     worker.join(); 
     logger.info("Result is predictable: "+worker.getResult()); 
    } 
} 

Worker.java:あなたはこのようなラムダ関数インタフェース使用できるJava 8のコードの上に複数回実行

package multithreaded; 

import java.util.function.Function; 

public class Worker<T extends String, R extends String> extends Thread { 

    private final Function<T, R> callBack; 
    private volatile R result; 

    public Worker(Function<T, R> callBack) 
    { this.callBack = callBack; } 

    @Override 
    public void run() 
    { 
     try{ 
      int i = (int)(Math.random()*1000); 
      // simulate some activity unpredictable in terms of duration 
      Thread.currentThread().sleep(i); 

      // After "activity" is finished -- call the call-back function and get result in local variable. 
      // (Synchronization ommited for the sake of simplicity) 
      result = this.callBack.apply((T)("Result "+i)); // now let's call the call-back function and save the result in local variable. 
     } 
     catch(InterruptedException e) 
     {e.printStackTrace();} 
    } 

    // Getter for the local variable, populated by call-back function. 
    // (Synchronization ommited for the sake of simplicity) 
    public R getResult() 
    { return this.result; } 
} 

すると、あなたは気づくでしょう親スレッドの観点からは、子スレッドが完全に終了するまで、結果は予測できません。

p.s.私はあなたのアプリケーションでデータ処理のロジック全体を再考し、おそらくプロデューサ - コンシューマロジックを使用して、完全に独立したマルチスレッド処理を再考することを検討することをお勧めします。

関連する問題