I'm using archictecture Android Architecture Components. I want to load an image from my api.
this is the request on postman :
!https://ibb.co/WPJjpFm
I' am actually using retrofit but i don't known how to transform Responsebody to file.
#GET("image/{filename}")
Call<ResponseBody> getImage(#Path("filename") String filename);
public MutableLiveData<File> retriveImageTest(String filename) {
MutableLiveData data = new MutableLiveData<>();
executor.execute(() -> {
imageWebService.getImage(filename).enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
// How to deal with responsebody ?
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
});
return data;
}
What' s the best way to do it without breaking Android Architecture Components ?
Thanks in advance.
It is better to use Image loading libraries like Glide ,Picasso or Fresco to load images:
Using Glide, add this to your app gradle file
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
Then ,
Glide.with(this).load(imageUrl).into(imageView);
For more info : Glide docs
Related
learner here and I'm trying to add a retry button for whenever there is an error in Retrofit Callback#onFailure method.
Somewhat following the Android Architecture Guide, I'm able to call, persist the data and show it on RecyclerView. Here is a general flow of what I've done so far:
On PagedList.BoundaryCallback I'm getting the response and saving it. Here I've also created a LiveData of NetworkState, which I'm observing within MainActivity through ViewModel class.
#Override
public void onZeroItemsLoaded() {
if (isFetchNeeded())
mClient.fetchFirstNetworkCall().enqueue(getRetrofitCallback());
}
#Override
public void onItemAtEndLoaded(#NonNull Item itemAtEnd) {
if (mNextPageToken != null)
mClient.fetchNextNetworkCall(mNextPageToken).enqueue(getRetrofitCallback());
}
#Override
public void onResponse(#NonNull Call<BloggerApi> call, #NonNull Response<BloggerApi> response) {
mObservableNetwork.setValue(NetworkState.LOADING);
if (response.isSuccessful()) {
mExecutors.diskIO().execute(() -> {
insertItemsToDb(responseBody.getItems());
mObservableNetwork.postValue(NetworkState.SUCCESS);
});
} else {
String error = response.errorBody() == null ? "Unknown Error" : String.valueOf(response.errorBody());
mObservableNetwork.setValue(NetworkState.error(error));
}
}
#Override
public void onFailure(#NonNull Call<BloggerApi> call, #NonNull Throwable t) {
mObservableNetwork.setValue(NetworkState.error(t.getMessage()));
}
And then on UI:
mViewModel.getNetworkState().observe(this, networkState -> {
if (networkState.getStatus() == Status.ERROR) {
retryButton.setOnClickListener(view -> {
// todo: Implement what to do
});
}
});
I'm lost here and don't know how implement a Retry button to make the last call if for some reason I get an error. Can you please help me out about what the Retry button should actually do to get the callback?
Thank you.
P.S. I'm new to Java, and as of now Kotlin is out of my league so couldn't figured out how Google sample projects implementing the retry method, and, also my sample project is on GitHub/DemoBlogApp for any reference. Any help is appreciated.
Figured it out myself long time back but was waiting for an opinion. While I didn't got any, thought of posting an answer to myself so that others may find it useful.
Retrofit has clone() method which can be super useful for situations for failures. So basically, make an interface:
public interface RetryCallback<T> {
void getCall(Call<T> call, ApiCallback<T> callback);
}
On Retrofit failure:
class Repository {
RetryCallback<Api> retryCallback;
//...
new Callback<Api>() {
// other Callback methods
public void onFailure(Call<Api> call, Throwable t) {
retryCallback.getCall(call, this);
}
}
public void setRetryCallback(RetryCallback<Api> retryCallback) {
this.retryCallback = retryCallback;
}
}
On MainActivity:
//...
// Using lambda instead of initializing with new operator
viewModel.setRetryCallback((call, callback) ->
call.clone().enqueue(callback);
);
I wish to handle all my responses in single method. the purpose is to recall the service when the response code is not 3, when the response code is 3 I intend to first refresh the token and then recall the same service.
I've created a BaseCallback class to catch one method but I can't see the log and can't catch breakpoints.
BASECALLBACK.class
public class BaseCallBack<T> implements Callback<T> {
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (!response.isSuccessful()){
Log.d("BaseCallback","Response Fail");
}
}
#Override
public void onFailure(Call<T> call, Throwable t) {
t.toString();
}
}
CALL METHOD
ApiManager.getInstance().getUsers().enqueue(new BaseCallBack<List<User>>() {
#Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
if (response.isSuccessful()){
}
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
}
});
I just want to handle my services single method.
Your starting point is good - you have an ApiManager which is the single point you're looking for - a class, NOT a method (methods shouldn't be a single contact point in this case, it will make your code unreadable and harder to debug later.
From here it would probably be better to use your own custom interface, and implement it however you wish from where you call the request, there you can handle the stuff you want, this is a very generic example that should fix some stuff and get you going.
Be mindful to the fact that this still requires you to work - tweak and add the stuff you need.
This is all you need as an interface (very basic, you can add stuff)
public interface CustomCallListener<T>
{
public void getResult(T object);
}
This is how you should use it in you ApiManager - it receives your interface as a parameter carrying the expected object type, when the response returns do what you need - parse it, cut it, whatever - and cast it into the correct object, this example uses a String response and a List return object, you can expect whatever you think and parse it accordingly, Retrofit2 allows you to parse JSON strings directly (using GSON or some other library), so it's your decision on what to use here - if you don't know what I mean - read about it.
This is also where I would add breakpoints and Log. calls to debug the response you get as you get it you can also break down rawResponse for headers and other stuff.
class ApiManager
{
// .. other stuff you need...
public void getSomeList(final CustomCallListener<List<SomeObject>> listener)
{
Call<ResponseBody> request = serviceCaller.getSomeInfo(userid);
//...other stuff you might need...
request.enqueue(new Callback<ResponseBody>()
{
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
{
try
{
String response = rawResponse.body().string();
//...other stuff you might need...
//...do something with the response, convert it to
//return the correct object...
SomeObject object = new SomeObject(response);
listener.getResult(object);
}
catch (Exception e)
{
// .. the response was no good...
listener.getResult(null);
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable throwable)
{
// .. the response was no good...
listener.getResult(null);
}
});
}
}
Finally this is what you should use from anywhere in your code - this allows you to implement the callback right there and handle anything you need by what you return from the ApiManager.
ApiManager.getInstance().getSomeList(new CustomCallListener<List<SomeObject>>()
{
#Override
public void getResult(List<SomeObject> objects)
{
if (null != objects)
{
// check objects and do whatever...
}
else
{
// ... do other stuff .. handle failure codes etc.
}
}
});
Stuff to notice
As mentioned - this is a very generic skeleton that can be greatly modified (add more methods to the interface with different return types to handle Exceptions, Bad responses, other objects, add more params to the same method to handle more options, etc.) read about the subject more, beware of passing null Objects, use try and catches to avoid crashes.
Hope this Helps!
I am implementation for Retrofit on api call using images-upload base64Encode string. it is sending data perfect but Retrofit return response Internal Server Error 500 and i am sending request type is Body custom class. Plz help me what i do.
#Headers("Accept:application/json")
#POST(RestClient.postRegister)
Call<RegisterResp> getRegisterResponse(#Body RequestRegisterVo requestRegisterVo);
Call<RegisterResp> call = MyApplication.getRestClient().getApplicationServices().getRegisterResponse(requestRegisterVo);
call.enqueue(new Callback<RegisterResp>() {
#Override
public void onResponse(Call<RegisterResp> call, Response<RegisterResp> response) {
if (Other.isValidResp(response)) {
// success Log.i(TAG,"Register successfully");
} else {
hideDialog();
}
}
#Override
public void onFailure(Call<RegisterResp> call, Throwable t) {
hideDialog();
showToast(t.getMessage());
}
});
The same issue I had to face it, I got a solution in my case-
there is parameter issue, I was sending parameters in String and at the backend, they required Integer parameters.
You also checkout may be there is the issue with parameters or second reason is the URL issue so check it URL also.
I am implementing Link preview feature like WhatsApp, i.e
Provided any link, fetch all its Html
Crawl through Html, read all information
Display text and images
Jsoup Library
I am successfully able to perform this using Jsoup library
Document doc = Jsoup.connect("http://www.techjuice.pk").userAgent("Mozilla").get();
It returns the html code of the page as a response.
Retrofit Library
Now I wanted to perform the same task using Retrofit
Retrofit retrofit = new Retrofit.Builder()
.build();
API api = retrofit.create(API.class);
Call<ResponseBody> call = api.crawlLink("http://techjuice.pk");
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
API.class
public interface API {
#GET
Call<ResponseBody> crawlLink(#Url String url);
}
Exception
java.lang.IllegalStateException: Base URL required.
Unfortunatelly you can't change URL in Retrofit at Runtime in that way.
Try this tutorial: https://futurestud.io/tutorials/retrofit-2-how-to-change-api-base-url-at-runtime-2
or this answer: Set dynamic base url using Retrofit 2.0 and Dagger 2
How do I get a specific header using the Ion network library for Android?
This is what I'm trying:
...
.setCallback(new FutureCallback<Response<String>>() {
#Override
public void onCompleted(Exception e, Response<String> result) {
System.out.println("header: " + result.getHeaders().message("mykey"));
}
});
message(String) sets the HTTP response message. I should make that internal to avoid confusion.
Use
getHeaders().getHeaders().get(String)
It's a bit obtuse at the moment, will need to clean that API up in the next release.