Return http request result to an activity

2019-09-06 15:34发布

问题:

I have to develop an Android application that perform a http GET request to a server that responds with a JSON string.

Because I need to do that request more times in the app I've created a class only to do this task using AsyncTask.

The problem is that I'm not able to return the JSON sting from the AsyncTask to the activity and reading some question I've understood that the AsynkTask isn't the solution, so I've tried to perform the request using an Android Service but I got a NetworkOnMainThreadException.

How can I create a new thread to run the service and send back the result to the activity?

回答1:

I like use groundy for the command service

public class LoginCommand extends GroundyTask{
private static final String ARG_PASSWORD = "arg_password";
private static final String ARG_USER = "arg_username";

@Override
protected TaskResult doInBackground() {
    String userName = getStringArg(ARG_USER);
    String password = getStringArg(ARG_PASSWORD);
    //do something 
    return succeeded();
}

public static void start(Context context, BaseLoginCommandCallback callback, String login, String password) {
    Groundy.create(LoginCommand.class)
            .arg(ARG_USER, login)
            .arg(ARG_PASSWORD, password)
            .callback(callback)
            .queueUsing(context);
}

public static abstract class BaseLoginCommandCallback{

    @OnSuccess(LoginCommand.class)
    public void handleSuccess(){
        onLoginSuccess();
    }

    @OnFailure(LoginCommand.class)
    public void handleFailure(){
        onLoginError();
    }

    protected abstract void onLoginSuccess();

    protected abstract void onLoginError();
}
 }    

or use retrofit + gson ─ you can use groundy/AsyncTask/service + retrofit or use asynchronous request retrofit

model:

public class SignRequest {
private String login;
private String password;

public SignRequest(String login, String password) {
    this.login = login;
    this.password = password;
}

public SignRequest() {
}

public String getLogin() {
    return login;
}

public void setLogin(String login) {
    this.login = login;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
      }
}      




public class SignResponse implements Parcelable {
private long id;
private String login;
private String message;
@SerializedName("auth_token")
private String authToken;

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getLogin() {
    return login;
}

public void setLogin(String login) {
    this.login = login;
}

public String getMessage() {
    return message;
}

public void setMessage(String message) {
    this.message = message;
}

public String getAuthToken() {
    return authToken;
}

public void setAuthToken(String authToken) {
    this.authToken = authToken;
}




public SignResponse() {
}

public SignResponse(Parcel in) {
    this.id = in.readLong();
    this.login = in.readString();
    this.message = in.readString();
    this.authToken = in.readString();

}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel out, int flags) {
    out.writeLong(id);
    out.writeString(login);
    out.writeString(message);
    out.writeString(authToken);
}
 }

API:

public interface Api {
public static final String URL = "http://xxxxxx/api/v1";
static final String AUTH_SIGNIN = "/auth/signin";
static final String AUTH_SIGNUP = "/auth/signup";

static final String QUERY_AUTH_TOKEN = "auth_token";

@POST(AUTH_SIGNIN)
void sign(@Body SignRequest request, Callback<SignResponse> callback);
@POST(AUTH_SIGNIN)
SignResponsesign(@Body SignRequest request);
@POST(AUTH_SIGNUP)
void signup(@Body SignUpRequest request, Callback<SignUpResponse> callback);

} 

ASYNCHRONOUS:

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);        
    setContentView(R.layout.activity_auth);
  RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint(Api.URL)
            .build();
    Api api = restAdapter.create(Api.class);
    SignRequest request= new SignRequest();
    request.setLogin(login);
    request.setPassword(password);
    api.sign(request, new Callback<SignResponse>() {
        @Override
        public void success(SignResponse signResponse, Response response) {
            Log.d("api", "login: " + signResponse.getLogin());
        .......
        }

        @Override
        public void failure(RetrofitError error) {
            .....
    });

}

SYNCHRONOUS(for exemple AsyncTask):

......
 @Override
protected Void doInBackground(SignRequest... params) {
   SignRequest request =  params[0];
    RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint(Api.URL)
            .build();
    Api api = restAdapter.create(Api.class);
    SignResponse response = api.sign(request);

  return null;
}

.....


回答2:

As @ZygoteInit stated, in my opinion, you should use AsyncTask, Also you can apply some progress bar with this way.

But the easiest way would be using Java native threads and Android handler

final Handler handler = new Handler();
new Thread(new Runnable(){
    @Override
    public void run(){
        final String json = fetchFromNetwork();
        handler.post(new runnable(){
            // finish callback (here is UI thread)
            // do stuff with 'json' string
        });
    }
}).start();


回答3:

Use Volley.jar ! it already use asyncTask

private void makeJsonObjectRequest() {

showpDialog();

JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET,
        urlJsonObj, null, new Response.Listener<JSONObject>() {

            @Override
            public void onResponse(JSONObject response) {
                Log.d(TAG, response.toString());

                try {
                    // Parsing json object response
                    // response will be a json object
                    String name = response.getString("name");
                    String email = response.getString("email");
                    JSONObject phone = response.getJSONObject("phone");
                    String home = phone.getString("home");
                    String mobile = phone.getString("mobile");

                    jsonResponse = "";
                    jsonResponse += "Name: " + name + "\n\n";
                    jsonResponse += "Email: " + email + "\n\n";
                    jsonResponse += "Home: " + home + "\n\n";
                    jsonResponse += "Mobile: " + mobile + "\n\n";

                    txtResponse.setText(jsonResponse);

                } catch (JSONException e) {
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(),
                            "Error: " + e.getMessage(),
                            Toast.LENGTH_LONG).show();
                }
                hidepDialog();
            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                VolleyLog.d(TAG, "Error: " + error.getMessage());
                Toast.makeText(getApplicationContext(),
                        error.getMessage(), Toast.LENGTH_SHORT).show();
                // hide the progress dialog
                hidepDialog();
            }
        });

// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq);

}

Android JSON parsing using Volley



回答4:

You can use a thread with an interface:

Thread class:

public class RequestTask extends Thread {

    private ResultCallback callback;

    public RequestTask(ResultCallback callback) {
        this.callback = callback;
    }

    @Override
    public void run() {
        String result = "";
        // (Your request)

        callback.onFinished(result);
    }

    public interface ResultCallback {
        public void onFinished(String data);
        public void onError();
    }    
}

And where you need the data:

RequestTask task = new RequestTask(new ResultCallback() {
    @Override
    public void onFinished(String data) {
        //do something
    }

    @Override
    public void onError() {
        //show an error
    }
});
task.start();