Retrofit throws an error - java

I've created some Pojo model and I'm getting data from api into my android app. Data should be downloaded on button click.
Here is how I made this:
public class DownloadMain extends Fragment implements Callback<Partner> {
private static final String TAG = DownloadMain.class.getSimpleName();
private Button dloadPartners;
private Call callPartners;
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();
return view;
}
Button.OnClickListener btnListener = (new Button.OnClickListener() {
#Override
public void onClick(View v) {
callPartners.enqueue(DownloadMain.this);
}
});
#Override
public void onResponse(Call call, Response response) {
if(response.body() == null) {
try {
response.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getActivity(), "No Partners!", Toast.LENGTH_SHORT).show();
} else {
List<Partner> partners = (List<Partner>) response.body();
Log.d(TAG, "Number of partners received: " + partners.size());
}
}
#Override
public void onFailure(Call call, Throwable t) {
}
}
So problem is here. When I click on button it gives me a notice (toast) "No partners!".
And when I click again it throws me an error:
IllegalStateException: Already executed. at
retrofit2.OkHttpCall.enqueue(OkHttpCall.java:78)
at this line in Button onClick method:
callPartners.enqueue(DownloadMain.this);
I can't figure it out why retrofit is not getting any data.
QUESTION: Could someone help me to resolve this problem?

You can call only once. If you need to do more calls use clone.
From javadoc:
An invocation of a Retrofit method that sends a request to a webserver and returns a response. Each call yields its own HTTP request and response pair. Use clone() to make multiple calls with the same parameters to the same webserver; this may be used to implement polling or to retry a failed call.
Basically the code should be
callPartners.clone().enqueue(DownloadMain.this);

Related

How to pend flutter method channel callback (android native java code) for an android listener

I have a flutter app that run a java code in some situations.
I wrote java code in method call handler in MethodCahnnel.
In this callback I call another method that is communicate with a serial port using usb-serial-for-android and wait for data in onNewData listener. I want to send back this data to flutter. and I am using a class variable for it and fill it in onNewData method. and use result.success conditionaly when the variable is not empty! but result.success never called and if I delete the if statement, result.success called when the variable is empty.
Here is the section of my code:
public class MainActivity extends FlutterActivity implements SerialInputOutputManager.Listener {
private static final String CHANNEL = "channel";
private UsbSerialPort connectionPort;
private String response = "";
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
select();
if (!response.isEmpty()) result.success(response);
}
);
}
#Override
protected void onNewIntent(Intent intent) {
if (intent.getAction().equals("android.hardware.usb.action.USB_DEVICE_ATTACHED")) {
Toast.makeText(this, "new usb device detected!", Toast.LENGTH_SHORT).show();
}
super.onNewIntent(intent);
}
private void select() {
connectionPort.write(...);
}
#Override
public void onNewData(byte[] data) {
response = Utils.byteArrayToHexString(data);
}
#Override
public void onRunError(Exception e) {
status("error onRunError" + e.getMessage());
}
}

Picasso Showing the Error Path Must Not Be Empty?

