Updating class field from callback - java

I'm trying to connect to API using Retrofit. I need to login user and after this set "user" field which contains session key which is required to all other api calls. So I need to have it available before executing any code but I don't know how to check or block code until this field will be set. Any ideas how to do it?
public class ApiClient {
public static final String developerKey = "";
public static final String applicationKey = "";
static final String BASE_URL =
"https://secure.techfortesco.com/tescolabsapi";
public ApiService mApiService;
public User user;
public ApiClient() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel( RestAdapter.LogLevel.FULL )
.setEndpoint( BASE_URL )
.build();
if(mApiService == null) {
mApiService = restAdapter.create( ApiService.class );
}
}
public void login() {
mApiService.login( developerKey, applicationKey, new Callback<User>() {
#Override
public void success ( User user, Response response ) {
//code which should update user field
}
#Override
public void failure ( RetrofitError error ) {
}
} );
}
public interface ApiService {
#GET ("/restservice.aspx?command=LOGIN&email=&password=")
public void login (
#Query ("developerkey") String developerKey,
#Query ("applicationkey") String applicationKey,
Callback<User> callback );
#GET ("/restservice.aspx?command=PRODUCTSEARCH")
public void search (
#Query ("searchtext") String searchText,
#Query ("sessionkey") String sessionKey,
Callback<Pojo.SearchResult> callback);
}
}

You can try using callback:
Example:
public interface LoginCallback {
void ready();
}
And in the Activity / Fragment
public MainActivity extends Activity {
public void onCreate() {
super.onCreate();
ApiClient client = new ApiClient();
client.login(new LoginCallback() {
#Override
public void ready() {
//... do your next request in the API.
}
});
}
}
and your login method became:
public void login(final LoginCallback loginCallback) {
mApiService.login( developerKey, applicationKey, new Callback<User>() {
#Override
public void success ( User user, Response response ) {
//code which should update user field
loginCallback.ready();
}
#Override
public void failure ( RetrofitError error ) {
}
} );
}

Related

How to solve E/error: End of input at line 1 column 1 path $ in android studio

When I try to call rest API in the android studio I get an error that:
E/error: End of input at line 1 column 1 path $
I use firebase for the database and retrofit2 library.
But when I call the values a go to the firebase database and call the onFailure in call.enqueue() method.
public class APis {
public static final String URL = "http://192.168.178.43:8081/api/";
public static userService setuser() {
return client.getClient(URL).create(userService.class);
}
}
public interface userService {
#Headers("Content-Type: application/json")
#POST("signup")
Call<userlog> adduser(#Body userlog userlog);
}
public class userlog {
#SerializedName("email")
#Expose
private String emial_;
#SerializedName("password")
#Expose
private String password_;
#SerializedName("name")
#Expose
private String name_;
public userlog() {
}
public userlog(String emial_, String password, String name_) {
this.emial_ = emial_;
this.password_ = password;
this.name_ = name_;
}
public String getEmial_() {
return emial_;
}
public void setEmial_(String emial_) {
this.emial_ = emial_;
}
public String getPassword_() {
return password_;
}
public void setPassword_(String password_) {
this.password_ = password_;
}
public String getName_() {
return name_;
}
public void setName_(String name_) {
this.name_ = name_;
}
}
public void setPassword_(String password_) {
this.password_ = password_;
}
}
private void adduser_(userlog userll) {
service = APis.setuser();
Call<userlog> call = service.adduser(userll);
call.enqueue(new Callback<userlog>() {
#Override
public void onResponse(Call<userlog> call, Response<userlog> response) {
if (response.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT).show();
/* userdetails.setUserid(firebaseAuth.getUid());
userdetails.setEmail_(emailId.getText().toString());
startActivity(new Intent(SignupActivity.this, MainnewActivity.class));*/
}
}
#Override
public void onFailure(Call<userlog> call, Throwable t) {
Log.e("error", t.getMessage());
Toast.makeText(getApplicationContext(), "not Successdd", Toast.LENGTH_SHORT).show();
}
});
}
when I call "adduser_(userll)" method, I get a notification that "not Successdd".
The problem related to retrofit, i think the problem because the response of the call come as null or empty
you can create NullConverterFactory.class :
public class NullConverterFactory extends Converter.Factory {
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return new Converter<ResponseBody, Object>() {
#Override
public Object convert(ResponseBody body) throws IOException {
if (body.contentLength() == 0) return null;
return delegate.convert(body);
}
};
}
}
and add to the create of the retrofit
baseUrl(Config.URL+"/")
.client(okHttpClient)
// -----add here-------
.addConverterFactory(new NullConverterFactory())
//---------------------
.addConverterFactory(GsonConverterFactory.create())
.build()

How to parse json with retrofit on Android

