Fetching Simple JSON String Array using Retrofit - android

I want to fetch JSON string array from server using Retrofit.
The JSON array is like this.
["A","B","C"]
Here is the code I made .
MainActivity.class
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String url="http://proverbs-app.antjan.us";
RestAdapter restAdapter;
restAdapter = new RestAdapter.Builder()
.setEndpoint(url)
.build();
Service service=restAdapter.create(Service.class);
service.get(new Callback<List<String>>(){
#Override
public void failure(RetrofitError error) {
Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_LONG).show();
}
#Override
public void success(List<String> arg0, Response arg1) {
Toast.makeText(getApplicationContext(), arg0.toString(), Toast.LENGTH_LONG).show();
}
});
}
}
Here is the Service.class
public interface Service {
#GET("/")
public void get(Callback<List<String>> callback);
}
It shows only "Error" Toast.
Am I something wrong with my codes.
Please help me to fix it.
I'm a beginner.
So,please answer me in detail because I don't know much about it.
Thanks in advance.

You need to specify relative path for URL in the interface.
#GET("/")
public void get(Callback<List<String>> callback);

It looks like you're missing Gson. Add this line to your dependencies block in build.gradle:
compile 'com.google.code.gson:gson:2.3.1'

Related

response.body() result changes during execution. (retrofit2-get method)

I'm a beginner learning Android.
I'm trying to make my application receive data from local database.
So I used retroit2 as followed
public class SNSDataServicer {
private String BASE_URL = "http://10.0.2.2:8080/";
Retrofit retrofitClient =
new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
SelectAPI select = retrofitClient.create(SelectAPI.class);
InsertAPI insert = retrofitClient.create(InsertAPI.class);
UpdateAPI update = retrofitClient.create(UpdateAPI.class);
DeleteAPI delete = retrofitClient.create(DeleteAPI.class);
}
interface SelectAPI{
#GET("sns/all/{candidate}")
Call<List<SNSData>> selectAllByCandidate(#Path("candidate") String candidate);
}
and this is the code for MainActivity.java
public class MainActivity extends AppCompatActivity {
SNSDataServicer dataService = new SNSDataServicer();
List<SNSData> snsDataList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView checker = findViewById(R.id.checker);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dataService.select.selectAllByCandidate("3").enqueue(new Callback<List<SNSData>>() {
#Override
public void onResponse(Call<List<SNSData>> call, Response<List<SNSData>> response) {
snsDataList = response.body();
return;
}
#Override
public void onFailure(Call<List<SNSData>> call, Throwable t) {
t.printStackTrace();
Toast.makeText(getApplicationContext(), "Fail", Toast.LENGTH_LONG).show();
Log.d("Failure", "onResponse: Failed");
}
});
if(snsDataList==null) {
checker.setText("null");
} else {
checker.setText(snsDataList.get(0).getMedia());
}
}
});
}
}
When I press button, the textview's text should be set to size of the list.
But snsDataList kept on returning null
eventhough reponse.body() returned list successfully
below is scree capture of my debugging.
1.
enter image description here
by this point it was perfect, but when I hit F8 to debug next step
enter image description here
response body has been changed and when I hit F8 more, it takes me to
ExecutorCallAdapterFactory.java
Handler.class
Looper.class
and no more.
Then suddenly my snsDataList becomes null...
This is ridiculously hard for me and I've tried to solve it by myself for very long but I have failed...
Can someone help me with this problem? It will be really grateful.

get value of a variable “outside” of a callback in android