I am trying to fetching image from firebase. so when there is no image in firebase i want that my app logo will be set there. but my app is crashing and throwing the error into a log-cat.
I tried using if-else condition. and also on Success and on Error Methods. but did't worked fine.
private static final String Earnings_Freebies = "EARNINGS_FREEBIES";
private Earnings_Freebies list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earnings_freebies);
list = (Earnings_Freebies) getIntent().getExtras().getSerializable(Earnings_Freebies);
if (TextUtils.isEmpty(list.getmImageView())){
m_EF_ImageView.setImageResource(R.drawable.app_logo);
mProgressBarEF.setVisibility(View.GONE);
}
Picasso.with(getApplicationContext())
.load(list.getmImageView())
.into(m_EF_ImageView, new Callback() {
#Override
public void onSuccess() {
mProgressBarEF.setVisibility(View.GONE);
mFailedImage.setVisibility(View.GONE);
}
#Override
public void onError() {
mProgressBarEF.setVisibility(View.GONE);
mFailedImage.setVisibility(View.VISIBLE);
}
});
I want when there is error. or i forget to put image into firebase then app logo will automatically set into Image-view.
You can try below code. If not helpful then let me know a bit more about Earnings_Freebies model.
Make sure you were using latest dependency of Picasso.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earnings_freebies);
list = (Earnings_Freebies) getIntent().getExtras().getSerializable(Earnings_Freebies);
if (list == null && TextUtils.isEmpty(list.getmImageView())){
m_EF_ImageView.setImageResource(R.drawable.app_logo);
mProgressBarEF.setVisibility(View.GONE);
Picasso.with(getApplicationContext())
.load(R.mipmap.ic_launcher) // can also be a drawable
.into(m_EF_ImageView);
} else {
Picasso.with(getApplicationContext())
.load(list.getmImageView())
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.into(m_EF_ImageView);
}
}
you can try this way:
private static final String Earnings_Freebies = "EARNINGS_FREEBIES";
private Earnings_Freebies list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earnings_freebies);
list = (Earnings_Freebies) getIntent().getExtras().getSerializable(Earnings_Freebies);
if (list != null && list.getmImageView() != null && !TextUtils.isEmpty(list.getmImageView())){
Picasso.with(getApplicationContext())
.load(list.getmImageView())
.into(m_EF_ImageView, new Callback() {
#Override
public void onSuccess() {
mProgressBarEF.setVisibility(View.GONE);
mFailedImage.setVisibility(View.GONE);
}
#Override
public void onError() {
mProgressBarEF.setVisibility(View.GONE);
mFailedImage.setVisibility(View.VISIBLE);
}
});
}else{
Picasso.with(getApplicationContext())
.load(R.drawable.app_logo)
.placeholder(R.drawable.app_logo)
.into(m_EF_ImageView);
}
}
1) Picasso supports both download and error placeholders as optional features.
2) An error drawable will be used in case where there’s a failure in loading the image. In this case the interim placeholder image will be replaced by the error drawable that’s placed inside .error() method, where you can display your app's icon image in case of error.
Picasso.with(this).load("https://someImageURL")
.error(R.mipmap.ic_launcher) // Your app's icon image displayed on error
.placeholder(R.drawable.user_placeholder) // some placeholder image
.into(imageView, new Callback() {
#Override
public void onSuccess() {
Log.d("TAG", "onSuccess");
}
#Override
public void onError() {
Toast.makeText(getApplicationContext(), "An error occurred", Toast.LENGTH_SHORT).show();
}
});

repeat some items whenever i bring more data?