I try to write app which parse decoding of abbreviations and frequency of their use. User input abbreviation, for example "kg". So, app should connect to "http://nactem.ac.uk/software/acromine/dictionary.py?sf=kg" and parse it.
What should model classes look like? Did I describe #Geth correctly in the interface? How can I get the list, I made an adapter, bind it to the list, but I'm not sure about getResponse ().
Interface:
public interface SService {
#GET("dictionary.py?")
Call<Example> getResponse(#Query("sf=") String searchString);
}
Retrofit client:
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
And addition class ApiUtils
public class ApiUtils {
public static final String BASE_URL = "http://nactem.ac.uk/software/acromine/";
public static SService getSOService() {
return RetrofitClient.getClient(BASE_URL).create(SService.class);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private ArrayList<Lf> elements = new ArrayList();
EditText editText1;
ElementAdapter stateAdapter;
ListView list;
private SService mService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText1 = (EditText) findViewById(R.id.edit_text);
mService = ApiUtils.getSOService();
list = (ListView) findViewById(R.id.fragment_list);
stateAdapter = new ElementAdapter(this, R.layout.list_item, elements);
list.setAdapter(stateAdapter);
}
public void loadAnswers() {
mService.getResponse(editText1.getText().toString()).enqueue(new Callback<Example>() {
#Override
public void onResponse(Call<Example> call, Response<Example> response) {
if(response.isSuccessful()) {
stateAdapter.updateAnswers(response.body().getLfs());
} else {
int statusCode = response.code();
// handle request errors depending on status code
}
}
#Override
public void onFailure(Call<Example> call, Throwable t) {
}
});
}
public void activity_button(View view) {
//stateAdapter.clear();
loadAnswers();
}
}
UPD!!
All input data is an array: Array[Object{...}]. Right interface for parsing it:
public interface SService {
#GET("dictionary.py")
Call<List<Example>> getResponse(#Query("sf") String searchString);
}
So, we get with Call List with Example object (Only one object in this case).
Change the SService interface to the following,
public interface SService {
#GET("dictionary.py")
Call<Example> getResponse(#Query("sf") String searchString);
}

How to solve Retrofit2 interface null pointer

i try to connect my server and i stuck here about 3 hours. Simply use this in another project but... anyway here is my interface and service generator. Please help me...
ServiceGenerator
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ServiceGenerator {
private ServiceInterface serviceInterface;
private String BASE_URL = "http://xxxxxxxxx.com/xxxxx/xxx/";
public ServiceInterface init() {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
serviceInterface = retrofit.create(ServiceInterface.class);
return serviceInterface;
}
public ServiceInterface getServiceInterface() {
return serviceInterface;
}
}
SevrviceInterface
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface ServiceInterface {
#GET("login.php")
Call<LoginResponse> login(#Query("UserName") String id,
#Query("Password") String pass,
#Query("token") String token
);
}
xxxxxxApp
import android.app.Application;
import com.xxxxxxxxxxxxx.network.ServiceGenerator;
import com.xxxxxxxxxxxxx.network.ServiceInterface;
public class xxxxxxApp extends Application {
private static xxxxxxApp instance;
private ServiceGenerator serviceGenerator = new ServiceGenerator();
public static xxxxxxApp getInstance() {
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
serviceGenerator.init();
}
public ServiceInterface getServiceInterface() {
return serviceGenerator.getServiceInterface();
}
}
LoginAct.java
public class LoginAct extends BaseActivity {
SharedPreferences preferences;
Button btn_login;
EditText edt_username;
EditText edt_pass;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_login);
btn_login = findViewById(R.id.login_btn_login);
edt_username = findViewById(R.id.lgn_et_username);
edt_pass = findViewById(R.id.lgn_et_pass);
btn_login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
xxxxxxApp.getInstance().getServiceInterface().login(edt_username.getText().toString(),edt_pass.getText().toString(),"").enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if (response.isSuccessful()){
LoginAct.super.showToast(LoginAct.this," UserID : "+response.body().getUsers().get(0).getUser_ıd());
}
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
}
});
}
}
And if you cath my url doesn't have SSL its http:// . My error says :
java.lang.NullPointerException: Attempt to invoke virtual method 'com.xxxxxxxxxxxxxxxx.network.ServiceInterface com.xxxxxxxxxxxxxxxx.xxxxxxApp.getServiceInterface()' on a null object reference
at com.xxxxxxxxxxxxxxxx.ui.LoginAct$1.onClick(LoginAct.java:40)
I can't figure out how to solve this i try everything i can. please help.
.
.
.
.
.
.
.
.
Set your base url into
private String BASE_URL = "http://xxxxxxxxx.com/xxxxx";
and interface into
#GET("/xxx/login.php")
Call<LoginResponse> login(#Query("UserName") String id,
#Query("Password") String pass,
#Query("token") String token
);

How to write retrofit function for the following

