更新全局变量,通过使用一个接口。

huangapple go评论64阅读模式
英文:

Update global variable by using a interface

问题

我在我的MainActivity.java中有一个异步类:

class Register extends AsyncTask<String, String, JSONObject> {
    JSONObject json;

    @Override
    protected JSONObject doInBackground(String[] args) {

        String function = args[3];
        String email = args[2];
        String password = args[1];
        String name = args[0];

        ContentValues params = new ContentValues();
        params.put("username", name);
        params.put("password", password);
        params.put("function", function);
        if (email.length() > 0)
            params.put("email", email);

        String URL = "https://lamp.ms.wits.ac.za/home/s2090704/index.php";
        new PhpHandler().makeHttpRequest(act, URL, params, new RequestHandler() {
            @Override
            public void processRequest(String response) throws JSONException {
                json = new JSONObject(response);
                System.out.println(json); // 输出 {response: "...", message: "..."}

            }
        });
        System.out.println(json); // 输出 null
        return json;
    }
}

在doInBackground()方法中,PhpHandler使用OkHttp处理细节:

public class PhpHandler {

    JSONObject json;
    static String responseData = "";

    public void makeHttpRequest(final Activity a, String url,
                                ContentValues params, final RequestHandler rh) {

        // Making HTTP request
        OkHttpClient client = new OkHttpClient();
        FormBody.Builder builder = new FormBody.Builder();

        for (String key : params.keySet()) {
            builder.add(key, params.getAsString(key));
        }

        final Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();

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

            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                responseData = Objects.requireNonNull(response.body()).string();
                //System.out.println(responseData);
                a.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            rh.processRequest(responseData);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });

    }
}

RequestHandler是一个在主线程上处理请求的接口:

package com.example.registration;

import org.json.JSONException;

public interface RequestHandler {
    void processRequest(String response) throws JSONException;
}

现在,在我的异步类Register的doInBackground方法的processRequest方法外,json不会更新。我知道接口会使变量成为静态和最终的,是否有任何方法可以更新json的值?

英文:

I have a async class in my MainActivity.java

class Register extends AsyncTask&lt;String, String, JSONObject&gt; {
JSONObject json;
@Override
protected JSONObject doInBackground(String[] args) {
String function = args[3];
String email = args[2];
String password = args[1];
String name = args[0];
ContentValues params = new ContentValues();
params.put(&quot;username&quot;, name);
params.put(&quot;password&quot;, password);
params.put(&quot;function&quot;, function);
if (email.length() &gt; 0)
params.put(&quot;email&quot;, email);
String URL = &quot;https://lamp.ms.wits.ac.za/home/s2090704/index.php&quot;;
new PhpHandler().makeHttpRequest(act, URL, params, new RequestHandler() {
@Override
public void processRequest(String response) throws JSONException {
json = new JSONObject(response);
System.out.println(json); //outputs {response: &quot; ...&quot;,message:&quot;...&quot;}
}
});
System.out.println(json); //outputs null
return json;
}
}

in doInBackground() PhpHandler processes details using OkHttp.

public class PhpHandler {
JSONObject json;
static String responseData = &quot;&quot;;
public void makeHttpRequest(final Activity a, String url,
ContentValues params, final RequestHandler rh) {
// Making HTTP request
OkHttpClient client = new OkHttpClient();
FormBody.Builder builder = new FormBody.Builder();
for (String key : params.keySet()) {
builder.add(key, params.getAsString(key));
}
final Request request = new Request.Builder()
.url(url)
.post(builder.build())
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
responseData = Objects.requireNonNull(response.body()).string();
//System.out.println(responseData);
a.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
rh.processRequest(responseData);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
}
}

RequestHandler is an interface that processes request on the mainUiThread.

package com.example.registration;
import org.json.JSONException;
public interface RequestHandler{
void processRequest(String response) throws JSONException;
}

Now json doesn't update out of the processRequest method in doInBackground method of my async class Register.I know that interfaces make variables static and final is there any way to update the value of json?

答案1

得分: 0

processRequest 方法将在你从 doInBackground 返回 json 之后很长时间才会执行,因为 makeHttpRequest 执行异步的 HTTP 请求。

知道这一点后,你可能会想要重新设计这个类(没有必要在 AsyncTask 中包装已经是异步请求的部分),但如果你真的想要这样做,你将不得不在返回 json 之前等待请求完成(例如,使用 CountDownLatch)。

CountDownLatch latch = new CountDownLatch(1);
someField = null;
AtomicReference<String> someValue = new AtomicReference<>();

// 不要像这样启动新线程,我只是为了保持这个示例简单
new Thread() {
  Thread.sleep(1000); // 等待 1 秒
  someValue.set("abc"); // 注意,当使用 AtomicReference 时,你可以使用 `set` 方法而不是 `=` 运算符来赋值其值,可以将其保持为局部变量而不是类字段
  latch.countDown(); // 将 latch 计数减一
}.run();

System.out.println(someValue.get()); // null - 因为赋值将会在一秒后发生

latch.await(); // 这将强制当前线程等待,直到 latch 计数达到零(初始值为 1,传递给构造函数)

System.out.println(someValue.get()); // "abc"

阅读更多

英文:

processRequest method will be executed long after you return json from doInBackground, because makeHttpRequest performs an asynchronous http request.

Knowing this, you will probably want to re-design this class (there is no need to wrap already asynchronous request in AsyncTask), but if you really want to do it this way, you would have to wait for your request to complete before returning the json (for example, by using CountDownLatch).

  CountDownLatch latch = new CountDownLatch(1);
  someField = null;
  AtomicReference&lt;String&gt; someValue = new AtomicReference&lt;&gt;();

  // don&#39;t start new threads like this, im just trying to keep this example simple
  new Thread() {
    Thread.sleep(1000); // sleep for 1 second
    someValue.set(&quot;abc&quot;); // notice that because when using AtomicReference you assign it&#39;s value using `set` method instead of `=` operator, you can keep it as local variable instead of field class
    latch.countDown(); // reduce latch count by one
  }.run();
  
  System.out.println(someValue.get()); // null - because the assignation will happen in one second
  
  latch.await(); // this will force current thread to wait until the latch count reaches zero (initial was 1, passed to constructor)

  System.out.println(someValue.get()); // &quot;abc&quot;

read more

huangapple
  • 本文由 发表于 2020年5月31日 06:57:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/62109617.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定