There is a String message as a parameter in an interface method:
public class Home extends AppCompatActivity {
private String globalStringResult = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
getMediaInfo();
Log.d("Result: ", globalStringResult); // Here result is Null
}//TODO OnCreate End
private void getMediaInfo() {
FFmpeg.getInstance(this).execute(new String[]{"-version"},
new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
globalStringResult = message;
}
});
}
}
Here is this problem that I've faced many times but always ran from it. Now I want to deal with it if you help me.
I am executing getMediaInfo() method inside onCreate. When I log the result inside onCreate after getMediaInfo() execution , the result would be null. But if I run it inside an onClick button or something I get my desired result.
Is there any way that I could return callback message anywhere that I want?
Sounds like your function getMediaInfo is asynchronous which means it could take some time before the onSuccess block is called and your value is set. Instead of relying on a variable I would suggest to use a callback function. That way your message will be passed to the callback function and you could use it anywhere.
public interface MyCallback{
void success(String message);
}
Then you would need to modify your function as follows. Then where ever the callback is implemented you will receive the message and you can act on the value.
public void getMediaInfo(MyCallback callback){
FFmpeg.getInstance(this).execute(cmdArray, new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
callback.success(message);
}
});
If your further actions depend on the value set in onSuccess callback then simply call a function from this callback method. You need to provide more info on what exactly you are trying to do with this variable.
Asynchronous calls can be tricky but you have to wait until it is finished before the variable is available. This means calling any methods that rely on the variable in the callback of the async call. There's really no way around it. You may want to make two version of the call; one for onCreate and one when you need to call it from other places.
public class Home extends AppCompatActivity {
private String globalStringResult = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
getMediaInfoOnCreate();
// move any code below this line into the new method
}//TODO OnCreate End
private void getMediaInfo() {
FFmpeg.getInstance(this).execute(new String[]{"-version"},
new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
globalStringResult = message;
codeThatNeedsToBeRunDuringOnCreateButAfterSettingGlobalStringResult();
}
});
}
private void getMediaInfoOnCreate() {
FFmpeg.getInstance(this).execute(new String[]{"-version"},
new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
globalStringResult = message;
}
});
}
private void codeThatNeedsToBeRunDuringOnCreateButAfterSettingGlobalStringResult() {
// put your moved code from onCreate here
Log.d("Result: ", globalStringResult); // Here correct result will be logged
}
}

How to wait until a HTTP request has a response before sending next

I have to send some things from the database to the server. So, I call a db method, and get a cursor, which has many positions. I need to send a httprequest for avery position of the cursor, but only send the second petition when the first has been received in the server, and the proper answer sent. I have this code:
final Cursor cursor = db.getData();
Thread thread=new Thread(new Runnable() {
#Override
public void run() {
if(cursorContadores.moveToFirst()){
do{
Call<String> peticion = interfaz.saveToServer(cursor.getString(1), cursor.getString(2));
peticion.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response, Retrofit retrofit) {
if(response.message().equals("ok")){
}else{
}
}
#Override
public void onFailure(Throwable t) {
}
});
}while (cursorContadores.moveToNext());
cursorContadores.close();
db.close();
}
}
});
thread.start();
This way, I think it will not wait until every iteration in the do while block ends, to start the next iteration.
How could I achieve this? Something I could read to learn how to?
Thank you.
In your Http response, you can check for response code.
For example if the response is 200 for successful receive, you can do something like:
HTTPResponse response;
if(response.getStatusLine().getStatusCode()==200){
//SEND NEXT
}
This way you can send the next request once the previous one is received.
I hope I understood the question correctly.
Thank you.
This can most definitely be done AsyncTask... Handle the network request in doInBackground() and once doInBackground() is finished, onPostExecute() is triggered on the response and that's where you can execute any code that send the second petition.
If you need something a bit more generic and re-usable, you would probably want to implement a callback.. I'll refer to the next step as the client and the AsyncTask as the server.
Create a new interface and create some method stubs.
public interface MyEventListener {
public void onEventCompleted();
public void onEventFailed();
}
Have your client pass instance of MyEventListener to the server. A typical way of doing this is to have your client implement the interface (MyEventListener) and pass itself to the server.
public class MyActivity implement MyEventListener {
public void startEvent() {
new MyAsyncTask(this).execute();
}
#Override
public void onEventCompleted() {
// TODO
}
#Override
public void onEventFailed() {
// TODO
}
}
On the onPostExecute of the server, check if the callback is null and call the appropriate method.
public class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private MyEventListener callback;
public MyAsyncTask(MyEventListener cb) {
callback = cb;
}
[...]
#Override
protected void onPostExecute(Void aVoid) {
if(callback != null) {
callback.onEventCompleted();
}
}
}
Check similar reference
learn more reference

How to handle nested json objects/arrays in android using retrofit and gson?