How can I write a retrofit function to receive the following api call. I have only called retrofit functions where we pass parameters directly in params and not in body form-data so I don't know how to do this.
Although it's not right at all, This is what I have tried :
This is my mainActivity-
private void login(String username, String password) {
Call<User> call = student_signin.apiInterface.studentLogin("json",username, password);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.body().getError_code() == "401") {
Toast.makeText(student_signin.this, response.body().getError_message(), Toast.LENGTH_SHORT).show();
} else if (!response.body().getU_id().isEmpty()){
Toast.makeText(student_signin.this, "user signed in successfully", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<User> call, Throwable t) {
Toast.makeText(student_signin.this,t.getMessage(),Toast.LENGTH_LONG).show();
}
});
}
This is my APIinterface class-
public interface APIinterface {
#FormUrlEncoded
#POST("login")
Call<User> studentLogin(#Query("format") String format, #Field("username") String username, #Field("password") String password);
}
This is my APIclient class-
public class APIclient {
public static final String BASE_URL = "https://www.example.com/api/xyz/";
public static Retrofit retrofit = null;
public static Retrofit getApiClient()
{
if(retrofit==null)
{
// Gson gson = new GsonBuilder().setLenient().create();
retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}
}
And this is my model class-
public class User {
#Expose
#SerializedName("u_id")
private String u_id;
#Expose
#SerializedName("customer_id")
private String customer_id;
#Expose
#SerializedName("error_code")
private String error_code;
public String getU_id() {
return u_id;
}
public String getCustomer_id() {
return customer_id;
}
public String getError_code() {
return error_code;
}
}
Any help would be greatly appreciated and acknowledged.
#POST("/api/xyz/login")
fun getData(#Body params: JsonObject): JsonObject
client.getData(JsonObject().apply {
addProperty("advice_id", adviceId)
addProperty("content", content)
})
you can use this method to send the user name and password as pram in method getData() and revice the json as user list
#GET("/api/xyz/login")
Call<List<User>> getData(#Query("user_name") String userName,#Query("password") String password);

Passing information from interceptor to controller method

I am Using Play 2.3 (Java).
I have a onRequest method inside my Global.java file.
Following some answers on Stackoverflow and other resources, my Global.java is like -
private static ArrayList<String> admin_users = new ArrayList<String>();
public static ArrayList<String> getAdmin_users() {
return admin_users;
}
public static void setAdmin_users(ArrayList<String> admin_users) {
Global.admin_users = admin_users;
}
#Override
public void onStart(play.Application arg0) {
ArrayList<String> admins = new ArrayList<String>();
admins.add("aahuja");
admins.add("chlr");
admins.add("bobba");
setAdmin_users(admins);
}
private static ArrayList<String> admin_users = new ArrayList<String>();
public static ArrayList<String> getAdmin_users() {
return admin_users;
}
public static void setAdmin_users(ArrayList<String> admin_users) {
Global.admin_users = admin_users;
}
#Override
public void onStart(play.Application arg0) {
ArrayList<String> admins = new ArrayList<String>();
admins.add("aahuja");
admins.add("chlr");
admins.add("bobba");
setAdmin_users(admins);
}
private class ActionWrapper extends Action.Simple {
private String user;
public ActionWrapper(Action<?> action, String user) {
this.delegate = action;
this.user = user;
}
#Override
public Promise<Result> call(Http.Context ctx) throws java.lang.Throwable {
Promise<Result> result = this.delegate.call(ctx);
ctx.args.put("Name", this.user);
}
#Override
public Action<?> onRequest(Http.Request request, java.lang.reflect.Method actionMethod) {
if(request.getHeader("OriginalName") != null){
if(getAdmin_users().contains(request.getHeader("OriginalName"))){
if(request.hasHeader("IMPERSONATE") && request.getHeader("IMPERSONATE").equals("true")){
return new ActionWrapper(super.onRequest(request, actionMethod), request.getHeader("IMPERSONATE-IDENTITY"));
}
}
return new ActionWrapper(super.onRequest(request, actionMethod), request.getHeader("OriginalName"));
}
else
return super.onRequest(request, actionMethod);
}
Now, inside my controller file, I have a method like this -
public static Promise<Result> all() {
String name = (String) ctx().args.get("Name");
System.out.println(name);
// rest of code
}
Now when I pass a request to this application with the header information like -
OriginalName: abcd, I get a value of null inside my controller printed out.
Is ctx the correct way to pass data? If not whats the correct way.
I am trying to take the redundant logic out of the main business logic.
The same can also be achieved if we are able to modify the header information when it gets passed from the interceptor to the controller. But I cant find any suitable way of doing so.
Try to put the ctx.args.put() before calling the delegate:
#Override
public Promise<Result> call(Http.Context ctx) throws java.lang.Throwable {
ctx.args.put("Name", this.user);
Promise<Result> result = this.delegate.call(ctx);
}
You are setting the value afther your action run. So you cannot access the value inside your action.

Categories

Resources