I have created a load function to fetch items through a PHP file that adds 3 elements of the names in the database to Android each time I call the php file so I did the functions of the load function displays 3 names on the Android screen after that the Loadmore function and found a problem which is repeated The name in the middle is not identical to the database,see these screenshot:https://ibb.co/sFg6p7N I hope you help me and add the appropriate code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.activity_customer, container, false);
//View rootView = inflater.inflate(R.xml.pref, container, false);
//Intent intent = new Intent(PreferenceDemoActivity.this,PrefsActivity.class);
// startActivity(intent);
this.context = getActivity();
recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
customers = new ArrayList<>();
adapter = new CustomerAdapter(context,customers);
adapter.setLoadMoreListener(new CustomerAdapter.OnLoadMoreListener(){
#Override
public void onLoadMore() {
recyclerView.post(new Runnable() {
#Override
public void run() {
int index = customers.size()-1;
loadMore(index);
}
});
//Calling loadMore function in Runnable to fix the
// java.lang.IllegalStateException: Cannot call this method
while RecyclerView is computing a layout or scrolling error
}
});
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(adapter);
api = ServiceGenerator.createService(API.class);
load(0);
return rootView;
}
private void load(int index){
Call<List<Customer>> call = api.getCustomer(index);
call.enqueue(new Callback<List<Customer>>(){
#Override
public void onResponse(Call<List<Customer>> call, final
Response<List<Customer>> response){
Log.i("TRUE_TRUE_","Yes "+response.body().get(2).name);
if(response.isSuccessful()){
getActivity().runOnUiThread(new Runnable(){
public void run(){
customers.addAll(response.body());
adapter.notifyDataChanged();
}});
getActivity().runOnUiThread(new Runnable(){
public void run() {
}});
}else{
Log.e(TAG," Response Error "+String.valueOf(response.code()));
}
}
#Override
public void onFailure(Call<List<Customer>> call, Throwable t) {
Log.e(TAG," Response Error "+t.getMessage());
}
});
}
private void loadMore(int index){
// add loading progress view ....
customers.add(new Customer("load"));
adapter.notifyItemInserted(customers.size()-1);
Log.i("customers.size() ","Yes "+customers.size()); // = 4 -1 =3
Log.i("Index_","Yes "+index);// = 2
Call<List<Customer>>call = api.getCustomer(index);
call.enqueue(new Callback<List<Customer>>(){
#Override
public void onResponse(Call<List<Customer>> call,
Response<List<Customer>>response) {
if(response.isSuccessful()){
// remove loading view .......
customers.remove(customers.size()-1);
// Log.i("LastItemRemove","Yes "+response.body().get(2).name);// = 2
List<Customer>result=response.body();
if(result.size()>0){
// add loaded data
customers.addAll(result);
}else{//result size 0 means there is no more data available at server
adapter.setMoreDataAvailable(false);
//telling adapter to stop calling load more as no more server data available
Toast.makeText(context,"No More Data Available",Toast.LENGTH_LONG).show();
}
adapter.notifyDataChanged();
//should call the custom method adapter.notifyDataChanged here to get the correct loading status
}else{
Log.e(TAG," Load More Response Error "+String.valueOf(response.code()));
}
}
#Override
public void onFailure(Call<List<Customer>>call,Throwable t) {
Log.e(TAG," Load More Response Error "+t.getMessage());
}
});
}
In your onLoadMore callback change this
int index = customers.size()-1;
loadMore(index);
To this
loadMore(customers.size());
You are querying the last entity again in every load

change item from RecyclerView out of onBindViewHolder

