trying to make an android app that will communicate with a localhost server (tomcat apache) which use noSQL server (app->tomcat->noSQL). I already manage to make a servlet that handle params on "get" method and load them correctly to the database, now I am trying to insert the data from my app using retrofit2 lib.
following vids and tutorials I still couldnt manage to make this work.
this is the interface I am using:
public interface APIService {
#POST("login")
Call<Boolean> postUser(#Body User user);
#GET("login")
Call<Boolean> getUser(#Query("user_email") String user_email,#Query("user_pass") String user_pass);
public static final Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/")
.addConverterFactory(GsonConverterFactory.create())
.build();
}
and this is the code I am using when the button is clicked in the app:
APIService ApiService = APIService.retrofit.create(APIService.class);
User user = new User(name, email);
Call<Boolean> call = ApiService.getUser(email,name);
call.enqueue(new Callback<Boolean>() {
#Override
public void onResponse(Call<Boolean> call, Response<Boolean> response) {
String ans = response.message(); //for debugging
if (ans.compareTo("yes") == 0) {
Toast.makeText(getApplicationContext(), "YES!", Toast.LENGTH_SHORT).show();
} else if (ans.compareTo("no") == 0) {
Toast.makeText(getApplicationContext(), "NO!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "ELSE?!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<Boolean> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
so atm, nothing happen when I am clicking the button.(it used to crush but it stopped) and I am sure the the button's function is being called.
If you are using emulator, then change URL to http://10.0.2.2:8080/.
Two ways your problem can solved
If u are running with emulator use URL as http://10.0.2.2:8080/
instead of localhost
Running from mobile app use PC IP address
Related
I have build an App in Android Studio that can scan every type of code(like qr code, barcode ect.) and I want to store that Data inside MongoDB.
For that I build an Api with 2 routes post/get to post an item and get all items - tested it with Postman, and it works.
app.get('/items', async (req, res) => {
const collection = client.db('codes').collection('QR');
const items = await collection.find({}).toArray();
res.send(items);
});
app.post('/items', async (req, res) => {
const collection = client.db('codes').collection('QR');
const result = await collection.insertOne(req.body);
res.send(result);
});
My problem is, that it doesnt work when I call my method inside Android Studio
public interface API {
#FormUrlEncoded
#POST("/items")
Call<Void> sendData(
#Field("data") String data
);
}
public void addStuff(String data){
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("data", data);
} catch (JSONException e) {
e.printStackTrace();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:3000")
.addConverterFactory(ScalarsConverterFactory.create())
.build();
API api = retrofit.create(API.class);
Call<Void> call = api.sendData(jsonObject.toString());
call.enqueue(new Callback<Void>() {
#Override
public void onResponse(#NonNull Call<Void> call, #NonNull Response<Void> response) {
if (response.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Successfully added data to the Database", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Error getting data from the database" + response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(#NonNull Call<Void> call, #NonNull Throwable t) {
Toast.makeText(getApplicationContext(), "Failure", Toast.LENGTH_LONG).show();
}
});
}
After I scanned a code with my App, I get an dialog that asks me what to do next. One of those options is a Button "Add to Database", where I call the method above.
For Testing purpose I just hard coded an example String that gets passed to my method.
After that, I get the "Failure" Toast.
Tried to attach the debugger to the App, but that didnt really work out, at least Icouldnt figure where the error lies. I tried to to wrap the String into a JSONObject, and send it after I use the toString() Method on the provided data, and I tried to change the data type in the API Interface to JSONObject and send an actual JSONObject, instead of calling the onString() method on the data.
All of it results in failure.
I am working on an Android application and I am trying to consume an endpoint that takes in an image, saves it to Google Cloud Storage and returns a URL.
Question: I'm NOT new to working with endpoints but I don't know what image object to send (A Uri, a bitmap, a file, etc). Every format I use returns an Internal Server Error.
Here's the part of my user service interface responsible for making the request:
#POST("/add")
Call<PhotoUrlGetter> getUrlForPhoto(#Body Uri media);
Here's the part of my code where I'm actually making the request:
Uri media = ""; //the value is gotten from the image the user selected from gallery
UserService photoService = ServiceGeneratorForMedia.createService(UserService.class, "photoservice");
Call<PhotoUrlGetter> photoCall = photoService.getUrlForPhoto(media);
photoCall.enqueue(new Callback<PhotoUrlGetter>() {
#Override
public void onResponse(Call<PhotoUrlGetter> call, Response<PhotoUrlGetter> response) {
if(response.isSuccessful()){
Toast.makeText(getActivity().getApplicationContext(), response.body().getMediaUrl(), Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(getActivity().getApplicationContext(), Integer.toString(response.code()), Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<PhotoUrlGetter> call, Throwable t) {
Toast.makeText(getActivity().getApplicationContext(), "Failed", Toast.LENGTH_LONG).show();
}
});
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 make a call to an api using Retrofit GET request. This GET request requires a parameter. The API works perfectly when i use POSTMAN for testing but when i try to use the API call below it returns
Object reference not set to an instance of an object.
#GET("/api/account/*******")
Call<ResetPassword> requestPasswordResetToken(#Query("phoneNumber") String phoneNumber);
And the code how i make that request in my activity.
public void requestPasswordResetToken(String phoneNumber) {
Retrofit retrofit = RetrofitClient.getClient("");
APIService mAPIService = retrofit.create(APIService.class);
final ProgressDialog loading = ProgressDialog.show(this, "Please Wait", "Loading your information...", false, false);
loading.setCancelable(true);
loading.show();
mAPIService.requestPasswordResetToken(phoneNumber).enqueue(new Callback<ResetPassword>() {
#Override
public void onResponse(Response<ResetPassword> response, Retrofit retrofit) {
if(response.isSuccess()) {
String loginSuccess = response.body().getSuccess();
String message = response.body().getMessage();
if (loginSuccess.equals("true")) {
loading.dismiss();
showSnackMessage(message);
}else {
Log.e("loginError", message);
Toast.makeText(RequestPasswordResetActivity.this, message, Toast.LENGTH_LONG).show();
loading.dismiss();
}
}
}
#Override
public void onFailure(Throwable throwable) {
Log.e("ResetPasswordError", throwable.getMessage());
Toast.makeText(RequestPasswordResetActivity.this, "Unable to Login, Please Try Again", Toast.LENGTH_LONG).show();
loading.dismiss();
}
});
}
the screenshot of the what the API expects. The field names are correct.
Your codes looks fine. Do you check the result format of the api you are working on. And also ResetPassword class properties (variable names and types) must be same with response of the api. (be careful about upper case or lower case letters).
And also try this format request
#GET("methodName/{PARAMETER}")
Call<Object> getData(
#Path("telephoneNumber") String telephoneNumber
);
Make sure that you are calling correct method, you seem to call requestPasswordResetToken but you are showing resendVerification inside your interface.
I'm using com.squareup.retrofit2:retrofit:2.2.0
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(logging);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:9000")
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
final UserService service = retrofit.create(UserService.class);
Call<User> userCall = service.createUser(user)
Here is the problem: when I run the execute it make REST API request but when I use enqueue it does nothing (no exception, no log)
userCall.execute(); //this work
//this does not work
userCall.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
// no response
}
#Override
public void onFailure(Call<User> call, Throwable t) {
//nothing here
}
});
Well,
The issue was because I was using an emulator and try to call the localhost however, it turn out if you want call the localhost you have to use this ip 10.0.2.2
The execute works because I was running as unit test but when it runs enqueue I think it need to run on android platform.
refer to this
https://developer.android.com/studio/run/emulator.html#networkaddresses
How to get the Android Emulator's IP address?
You can try this full Answer Link
Here is the shortest code snippest.
private void emailLoginRequest() {
LoginService loginService = ApiFactory.createService(LoginService.class);
Call<JsonObject> call = loginService.login(edtEmail.getText().toString(),edtPassword.getText().toString(),mDeviceType,mDeviceToken);
call.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
hideProgressDialog();
if (response.isSuccessful()) {
LOGD(TAG, "onResponse 0: " + response.body().toString());
LoginResponse loginResponse = new Gson().fromJson(response.body().toString(), LoginResponse.class);
System.out.println("+++ get message >> " + loginResponse.getMessage());
int status = loginResponse.getStatus();
}else {
LOGD(TAG, "response fail 0: " + response.body());
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
hideProgressDialog();
LOGD(TAG, "onFailure: " + t.getMessage());
}
});
}
put your code as this:
userCall.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
Toast.makeText(this, "in response", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<User> call, Throwable t) {
Toast.makeText(this, "in response", Toast.LENGTH_SHORT).show();
}
});
Now based on method call you will get toast if its in response toast will be "In response" don't forget write youractivity name before this like : MainActivity.this
see this
retrofit can be called by 2 methods separately one is synchronous and another way is asynchronous.
enqueue is an asynchronous way where it does not wait for a response and proceed. here you need to handle Call separately to load UI later.
Execute is asynchronously call rest api and wait until get response and process it.
choice wisely