This project run with a web server. When user click button, it should post the message inside of EditText. I use Retrofit2 for it. The program has stoped when I click button.
ApiInterface.java
#POST("api/EmergencyNotification/SendNotification")
Call<SendMessageModel>postMessage(#Header("Authorization") String token,
// #Field(("PhotoRequest")) String photoRequest,
// #Field(("Location")) String location,
#Field(("MessageBody")) String messageBody);
// #Field(("AnswerValue")) String answerValue);
In the button OnClick this function runs:
protected void postMessage(){
startProgress();
String authorization = SessionHelper.getCustomerTokenWithBearer();
// Loc = lattitude + longitude;
Call<SendMessageModel> call = ApiService.apiInterface.postMessage(authorization,
mesaj.getText().toString().trim());
call.enqueue(new Callback<SendMessageModel>() {
#Override
public void onResponse(Call<SendMessageModel> call, Response<SendMessageModel> response) {
stopProgress();
if (response.isSuccessful()){
if (response.body() != null){
DialogHelper.showDialogWithOneButton("",response.body().getData());
}
}
else {
ApiErrorUtils.parseError(response);
}
}
#Override
public void onFailure(Call<SendMessageModel> call, Throwable t) {
stopProgress();
DialogHelper.showFailedDialog();
}
});
}
Ok. I solved it now. My api url was wrong and I added new #Multipart and #Part instead of #Field.
#POST("api/EmergencyNotification/SendMessage")
Call<SendMessageModel>postMessage(#Header("Authorization") String token,
#Part(("MessageBody")) String messageBody);
You are missing #FormUrlEncoded attribute since you are using field attribute instead of body
#POST("api/EmergencyNotification/SendNotification")
#FormUrlEncoded
Call<SendMessageModel>postMessage(#Header("Authorization") String token,
...
Related
Im in a confusing spot right now. My API returns a Token for Login when posting a new User with UserData. How do I get the response.body() as a String to save it?
It only returns a Post object what I don't actually want. I only use it to create the Post.
private void createPost(User user) {
Post post = new Post(user.getName(), user.getGender(), user.getBirthyear(), user.getHeight(),user.getWeight());
Call<Post> call = jsonmongo.createPost(post);
// To execute it asynchron
call.enqueue(new Callback<Post>() {
#Override
public void onResponse(Call<Post> call, Response<Post> response) {
if (!response.isSuccessful()) {
Log.e("RESPONSECODE", ""+ response.code());
return;
}
Log.e("RESPONSECODE", ""+ response.code());
}
#Override
public void onFailure(Call<Post> call, Throwable t) {
Log.e("RESPONSECODE", ""+ t.getMessage());
}
});
}
Get Response.Body and save it to the Database via SQL Adapter ( adapter.addToken(response.body()) )
response.body().toString only returns Object reference ( com.example.Resources.Post#4c8352 )
String S = new Gson().toJson(response.body())
Log.e("JSON", S)
Returns this:
E/JSON: {"age":0,"gender":0,"height":0,"weight":0}
Wanted output:
E/JSON: {"token":aslfjkhr9RRRRf283FGr3489pjfGGG34HH89fj}
let me try... you can use Gson library to create a String json object from the response.
Try it:
new Gson().toJson(response);
So I have this POST request made to the server and based on an argument the server will return error message within the errorBody() of Retrofit. I am trying to handle that Plain Text error returned by the server and then display it to the user within my Android application which uses Java. Below is my current attempt but this is giving me this error in Logcat:
#Url cannot be used with #POST URL (parameter #1)
Here is 400 response from the server:
Interface:
public interface ChangePickLocationClient
{
#GET
Call<ResponseBody> checkItem(#Url String url, #Header("Authorization") String authToken);
#GET
Call<String> getStringError(#Url String url, #Header("Authorization") String authToken);
#POST("Pick/ChangePickLocationAcceptChange")
Call<String> changePickLocationPOST(#Url String url, #Header("Authorization") String authToken, #Body
ChangePickLocationPostModel changePickLocationPostModel);
}
Implementation:
private static final String BASE_URL = "http://00.00.00.1234/api/";
Gson mGson = new Gson();
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient())
.baseUrl(BASE_URL).addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(mGson))
.build();
ChangePickLocationClient ChangePickLocationClient =
retrofitPOST.create(ChangePickLocationClient.class);
String itemNumber = itemNumberValue.getText().toString();
newPickLocationValue.setText(newPickLocationValue.getText().toString().toUpperCase());
String newPickLocation = newPickLocationValue.getText().toString();
String token = globalClass.getActiveToken();
final ChangePickLocationClient mChangePickLocationInterface =
retrofit.create(ChangePickLocationClient.class);
Call<String> mCallErrorPOST = mChangePickLocationInterface.changePickLocationPOST
(postUrl, "Bearer " + globalClass.getActiveToken(),
changePickLocationPostModel);
call.enqueue(new Callback<ChangePickLocationPostModel>()
{
#Override
public void onResponse(Call<ChangePickLocationPostModel> call,
Response<ChangePickLocationPostModel> response)
{
String mPlainTextResponse = null;
try {
if(response.errorBody() != null)
{
mPlainTextResponse = response.errorBody().string();
}
} catch (IOException e)
{
e.printStackTrace();
}
Toast.makeText(ChangePickLocation.this, mPlainTextResponse
,Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<ChangePickLocationPostModel> call, Throwable t)
{
Toast.makeText(ChangePickLocation.this, "Unknown server error!"
,Toast.LENGTH_SHORT).show();
}
});
When the response is 400, the second call being made needs to be a clone() call. This is because the Call cannot be used more than once as stated in the documentation.
use this:
call.clone().enqueue(new Callback<ChangePickLocationPostModel>()
instead of
call.enqueue(new Callback<ChangePickLocationPostModel>()
I did this and it doesn't work
#Headers("Accept: application/json")
#GET("objects/last_state/?modify_after={date}")
Call<State> getUpdate(#Header("Authorization") String token, #Path("date") String date);
on SyncHttpClient i did this :
syncHttpClient.get(context, "https://****/objects/last_state?modify_after=" + lastModify, headers, null, handler);
and it work. What did I do wrong in that?
I call this method :
MyApplication.retrofitInterface.getUpdate("SCToken " + singleton.getUid(), singleton.getLastModify()).enqueue(new Callback<State>() {
#Override
public void onResponse(Call<State> call, Response<State> response) {
Log.e("tak", "tak");
}
#Override
public void onFailure(Call<State> call, Throwable t) {
Log.e("nie", "nie");
}
});
Try use a #Query in Retrofit to this type of request with get (?=)
#Headers("Accept: application/json")
#GET("objects/last_state/")
Call<MovieResult> getAllMovies(#Header("Authorization") String token, #Query("modify_after") String date);
In Retrofit you need to express the ?modify_after={date} part of the path as a #Query("name") parameter of the method.
So, replace #Path("date") with #Query("modify_after"), and just put #GET("objects/last_state")
I would really really appreciate any help I can get on this! Sorry for the long question.
I'm creating this android app, where to sign up, users will type in their phone number and submit it, to get a verification code via text message.
I have worked off of this tutorial:
https://code.tutsplus.com/tutorials/sending-data-with-retrofit-2-http-client-for-android--cms-27845
I have reduced the 2 fields in their app to one field - one text field for a phone number, and a submit button below. This phone number is to be sent to the API.
I'm really new to Retrofit, and I've been trying for a while now to successfully send a call to the API. I have tested the API call by using the 'Postman' desktop app, and the API is alive and responding...I've just not been able to form a valid request to send to the API.
The JSON schema our API guy designed...for this activity needs just one string, the phone number:
{
"phone_number": "string"
}
and then if it is a valid phone number and the user isn't in the database, you get back a 200 response
{
"message": "string"
}
OR you can get back a 400 response from the API
{
"error": "string",
"description": "string"
}
My retrofit interface, called APIService.java looks like this:
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.Body;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
public interface APIService {
#POST("/verifications/signup/send")
#FormUrlEncoded
Call<Post> sendPhoneNumber(#Field("phone_number") String phone_number);
}
I am really new to retrofit2, and above, I can sense one issue, which I don't know how to solve. From the API schema I was given, this one parameter I sent to the API should be 'body'....not 'field'. Maybe in retrofit #Body...I am not too sure how to implement that in this java file above.
Now, what I did below might be really stupid...I don't understand how retrofit java 'model' classes should be made. I followed one tutorial that modeled the class after the RESPONSE, rather than the data call. So, I modified their Post class (which is what I called my ?JSON object to send a single phone number). So my Post class looks like this:
public class Post {
#SerializedName("message")
#Expose
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public String toString() {
//return "Post{" + "message = " + message + '}';
return "This is a return message string";
}
}
Honestly, I think what I've done might be totally wrong, but I am not sure how to design the object(Post) class, considering I don't even know what this class will be used for...except getting the response back?
public class MainActivity extends Activity {
private TextView mResponseTv;
private APIService mAPIService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText phoneNumberEt = (EditText)
findViewById(R.id.et_phoneNumber);
Button submitBtn = (Button) findViewById(R.id.btn_submit);
mResponseTv = (TextView) findViewById(R.id.tv_response);
mAPIService = ApiUtils.getAPIService();
submitBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String phoneNumber = phoneNumberEt.getText().toString().trim();
if (!TextUtils.isEmpty(phoneNumber)) {
sendPost(phoneNumber);
}
}
});
}
public void sendPost(String phone_number) {
mAPIService.sendPhoneNumber(phone_number).enqueue(new Callback<Post>() {
#Override
public void onResponse(Call<Post> call, Response<Post> response) {
int statusCode = response.code();
if (response.isSuccessful()) {
showResponse("Response code is " + statusCode + ". Submitted successfully to API - " + response.body().toString());
Log.i(TAG, "post submitted to API." + response.body().toString());
}
}
#Override
public void onFailure(Call<Post> call, Throwable t) {
showResponse("Unable to submit post to API.");
Log.e(TAG, "Unable to submit post to API.");
}
});
}
public void showResponse(String response) {
if (mResponseTv.getVisibility() == View.GONE) {
mResponseTv.setVisibility(View.VISIBLE);
}
mResponseTv.setText(response);
}
}
My other files are pretty much exactly like the files in the tutorial link above. That's what I modified to get to my simple one text field version.
When I am able to get this to contact the API, and I can read the response, then I'll incorporate this into the real app I'm working on.
For now, the app compliles, and runs on my phone(and emulator too). When I submit the phone number, the text field below the submit button doesn't show any message like it should...so I know for sure that theres a problem once
mAPIService.sendPhoneNumber(phone_number).enqueue(new Callback<Post>() {
#Override
public void onResponse(Call<Post> call, Response<Post> response)
{
is reached in MainActivity.
I think that this api requires parameters in JsonObject. so try this
In your APIService
#POST("/verifications/signup/send")
Call<JsonObject> sendPhoneNumber(#Body JsonObject phone_number);
And when sending data use this
JsonObject object=new JsonObject();
object.addProperty("phone_number",yourPhoneNumber);
and in your send post method
mAPIService.sendPhoneNumber(object).enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
int statusCode = response.code();
if (response.isSuccessful()) {
showResponse("Response code is " + statusCode + ". Submitted successfully to API - " + response.body().toString());
Log.i(TAG, "post submitted to API." + response.body().toString());
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
showResponse("Unable to submit post to API.");
Log.e(TAG, "Unable to submit post to API.");
}
});
}
Please try and let me know if it is working.
According to the JSON schema with the phone number, you need to pass the phone number in the body of the API. Instead of using a #Field annotation, use a #Body annotation where the parameter will be an instance of the RequestBody class.
#Field documentation https://square.github.io/retrofit/2.x/retrofit/retrofit2/http/Field.html
Create the new RequestBody class with field phone number.
public class RequestBody {
#Expose
#SerializedName("phone_number")
private String phoneNumber;
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
From the activity when you want to pass the phone number, create an object of the RequestBody class, pass the phone number in the setPhoneNumber() method. Then pass this object in the APIService as a parameter.
In MainActivity.class,
public void sendPost(String phone_number) {
RequestBody requestBody = new RequestBody();
requestBody.setPhoneNumber(phone_number);
mAPIService.sendPhoneNumber(requestBody).enqueue(new Callback<Post>() {
#Override
public void onResponse(Call<Post> call, Response<Post> response)
{
Your APIService will thus look like
public interface APIService {
#POST("/verifications/signup/send")
#FormUrlEncoded
Call<Post> sendPhoneNumber(#Body RequestBody requestBody);
}
I have some troubles trying to execute this code:
#Override
public void loginProcessGoogle(User googleUser) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.callbackExecutor(Executors.newSingleThreadExecutor())
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestInterface requestInterface = retrofit.create(RequestInterface.class);
User user = new User();
String email = googleUser.getEmail() == null ? "" : googleUser.getEmail();
String name = googleUser.getName();
String googleId = googleUser.getProvider_id();
user.setEmail(email);
user.setName(name);
user.setProvider_id(googleId);
user.setProvider_name(User.provider_name_google);
ServerRequest request = new ServerRequest();
request.setUser(user);
Call<ServerResponse> response = requestInterface.socialAuthenticate(request);
response.enqueue(new Callback<ServerResponse>() {
#Override
public void onResponse(Call<ServerResponse> call, retrofit2.Response<ServerResponse> response) {
ServerResponse resp = response.body();
Snackbar.make(getView(), resp.getMessage(), Snackbar.LENGTH_LONG).show();
if(resp.getResult().equals(Constants.SUCCESS)){
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean(Constants.IS_LOGGED_IN,true);
editor.putString(Constants.EMAIL,resp.getUser().getEmail());
editor.putString(Constants.NAME,resp.getUser().getName());
editor.putString(Constants.ID,resp.getUser().getId());
editor.apply();
goToProfile();
}
progress.setVisibility(View.INVISIBLE);
}
#Override
public void onFailure(Call<ServerResponse> call, Throwable t) {
progress.setVisibility(View.INVISIBLE);
Log.d(Constants.TAG,"failed");
Snackbar.make(getView(), t.getLocalizedMessage(), Snackbar.LENGTH_LONG).show();
}
});
String testString= "Hello";
}
When im debuggin this code, i put a breakpoint for example in user.setEmail(email);,it enters, also with another before the response.enqueue callback, when im trying to put a breakpoint inside onResponse method, it goes immediately to the string variable in the bottom (testString)
What is the best way to enter first into the response.enqueue before the string variable in the bottom, for example in ServerResponse resp = response.body();?
You cannot, because the enqueue method run in another thread with the thread you setEmail, untill retrofit receive the result it execute onResponse method.
Yo can use excute method instead enque. See here for more details https://futurestud.io/tutorials/retrofit-synchronous-and-asynchronous-requests.