On my onBindViewHolder I have this to set the setImageResource
holder.card_image.setImageResource(image);
But my items can be purchased so, I have this to purchase on my holder.view.setOnClickListener()
bp.purchase((Activity) mContext,model.getProduct_id());
so, it goes to this method :
bp = new BillingProcessor() new BillingProcessor.IBillingHandler() {
#Override
public void onProductPurchased(#NonNull String productId, #Nullable TransactionDetails details) {
showToast("onProductPurchased: " + productId);
//Purchased OK
//WANT TO CHANGE THE IMAGE ONCE PURCHASE IS OK
}
#Override
public void onBillingError(int errorCode, #Nullable Throwable error) {
showToast("onBillingError: " + Integer.toString(errorCode));
}
#Override
public void onBillingInitialized() {
showToast("onBillingInitialized");
readyToPurchase = true;
}
#Override
public void onPurchaseHistoryRestored() {
showToast("onPurchaseHistoryRestored");
for(String sku : bp.listOwnedProducts())
Log.d("skuProducts", "Owned Managed Product: " + sku);
for(String sku : bp.listOwnedSubscriptions())
Log.d("skuProducts", "Owned Subscription: " + sku);
}
});
How do I change it if I'm not onBindViewHolder?
My adapter looks like :
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter< CardPOJO, CardHolder>(options) {
#Override
public CardHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//inflate the single recycler view layout(item)
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_product, parent, false);
int width = parent.getMeasuredWidth() / 2;
width -= mContext.getResources().getDimensionPixelSize(R.dimen._8sdp);
final CardHolder cardViewHolder = new CardHolder(view,width);
return cardViewHolder;
}
#Override
public void onDataChanged() {
super.onDataChanged();
tv.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
#Override
protected void onBindViewHolder(CardHolder holder, int position, final CardPOJO model) {
holder.state.setText(model.getState());
holder.cardName.setText(model.getName());
switch (model.getState()){
case "free":
//Img free
break;
case "not_free":
//Img not free
break;
default:
break;
}
holder.view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(model.getState().equals("free")){
//stuff
}
else{
//stuff
}
root_ref.child("PurchasedProducts").child(currentuser).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
bp.purchase((Activity) mContext,model.getProduct_id()); //HERE I CALL THE PURCHASE SO IF IT'S OK I WANT TO DO SOMETHING LIKE holder.card_image.setImageResource(image);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
});
}
};
adapter.startListening();
products_recycler.setAdapter(adapter);
If I assume correctly you want to change the view appearance or some image change if some payment is done successful or failed.
for that, you can have a callback which will give you the item position in activity or fragment back from there you can make a server call to make the purchase happen and if everything goes well.
when you make your adapter constructor pass the callback
final SomeAdapter obj = new SomeAdapter(this,new Callback(){
#Override
onPaymentRequested(int position, View view){
//this will get called when you press click on image in bindviewholder
bp = new BillingProcessor() new BillingProcessor.IBillingHandler() {
#Override
public void onProductPurchased(#NonNull String productId, #Nullable TransactionDetails details) {
showToast("onProductPurchased: " + productId);
//Purchased OK
adapterModelList.get(position).setPayment(true);
obj.notifyDataSetChanged();
}
#Override
public void onBillingError(int errorCode, #Nullable Throwable error) {
showToast("onBillingError: " + Integer.toString(errorCode));
}
#Override
public void onBillingInitialized() {
showToast("onBillingInitialized");
readyToPurchase = true;
}
#Override
public void onPurchaseHistoryRestored() {
showToast("onPurchaseHistoryRestored");
for(String sku : bp.listOwnedProducts())
Log.d("skuProducts", "Owned Managed Product: " + sku);
for(String sku : bp.listOwnedSubscriptions())
Log.d("skuProducts", "Owned Subscription: " + sku);
}
});
}
});
recyclerView.setAdapter(obj);
so when you call your obj.notifyDataSetChanged(); it will make the adapter to draw all views again where you can set some flag according to int position recieved for click callback and make it change accordingly.
Edit=>07/12/2018: Tried the Firebase Adapter and made few changes since the code was not enough to replicate the scenario but I have made a sample class made few changes but the basic idea is like below.
1: When user click on view in onBindViewHolder we receive a callback which gives a position parameter in fragment or activity from where we are calling
2: Now we process the payment and when we are done we make a change in Database firebase also by updating the CardPojo to server for that particular user item.
3: while we update the CardPojo on server we also set a flag in card pojo which is a boolean for paymentSuccess which will be true when payment is done.
4: since our payment is done and is synced with server with new flag data now we can just call firebaseRecycler.notifyItemChanged(position); which will get the lates update from the server for that particular position which we have received on callback.
5: Now populateViewHolder() gives you a cardpojo object you can check if payment is done then you can change the image
so here is the sample code involved I have tried to match the scenario at best, hope you understand what I am trying to do here.
so first create a listener or a callback
public interface CallBackInterface {
void onClick(int position,CardPOJO cardPOJO);
}
now instead of initializing the FirebaseRecyclerAdapter in activity or fragment just create a class and extend it this separates your ui logic and gives us the extensibility of doing extra things like adding callback.
public class FirebaseRecycler extends FirebaseRecyclerAdapter<CardPOJO,CardHolder> {
CallBackInterface callBackInterface;
public FirebaseRecycler(Class<CardPOJO> modelClass, int modelLayout, Class<CardHolder> viewHolderClass, DatabaseReference ref) {
super(modelClass, modelLayout, viewHolderClass, ref);
this.callBackInterface = callBackInterface;
}
public FirebaseRecycler(Class<CardPOJO> modelClass, int modelLayout, Class<CardHolder> viewHolderClass, Query ref) {
super(modelClass, modelLayout, viewHolderClass, ref);
this.callBackInterface = callBackInterface;
}
#Override
public CardHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//your inflater logic goes here
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_product, parent, false);
CardHolder cardHolder = new CardHolder(view);
return cardHolder;
}
#Override
protected void populateViewHolder(CardHolder viewHolder, final CardPOJO model, final int position) {
//your populate logic
//your existing code here
if (model.isPaymentDone){
//set payment success image holder.card_image.setImageResource(image);
}else{
//set payment failure image
}
//setting the card click listener
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//we have the card click listener, we will start the payment processing in activity
callBackInterface.onClick(position,model);
}
});
}
public void setCallBackInterface(CallBackInterface callBackInterface) {
this.callBackInterface = callBackInterface;
}
}
now almost everything is done we need to call this Custom Firebase adapter and pass the required things and it will do its job.
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final DatabaseReference mDatabaseRef = FirebaseDatabase.getInstance().getReference();
/*
if you have any other database child then you can refer to it using
DatabaseReference child = mDatabaseRef.child("yourchilddatabase");
and pass this to the last argument
*/
final FirebaseRecycler firebaseRecycler = new FirebaseRecycler(CardPOJO.class, R.layout.card_product, CardHolder.class, mDatabaseRef);
firebaseRecycler.setCallBackInterface(new CallBackInterface() {
#Override
public void onClick(final int position, final CardPOJO cardPOJO) {
//start processing the payment
bp = new BillingProcessor() new BillingProcessor.IBillingHandler() {
#Override
public void onProductPurchased(#NonNull String productId, #Nullable TransactionDetails details) {
/**
*when you have processed the payment just enable the flag on server database by having a extra boolean flag for this
* and check in onBindViewHolder if this is enabled if so then replace your image
* updating the values on server, you can handle it according to your user case
*/
cardPOJO.setPaymentDone(true);
mDatabaseRef.push().setValue(cardPOJO);
firebaseRecycler.notifyItemChanged(position);
}
#Override
public void onBillingError(int errorCode, #Nullable Throwable error) {
//existing logic
}
#Override
public void onBillingInitialized() {
//existing logic
}
#Override
public void onPurchaseHistoryRestored() {
//existing logic
}
};
}
});
}
this demonstrates the basic logic you can patch it according to your requirement.
Get your item from RecyclerView's adapter and edit it. Then just call Adapter.onItemChanged(int position), this will cause to call onBindViewholder to be called specifically for that position.

