在类方法上创建回调

时间:2016-05-10 14:01:45

标签: java android

我正在为我创建的网络连接类而苦苦挣扎。我创建的Runnable的结果返回一个JSON对象,其中包含服务器所需的所有信息。线程运行并完美地接收数据,但当然,程序在此期间保持运行,这导致JSONException为NULL。

我创建了一个名为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();
}

上述内容是从Activity中调用的,如下:

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

JSON对象jsonResponse返回为NULL,因为Thread仍在访问服务器以获取响应。

我需要弄清楚如何阻止jsonResponse对象被Net.jsonResponse填充,直到线程完成以阻止它返回NULL。

任何帮助?

2 个答案:

答案 0 :(得分: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() {

                }
            });
        }
    });

或者您可以使用AsyncTask来完成主UI空间的工作,并在回调中为您提供结果。

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

的示例

答案 1 :(得分:0)

如果你想卸载主线程,你应该考虑并行任务可以在一般来说任何时间后完成它的执行。当然,你可以在主线程中等待子线程完成(使用&#39; join()&#39;),尽管这在速度增益方面有点可疑。

无论如何,回答你的问题:

  

我需要弄清楚如何阻止jsonResponse对象   由Net.jsonResponse填充,直到线程完成为止   阻止它返回NULL。

我建议你改变

public void createNetworkThread(...

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;

这显然打开了性能问题,因为主线程将被&#t ;join()&#39;有效地完全阻止。直到子线程完成。

回答主题中的问题:在Java 8中,您可以使用lambda功能界面,如下所示:

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:

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。我建议你重新思考应用程序中数据处理的整个逻辑,并考虑重新分解为完全独立的多线程处理(可能使用 producer-consumer 逻辑)。