I am using retrofit library for a web service that expect request as json and give response as json.
public class GitHubClient extends Activity{
private static final String API_URL = "http://10.0.0.32/test";
static class Contributor {
String login;
int contributions;
}
public static class Array {
public String id;
public String name;
}
class Contributor1 {
public Array array;
}
interface Login {
#POST("/testapp/")
Contributor1 mu(#Body User user,Callback<Contributor1> callBack);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new myasyncclass().execute();
}
public class User {
public String mail;
public String password;
}
public class myasyncclass extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
// Create a very simple REST adapter which points the GitHub API endpoint.
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer(API_URL)
.build();
Login login = restAdapter.create(Login.class);
User user=new User();
user.mail="ttete";
user.password="tett";
Contributor1 contributors = login.mu(user,new Callback<Contributor1>() {
#Override
public void failure(RetrofitError error) {
System.out.println("failure, error: " + error);
}
#Override
public void success(Contributor1 result, Response arg1) {
System.out.println("success, result: " + result);
}
});
return null;
}
}
}
This is my entire class .But i am getting the following error
Caused by: java.lang.IllegalArgumentException: Method mu may only have return type or Callback as last argument, not both.
What should i do overcome this error?
This interface definition is wrong as per the error.
interface Login {
#POST("/testapp/")
Contributor1 mu(#Body User user,Callback<Contributor1> callBack);
}
You should modify it to
interface Login {
#POST("/testapp/")
Contributor1 mu(#Body User user);
}
Since now it does not have a callback, you should be able to call it synchronously.
Related
I'm making requets to Google Books API with Retrofit2 and use GSON converter, but have an error
ErrorExpected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path
$
API URL to JSON
This is my
BookService.java
public class BookService{
private static final String BASE_URL = "https://www.googleapis.com/";
private BookApiService mApiService;
private BookCallback mListener;
public BookService(BookCallback listener){
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
mApiService = retrofit.create(BookApiService.class);
mListener = listener;
}
public void getBooks(String query){
final ApiResponse apiResponse = new ApiResponse();
Call<List<Book>> call = mApiService.getBooks(query);
call.enqueue(new Callback<List<Book>>() {
#Override
public void onResponse(Call<List<Book>> call, Response<List<Book>> response) {
apiResponse.setBooks(response.body());
mListener.notifyDataReceived(apiResponse);
}
#Override
public void onFailure(Call<List<Book>> call, Throwable t) {
apiResponse.setError(t);
mListener.notifyDataReceived(apiResponse);
}
});
}
public interface BookCallback{
void notifyDataReceived(ApiResponse apiResponse);
}
}
and my Interface
BookApiService.java
public interface BookApiService {
#GET("/books/v1/volumes")
Call<List<Book>> getBooks(#Query("q") String query);
}
Then making request from MainActivity.java that implements BookCallback
public class MainActivity extends AppCompatActivity implements BookService.BookCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main)
new BookService(this).getBooks("android");
}
}
Your response is not an array. its an object with array in it.
For fix this you must create other response class like BookResponse
BookResponse.java
public class BookResponse{
#SerializedName("kind")
private Sting kind;
#SerializedName("totalItems")
private Int totalItems;
#SerializedName("items")
private List<Book> items;
}
And change your interface like this
public interface BookApiService {
#GET("/books/v1/volumes")
Call<BookResponse> getBooks(#Query("q") String query);
}
The response you are having is not an array of Books, but it is an object, which perhaps is a response that has an array with books. So what the error says: Your JsonResponse is not starting with [] but is starting with {}
I have 3 classes: LogIn, LogicController and WebService.
LogIn is an Activity that, by pressing a button, executes a static LogicController method which, in turn, executes a static method in WebService. WebService makes a request to the server using JsonObjectRequest. I need that interaction to represent the MVC model (a school work requires it), and I could not do it without static methods, since I could not "serialize" LogicController to pass as a variable to LogIn.
The problem is that I can not get LogIn to wait for WebService to complete its work before continuing, and I need that to use a parameter returned by it.
LogIn class:
public class LogIn extends AppCompatActivity {
EditText txtUsr;
EditText txtPass;
Button btnLogIn;
#Override
protected void onCreate(Bundle savedInstanceState) {
txtUsr = (EditText) findViewById(R.id.txtUsr);
txtPass = (EditText) findViewById(R.id.txtPass);
btnLogIn = (Button) findViewById(R.id.btnIS);
btnLogIn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
logInWebService();
}
});
}
private void logInWebService() {
String usr = txtUsr.getText().toString();
String pass = txtPass.getText().toString();
boolean result;
result = LogicController.logInWebService(this, usr, pass);
if(result){
//doSomething in response to the result
//need to execute this after logInWebService is done
}
}
}
LogicController class:
public class LogicController extends AppCompatActivity {
private WebService myWebService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myWebService = new WebService(1);
}
public static boolean logInWebService(Context context, String usr, String pass){
boolean result = WebService.logInWebService(context, usr, pass);
return result;
}
}
WebService class:
public class WebService {
private static boolean result;
public WebService(int idGestor) {
this.idGestor = idGestor;
}
public static boolean logInWebService(Context context, final String usr, final String pass) {
String url = "https://webpage.myPhpWS.php?"+"idusr="+usr+"&pass="+pass;
result = false
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
if(someOperation){
result = true;
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println("Error"+error.getMessage());
}
});
RequestQueue request = Volley.newRequestQueue(context);
request.add(jsonObjectRequest);
return result; //this is the final result needed
}
}
I use nested classes since the WebService class makes several requests, and I must be able to handle them separately. I would prefer, if possible, not to add classes to this scheme.
I could not find a thread that touched on this specific topic.
Any help would be useful, even if I'm having a bad approach from the beginning.
Thanks for advance.
you can use a callback interface and pass it as a parameter to the LogicController.logInWebService(this, usr, pass,callback);.
1- create interface ResultCallback
interface ResultCallback {
void on success();
void onFailure();
}
2- pass it to the logInWebService
//show progress dialog before making the request
LogicController.logInWebService(this, usr, pass,new ResultCallback (){
#Override
public void onSuccess() {
//hide progress and show success message
}
#Override
public void onFailure() {
//hide progress and show error
}
}
);
3- then modify your method logInWebService()
public static boolean logInWebService(Context context, final String usr, final String pass,ResultCallback callback) {
String url = "https://webpage.myPhpWS.php?"+"idusr="+usr+"&pass="+pass;
result = false
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
callback.onSuccess(); //you can pass sth to this method
if(someOperation){
result = true;
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println("Error"+error.getMessage());
callback.onSuccess();
}
});
RequestQueue request = Volley.newRequestQueue(context);
request.add(jsonObjectRequest);
return result; //remove this and return void instead.
}
a better approach is to use Rxjava observables.
Ok , i had the same problem, i just solved it with ObservableInteger , just declare it
private ObservableInteger mObsInt;
then in onCreate setup a listener
//Listener
mObsInt = new ObservableInteger();
mObsInt.set(0);
mObsInt.setOnIntegerChangeListener(new OnIntegerChangeListener()
{
#Override
public void onIntegerChanged(int newValue)
{
if (mObsInt.get()==1)
Log.e("Downloads"," mObsInt 1");
Log.e("Download1"," Finished first process ");
if (mObsInt.get()==2){
Log.e("Downloads"," mObsInt 2");
Log.e("Download2"," Finished second process ");
mProgressDialog.dismiss();
Intent mainIntent = new Intent().setClass(LoginActivity.this, Principal.class);
startActivity(mainIntent);
finish();
}
}
});
and then just do this (after a process has finished)
mObsInt.set(mObsInt.get()+1);
so it will count, if the first thing finish obsInt will be 1 , and when the second one finish, obsInt will be 2, so after obsInt == 2 , you can move on to the other activity or process you need
happy coding !
I have an web api which gives me array of partners and it looks like this:
[
"partner1",
"partner2",
"partner3",
"....",
"parner222"
]
I have Table partners (ActiveAndroid) in which I would like to save all partners from api.
#Table(name = "Partners")
public class Partners extends Model {
#Column(name = "Name")
String name;
public Partners() {}
public Partners(String name) {
this.name = name;
}
}
Here is my Pojo model class:
public class Partners {
#SerializedName("name")
#Expose
private List<String> name = new ArrayList<String>();
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
This is my interface
public interface APIService {
#GET("Partners")
Call<Partners> getPartners();
}
And this is my APIHelper with api url
public class APIHelper {
public static APIService apiService;
public static APIService getApiService() {
if (apiService == null) {
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://part-oflink.domain.com/partners.json/")
.addConverterFactory(GsonConverterFactory.create()).build();
apiService = retrofit.create(APIService.class);
}
return apiService;
}
}
And this is Fragment where I have an Button on which I would like to implement onClick method to get data from API and save it into Partners table.
public class DownloadMain extends Fragment implements Callback<Partners> {
private Button dloadPartners;
private Call<Partners> callPartners;
public static APIService apiService;
public DownloadMain() {}
public DownloadMain newInstance() { return new DownloadMain(); }
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.download_main, container, false);
dloadPartners = (Button) view.findViewById(R.id.downloadPartners);
dloadPartners.setOnClickListener(btnListener);
callPartners = APIHelper.getApiService().getPartners();
callPartners.enqueue(this);
return view;
}
Button.OnClickListener btnListener = (new View.OnClickListener() {
#Override
public void onClick(View v) {
//here I need to implement that on click downloads me data
// and save it into my Partners table
}
});
#Override
public void onResponse(Call<Partners> call, Response<Partners> response) {
//here I'm trying to put api response into array list
if (response.body() != null) {
ArrayList<String> partnersList = new ArrayList<>();
partnersList = response.body();
}
}
#Override
public void onFailure(Call<Partners> call, Throwable t) {
}
}
And now I have stuck. I would like to implement onClick Button method to get data from API. In onResponse() method I'm trying to put data into ArrayList to check if data is recieved. And also I would like to save this data into my table partners.
I would be grateful if someone could help me or guide me to fix this. This is first time I'm doing with retrofit and api.
Can somebody help me or guide me to successfully get data from API and save it into table Partners?
The way you are trying to parse the JSON string(array of partners) is not the appropriate. Your JSON should like this:
{
"partners":
["partner1", "partner2", "partner3", ...]
}
And the POJO model class should be:
class Partners{
private List<String> partners;
public Partners(){}
public void setList(List<String> partners) {
this.partners = partners;
}
public List<String> getList() {
return this.partners;
}
//setter and getter methods
}
If the response is not empty then for printing the values:
for(Partner partner: response){
Log.d("Partner Name",partner.name);
}
And if you are using any ORM for the database, then call its DAO and pass the values to save in the DB.
I'm using RoboSpice with Google HTTP Client & GSON this way:
ApiSpiceService:
public class ApiSpiceService extends GoogleHttpClientSpiceService {
private static final int THREAD_COUNT = 3;
#Override
public CacheManager createCacheManager(Application application) throws CacheCreationException {
CacheManager cacheManager = new CacheManager();
GsonObjectPersisterFactory gsonObjectPersisterFactory = new GsonObjectPersisterFactory(application);
cacheManager.addPersister(gsonObjectPersisterFactory);
return cacheManager;
}
#Override
public int getThreadCount() {
return THREAD_COUNT;
}
}
Request:
public class InfoRequest extends GoogleHttpClientSpiceRequest<Contact> {
private final String url;
public InfoRequest() {
super(Contact.class);
this.url = "some-url/path.json";
}
#Override
public Contact loadDataFromNetwork() throws Exception {
HttpTransport httpTransport = new NetHttpTransport();
HttpRequestFactory httpRequestFactory = httpTransport.createRequestFactory(new InfoHttpRequestInitializer());
HttpRequest httpRequest = httpRequestFactory.buildGetRequest(new GenericUrl(url));
httpRequest.setParser(new GsonFactory().createJsonObjectParser());
return httpRequest.execute().parseAs(Contact.class);
}
private class InfoHttpRequestInitializer implements HttpRequestInitializer {
#Override
public void initialize(HttpRequest request) throws IOException {
}
}
}
Model (Contact.java):
public class Contact {
private String data;
}
BaseActivity:
public abstract class BaseActivity extends ActionBarActivity {
protected SpiceManager spiceManager = new SpiceManager(ApiSpiceService.class);
#Override
protected void onStart() {
super.onStart();
spiceManager.start(this);
}
#Override
protected void onStop() {
spiceManager.shouldStop();
super.onStop();
}
}
And MainActivity:
public class MainActivity extends BaseActivity {
private InfoRequest infoRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
infoRequest = new InfoRequest();
}
#Override
protected void onStart() {
super.onStart();
spiceManager.execute(infoRequest, "txt", DurationInMillis.ALWAYS_EXPIRED, new TextRequestListener());
}
private class TextRequestListener implements RequestListener<Contact> {
#Override
public void onRequestFailure(SpiceException spiceException) {
//
}
#Override
public void onRequestSuccess(Contact s) {
//
}
}
It seems to be valid code, but, unfortunately, when it finish the request execution, field data in returned Contact instance is null.
There are no errors in logcat.
The requested content is 100% valid JSON. Why it is not being parsed?
Ok, I've found the solution. I need to add #Key annotation to fields in model. It's strange, because pure Gson does not require this.
public class Contact {
#Key
private String data;
}
I've always been curious about implementing Retrofit in my applications to make simple POST and GET requests. However I have have problems wrapping my head around it. Today I decided to try to integrate it in my app but am having troubles. If you could have a look at my code that would be great. This is the error I'm getting
"Caused by: retrofit.RetrofitError: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2"
This is the api call if you want to try it out.
http://api.thebookofeveryone.com/social/makelove?phrase=love
I also know I'm not doing anything with the returned Image Object right now as I need to solve this problem first.
Thank you.
MainActivity
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
extraThread task = new extraThread();
task.execute();
}
public class extraThread extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
RetrofitInterface.getImageApiClient().getImage("love");
return null;
}
}
RetroFit Interface
public class RetrofitInterface {
private static ImageApiInterface sImageService;
public static ImageApiInterface getImageApiClient() {
if (sImageService == null) {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://api.thebookofeveryone.com")
.build();
sImageService = restAdapter.create(ImageApiInterface.class);
}
return sImageService;
}
public interface ImageApiInterface {
#GET("/social/makelove")
Image getImage(#Query("phrase") String phrase);
}
}
Image Class
public class Image {
boolean success;
String url;
}
It's a JSON parsing error. Change you Image class to:
public class Image {
private Boolean success;
private String url;
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Or:
public class Image {
Boolean success;
String url;
}
Everything should work fine.
To create a POJO from JSON or JSON-Schema, I recommend http://www.jsonschema2pojo.org/. It's really helpful.