How to retrieve image from a JSON Response from API using retrofit - android

I'm getting a JSON response where it shows my image path but i can't just directly load the image from it's path using retrofit.
Here's the JSON Output sample:
{
"Emp_Photo": "/Images/2018_07_02_05_30_24.jpg",
}
I tried fetching and storing the value of Emp_Photo into a string and loaded the string into imageview using picasso but it doesn't work.
Here's some part of my code which i'm trying to accomplish:
final ProgressDialog progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Fetching Data...");
progressDialog.show();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiClient.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
Fetchemployeedetailsinterface service = retrofit.create(Fetchemployeedetailsinterface.class);
//Result is our pojo class
SharedPreferences settings = getActivity().getSharedPreferences("PREFS_NAME", 0);
String emailtoken= settings.getString("email", "").toString();
Call<ResponseData> call = service.Bind_Employee_Details_Based_On_Id(emailtoken);
call.enqueue(new Callback<ResponseData>() {
#Override
public void onResponse(Call<ResponseData> call, Response<ResponseData> response) {
//.getMessage is POJO method to listen for final json output
List<MessageItem> listResponse =response.body().getMessage();
String fname=listResponse.get(0).getEmpFirstName();
String lname=listResponse.get(0).getEmpLastName();
String email=listResponse.get(0).getEmpEmail();
String address=listResponse.get(0).getEmpAddress();
String joindt=listResponse.get(0).getJoiningDate();
String imgaddress=listResponse.get(0).getEmpPhoto();
Picasso.with(getActivity()).load(imgaddress).into(pick);
ettvname.setText(fname+"-"+lname);
etfname.setText(fname);
etlname.setText(lname);
etemail.setText(email);
etaddress.setText(address);
etjoindt.setText(joindt);
progressDialog.dismiss();
}
#Override
public void onFailure(Call<ResponseData> call, Throwable t) {
progressDialog.dismiss();
Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});

Your Emp_Photo is just the path of the image. You should convert it to a full URL, then load it with Picasso.
String imageUrl = YOUR_ROOT_IMAGE + imgaddress
Picasso.with(getActivity()).load(imageUrl).into(pick);
Other advice:
And you should apply some conventions to make your code easier to read.
service.Bind_Employee_Details_Based_On_Id() -> service.bindEmployeeDetailsBasedOnId()
Fetchemployeedetailsinterface -> FetchEmployeeDetailsInterface
...
And here:
List<MessageItem> listResponse =response.body().getMessage();
String fname=listResponse.get(0).getEmpFirstName();
You should check and make sure listResponse has at least 1 item to prevent your app crash at runtime.

As you have mentioned in your description you are getting the only path of the image. But, you are not getting the full path of your image. So, you should have to required fill path of your image from where you can fetch image and load in your image view easily. For that you have to follow below method:
String image = base_URL + imgaddress; //Here base URL means initial path of your image or server.
Picasso.with(getActivity()).load(imgaddress).into(pick);
Try to get base_URL in response or another way.

Related

Android Studio - Using retrofit2 to get info from restdb

I'm trying to use Retrofit2 to create a GET petition for my Android app. I have followed a tutorial on how to create the code and it worked with a webpage that did not need any authentication. Then I tried to adapt the same code to my needs, but I can't get it right. Either I get a 401 error or I get a 500 error.
I want to reach this URL: http://adaptai-eea8.restdb.io/rest/usuarios
So my baseurl is http://adaptai-eea8.restdb.io/.
This is my function, which is in the MainActivity:
private void find(String codigo){
String apikey = "9dc3afb8b6087192d5e9e50c5f2cb44927be5";
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://adaptai-eea8.restdb.io/")
.addConverterFactory(GsonConverterFactory.create()).build();
UsuarioAPI usuarioAPI = retrofit.create(UsuarioAPI.class);
Call<Usuario> call = usuarioAPI.find(codigo);
call.enqueue(new Callback<Usuario>() {
#Override
public void onResponse(Call<Usuario> call, Response<Usuario> response) {
try {
int a = 5;
if(response.isSuccessful()){
Usuario u = response.body();
textView.setText(u.getContra());
Log.d("Funciona", u.getContra());
}
}catch(Exception ex){
Toast.makeText(MainActivity.this, ex.getMessage(), Toast.LENGTH_SHORT);
}
}
#Override
public void onFailure(Call<Usuario> call, Throwable t) {
Toast.makeText(MainActivity.this, "Error de conexión", Toast.LENGTH_SHORT);
}
});
}
And this is the GET petition I am using:
#Headers({"User-Agent: my-restdb-app","Content-Type: application/x-www-form-urlencoded", "x-apikey: heregoestheapikey", "Accept: application/json", "cache-control: no-cache"})
//#FormUrlEncoded
#GET("rest/usuarios/")
//public Call<Usuario> find(#Query("nombre") String nombre);
Call<Usuario> find(#Query("nombre") String nombre);
There has to be something wrong with this code, and maybe it is related to sending the apikey as a header, i don't know. Can someone tell me where am I wrong? Thanks in advance.
If you want to pass the apiKey as header you need to pass it as a parameter like you can see in the docs
#Headers({"User-Agent: my-restdb-app","Content-Type: application/x-www-form-urlencoded", "Accept: application/json", "cache-control: no-cache"})
#GET("rest/usuarios/")
Call<Usuario> find(#Header("x-apikey") String apiKey, #Query("nombre") String nombre);
Additionally, are you sure about the rest of parameters? Like User-Agent being "my-restdb-app" and query param name being "nombre"

Display large amount of data(mostly text) in android app

I'm creating an android app and i have a relatively large amount of data (mostly in text form and as key->string pairs) that i want to display in my app.
The problem is i don't want to enter the data in my app's code,meaning feel each TextView manually with the associated data.i don't feel that to be right!
I want my app to read this data from a file(maybe a JSON?) and then associate each key-> string pair with the related TexView.
To be more clear, i need to read from a prepared text file and use that text inside my app, AND i want to do this offline,i dont want to use any webservic
How should i accomplish this? should i use a database or room?Then how should i feel the database manually without using insert codes inside the app?
Use Volley for JSON Parsing
private static final String url ="your url";
Create a method
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Please wait, while we load the data");
progressDialog.show();
*make a String or JSON request*
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
newurl, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("response", response.toString());
Log.i("updated Url",newurl);
progressDialog.dismiss();
*then move into the json and create JSON object or JSON Array to get their String values*
try {
JSONObject data = response.getJSONObject("data");
JSONArray onwardflights = data.getJSONArray("data_key");
for (int i = 0; i < onwardflights.length(); i++) {
JSONObject onwardFlightsChild = onwardflights.getJSONObject(i);
String arrival,deparutre,duration,flightno,grossamount,image,direct;
JSONObject object = onwardFlightsChild.getJSONObject("data_key");
Onwardflights onwardflights1 = new Onwardflights(
arrival = onwardFlightsChild.getString("data_key"),
deparutre = onwardFlightsChild.getString("data_key"),
duration = onwardFlightsChild.getString("data_key"),
flightno = onwardFlightsChild.getString("data_key"),
direct = onwardFlightsChild.getString("data_key"),
origin = onwardFlightsChild.getString("data_key"));
Log.i("Origin",origin);
Fare fare = new Fare(
grossamount = object.getString("data_key")
);
onwardflights1.setFare(fare);
suggestionmodel.add(onwardflights1);
}
*Create an instance of adapter and pass the parameters*
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(suggestionmodel,getApplicationContext());
recyclerView.setAdapter(recyclerAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("THIS", "Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
requestQueue.add(jsonObjReq);
}
You could simply use a JSON file. Now, the question is: How do you ship a JSON file with your app so that it's available at Runtime? You can use any of these methods:
Put it in the directory res/raw/ and read it using the Resources class (it has a openRawResource() method)
Put it in the assets/ directory and read it in using the AssetManager class (it has a open() method that returns an InputStream)
I hope this helps... Merry coding!

Retrofit / OkHttp3 400 Error Body Empty

I am using Retrofit 2 in my Android project. When I hit an API endpoint using a GET method and it returns a 400 level error I can see the error content when I use an HttpLoggingInterceptor, but when I get to the Retrofit OnResponse callback the error body's string is empty.
I can see that there is a body to the error, but I can't seem to pull that body when in the context of the Retrofit callback. Is there a way to ensure the body is accessible there?
Thanks,
Adam
Edit:
The response I see from the server is:
{"error":{"errorMessage":"For input string: \"000001280_713870281\"","httpStatus":400}}
I am trying to pull that response from the response via:
BaseResponse baseResponse = GsonHelper.getObject(BaseResponse.class, response.errorBody().string());
if (baseResponse != null && !TextUtils.isEmpty(baseResponse.getErrorMessage()))
error = baseResponse.getErrorMessage();
(GsonHelper is just a helper which passes the JSON string through GSON to pull the object of type BaseResponse)
The call to response.errorBody().string() results in an IOException: Content-Length and stream length disagree, but I see the content literally 2 lines above in Log Cat
I encountered the same problem before and I fixed it by using the code response.errorBody().string() only once. You'll receive the IOException if you are using it many times so it is advised to just use it as a one-shot stream just as the Documentation on ResponseBody says.
My suggestion is: convert the Stringified errorBody() into an Object immediately as the latter is what you're gonna be using on subsequent operations.
As it was mentioned, you need to use response.errorBody().string() only once. But there is a way to get the error body string more than once.
TL;DR Use the code below to get error body string from response more than once.
public static String getErrorBodyString(Response<?> response) throws IOException {
// Get a copy of error body's BufferedSource.
BufferedSource peekSource = response.errorBody().source().peek();
// Get the Charset, as in the original response().errorBody().string() implementation
MediaType contentType = response.errorBody().contentType(); //
Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
charset = Util.bomAwareCharset(peekSource, charset);
// Read string without consuming data from the original BufferedSource.
return peekSource.readString(charset);
}
Explanation:
This is based on the original response.errorBody().string() method implementation. It uses the copy of BufferedSource from peek() and returns the error body string without consuming it, so you can call it as many times as you need.
If you look at the response.errorBody().string() method implementation, you'll see this:
public final String string() throws IOException {
try (BufferedSource source = source()) {
Charset charset = Util.bomAwareCharset(source, charset());
return source.readString(charset);
}
}
source.readString(charset) consumes data of the error body's BufferedSource instance, that's why response.errorBody().string() returns an empty string on next calls.
To read from error body's BufferedSource without consuming it we can use peek(), which basically returns a copy of the original BufferedSource:
Returns a new BufferedSource that can read data from this
BufferedSource without consuming it.
you can use Gson to get errorBody as your desired model class:
val errorResponse: ErrorMessage? = Gson().fromJson(
response.errorBody()!!.charStream(),
object : TypeToken<ErrorMessage>() {}.type
)
First create an Error class like below:
public class ApiError {
#SerializedName("httpStatus")
private int statusCode;
#SerializedName("errorMessage")
private String message;
public ApiError() {
}
public ApiError(String message) {
this.message = message;
}
public ApiError(int statusCode, String message) {
this.statusCode = statusCode;
this.message = message;
}
public int status() {
return statusCode;
}
public String message() {
return message;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
}
Second you can create a Utils class to handle your error like below:
public final class ErrorUtils {
private ErrorUtils() {
}
public static ApiError parseApiError(Response<?> response) {
final Converter<ResponseBody, ApiError> converter =
YourApiProvider.getInstance().getRetrofit()
.responseBodyConverter(ApiError.class, new Annotation[0]);
ApiError error;
try {
error = converter.convert(response.errorBody());
} catch (IOException e) {
error = new ApiError(0, "Unknown error"
}
return error;
}
And finally handle your error like below:
if (response.isSuccessful()) {
// Your response is successfull
callback.onSuccess();
}
else {
callback.onFail(ErrorUtils.parseApiError(response));
}
I hope this'll help you. Good luck.
If you are gettig 400 then its a bad request you r trying to send to server.
check your get req.

Picasso image url lookup before load

So I'm currently investigating the possibility to replace a lot of custom image loading AsyncTasks in a project, with the Picasso library and it seems promising. However there is one issue that I'm not completely sure how to solve using Picasso.
In this case we are downloading Album Art for music tracks, however when our ListView is to be shown we only have the track ids. So first we have to lookup an Album Art URL based on the track id and then load it into an ImageView. Currently we have an AsyncTask where we in doInBackground() first lookup the image URL and then load a Bitmap from it, which is then pasted to onPostExecute.
Is there any way to make this pre-lookup using Picasso or will we have to wrap the Picasso call in a AsyncTask that first perform the lookup (and feels like it kinda defeats the purpose).
Update: How it works now:
private class AlbumArtTask extends AsyncTask<String, Bitmap, Bitmap> {
#Override
protected Bitmap doInBackground(String... strings) {
final String id = strings[0];
// This part is what I'm asking for, basically to be able to make an Async
// lookup of the url that will later be used by Picasso
final Uri uri = getAlbumArtUriFromTrackId(id);
// Creating the Bitmap and return it to be used in an ImageView
// This part is handled by Picasso
return bitmap = createBitmapFromUri(uri);
}
#Override
protected void onPostExecute(Bitmap bitmap) {
// load image into ImageView
}
}
Update 2: Made up example of what I'm after
Picasso.with(mContext)
.load(new UriProvider() {
// Get the actual image URI here
public Uri getImageUri() {
return getAlbumArtUriFromTrackId(id);
}
})
// And load it here
.into(mImageView);
I had to solve the same problem for my app. I used OkHTTP interceptor to redirect the request.
This is my picassa declaration:
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new PhotoInterceptor());
Picasso picasso = new Picasso.Builder(context)
.downloader(new OkHttpDownloader(client))
.build();
This is a basic implementation of the interceptor:
public class PhotoInterceptor implements Interceptor {
Gson gson = new Gson();
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
if (response.isSuccessful()) {
Photo photo = gson.fromJson(response.body().charStream(), Photo.class);
if (photo!=null) {
request = request.newBuilder()
.url(photo.getPhoto_file_url())
.build();
response = chain.proceed(request);
}
}
return response;
}
}
You have to load images from your Album Art URL using Piccaso while your listView is created. Then on Detail screen of Track you have to call your actual image url to set it in imageview.
Edited
private class AlbumArtTask extends AsyncTask<String, Bitmap, Uri> {
ImageView mImageView;
Context mContext;
public AlbumArtTask(Context context,ImageView imageView){
this.mImageView=imageView;
this.mContext=context;
}
#Override
protected Uri doInBackground(String... strings) {
final String id = strings[0];
// This part is what I'm asking for, basically to be able to make an Async
// lookup of the url that will later be used by Picasso
final Uri uri = getAlbumArtUriFromTrackId(id);
// Creating the Bitmap and return it to be used in an ImageView
// This part is handled by Picasso
return uri;
}
#Override
protected void onPostExecute(Uri uri) {
// You have to pass imageview in constructor.
// load image into ImageView
Picasso.with(mContext).load(uri)/* And load it here*/.into(mImageView);
}
}

JSON parsing not encoding string with underscore in Android using Volley

I am trying to encode a string which contains a URL, I have a strange issue where the complete string is not being returned, I have noticed that it may be related to the underscore, I have tried a few solution where I replace the underscore, but haven't had much luck with that solution. Below is the JSON.
[{"id":"1","source":"BBC WORLD NEWS",
"time_date":"Sat, 25 Oct 2014 10:49:13",
"title":"Iran hangs woman despite campaign","description":"Iran defies an international campaign and hangs a woman who killed a man she said was trying to sexually abuse her.",
"link":"http:\/\/www.bbc.co.uk\/news\/world-middle-east-29769468#sa-ns_mchannel=rss&ns_source=PublicRSS20-sa",
"image":"http:\/\/news.bbcimg.co.uk\/media\/images\/78529000\/jpg\/_78529517_78528720.jpg"},
I am trying to retrieve the image element from the json. The following is what I receive from my parsing.
http://news.bbcimg.co.uk/media/images/78526000/jpg
I am using this code at the moment:
String imageurl = feed.getImage();
try {
imageurl = URLDecoder.decode(imageurl, "UTF-8");
System.out.println("---------------------------"+imageurl);
imageurl.replace("_", "%5f");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
getimage method:
private String image;
public String getImage() {
return image;
}
private void requestNewsData(String uri) {
RestAdapter api = new RestAdapter.Builder().setEndpoint(ENDPOINT).build();
NewsAPI restapi = api.create(NewsAPI.class);
restapi.news(new Callback<List<RssObject>>() {
public void success(final List<RssObject> newsFeed, Response response) {
Log.v("nas", "the webservice success " + response.getReason());
for (int i = 0; i < newsFeed.size(); i++) {
System.out.println(newsFeed.get(i).description);
newsList.add(newsFeed.get(i).description);
FeederModel feed = new FeederModel();
feed.setSource(newsFeed.get(i).source);
feed.setImage(newsFeed.get(i).image); // adding setimage
}
}
The retrieved string is missing the final part of the url.
Any suggestion would be gratefully appreciated. Thanks.

Categories

Resources