Microsoft translator API , Translate.execute() method not invokes in android

I am trying to make an Android app that will use some API for translation (now I use Microsoft API - microsoft-translator-java-api-0.6.2-jar-with-dependencies.jar )
I have done this for single String, but I want to translate some pdf file. Someone know how can I send PDF to this translator and get it back translated?
public class FirstFrag extends MainNavigation.SectionFrag {
private Button translate;
String translatedText;
public FirstFrag(){
super();
}
public static FirstFrag newInstance(Context c, int section){
FirstFrag ret = new FirstFrag();
ret.setSection(section);
return ret;
}
#Override
public void afterCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.afterCreateView(inflater, container, savedInstanceState);
setContentView(R.layout.first_frag_layout);
translate = (Button) findViewById(R.id.btnProgressBar);
translate.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
translate.setEnabled(false);
new TranslateFromBing().execute();
}
});
}
#Override
protected void onRetryClicked() {}
// Async Task Class
class TranslateFromBing extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... f_url) {
Translate.setClientId("MY CLIENT ID");
Translate.setClientSecret("MY CLIENT SECRET");
translatedText = null;
try {
translatedText = Translate.execute("Bonjour le monde", Language.FRENCH, Language.ENGLISH);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onProgressUpdate(String... progress) {
}
#Override
protected void onPostExecute(String file_url) {
Toast.makeText(getActivity().getApplicationContext(), "Translation complete", Toast.LENGTH_LONG).show();
TextView translated = (TextView) findViewById(R.id.translatedText);
if(translatedText != null) {
translated.setText(translatedText);
}
else {
translated.setText("ERROR HERE");
}
}
}
You are invoking execute inside method that is called on UI thread. I dont know this API but it most probably does communicate with server and if it returns data immediately - and not through some kind of callback, then it is probably doing HTTP communication.
This is not allowed under android, you should call this api inside AsyncTask.
Another thing is, You should analyze logcat - it should provide you with additional hints on whats wrong. The fact you call execute inside try/catch is probably because you were getting android.os.NetworkOnMainThreadException.

Categories

Resources