This is my json object structure:
object {1}
products [3]
0 {14}
1 {14}
2 {14}
and here is my code:
gitapi.java
public interface gitapi {
#GET("/admin/API/{user}")
public void getFeed(#Path("user") String user, Callback<gitmodel> response);
}
MainActivity.java
Button click;
TextView tv;
EditText edit_user;
ProgressBar pbar;
String API = "http://xxyyzz.com"; //BASE URL
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
click = (Button) findViewById(R.id.button);
tv = (TextView) findViewById(R.id.tv);
edit_user = (EditText) findViewById(R.id.edit);
pbar = (ProgressBar) findViewById(R.id.pb);
pbar.setVisibility(View.INVISIBLE);
click.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String user = edit_user.getText().toString();
pbar.setVisibility(View.VISIBLE);
//Retrofit section start from here...
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(API).build(); //create an adapter for retrofit with base url
gitapi git = restAdapter.create(gitapi.class); //creating a service for adapter with our GET class
//Now ,we need to call for response
//Retrofit using gson for JSON-POJO conversion
git.getFeed(user, new Callback<gitmodel>() {
#Override
public void success(gitmodel gitmodel, Response response) {
//we get json object from github server to our POJO or model class
tv.setText("getTitle :" + gitmodel.getTitle());
pbar.setVisibility(View.INVISIBLE); //disable progressbar
}
#Override
public void failure(RetrofitError error) {
tv.setText(error.getMessage());
pbar.setVisibility(View.INVISIBLE); //disable progressbar
}
});
}
});
}
The problem is I dont know how to access the inner json objects. Is there a way to do this.
from jsonschemaa2pojo.com i got the pojo file as 2 files one for gitmodel.java and other for product.java. My Question is how can i access the objects within the json object.
Ex: you can see the tv.setText("getTitle :" + gitmodel.getTitle()); in MainActivity.java which is what i want to achieve. i want to call the methods in order to access the inner object.
Thank you...
You have to create POJO using this link : http://www.jsonschema2pojo.org/
In this link select Source type: JSON and Annotation style: GSON and after that click on preview it will create pojo as per your Json and you will easily parse json.

App crash when I submit a new post to Parse

This is the only Place my app crashes and one of the more important features
The LogCat tells me:
java.lang.IllegalArgumentException: You must create this type of ParseObject using ParseObject.create() or the proper subclass.
at line 37.
I tried the ParseObject.create() however that just caused more problems (I may have done it incorrectly). How Should I code this?
Here is my newPost class:
public class newPost extends Activity {
private Button addButton;
private TextView postView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newpost);
postView = ((EditText) findViewById(R.id.postView));
addButton = ((Button) findViewById(R.id.addButton));
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//line 37 Below
ParseObject post = new ParseObject("Posts");
post.put("content", postView);
post.saveInBackground(new SaveCallback () {
#Override
public void done(ParseException e) {
if (e == null) {
setResult(RESULT_OK);
finish();
} else {
Toast.makeText(getApplicationContext(),
"Error saving: " + e.getMessage(),
Toast.LENGTH_SHORT)
.show();
}
}
});
}
});
}
Replace this line
ParseObject post = new ParseObject("Posts");
with this
ParseObject post = ParseObject.create("Posts");
Ensure that you've added the below line in the Application.java class where Parse is initialised
ParseObject.registerSubclass(Message.class);
In my case I had to remove the '#ParseClassName' annotation in my model class. My understanding is that if I have a parse model class 'Posts' and I call 'registerSubclass(yourclassname)' in Application, then all I need is
Post obj = new Post();
You probably made a mistake in initialising Parse in your Application class. Or forgot to put android:name=".YourApplicationClass" in your Manifest file.
I got this error because I forgot to register my parse class as a subclass in my application extension:
public class App extends Application
{
#Override
public void onCreate()
{
super.onCreate();
App application = this;
ParseObject.registerSubclass(Posts.class); // <-- This is what you need
Parse.enableLocalDatastore(this);
Parse.initialize(new Parse.Configuration.Builder(getApplicationContext())
.applicationId(EnvironmentConfig.appID)
.server(EnvironmentConfig.serverName)
.enableLocalDataStore()
.build());
ParseInstallation.getCurrentInstallation().saveInBackground();
}
}

Categories

Resources