I need to show a progress bar while downloanding something from my webservice, because i need to make a fragment transition just when the download was complete. I've tried to many different things, but im still stucked on the start. I got the transition before the download finish
Someone can show me an example or show me a direction from where to look to solve this problem?
public void efetuarLogin() {
loadProgress.setVisibility(View.VISIBLE);
final iRequestsTramita requestsTramita = TramitaService.getInstance().usarServico();
Call<RespostaTramita> callCapturarUG = requestsTramita.getResposta(new LoginTramita(userLogin,userPass));
callCapturarUG.enqueue(new Callback<RespostaTramita>() {
#Override
public void onResponse(Call<RespostaTramita> call, Response<RespostaTramita> response) {
//loadProgress.setVisibility(View.GONE);
if (response.isSuccessful()) {
doing something...
baixarObrasGestor();
loadProgress.setVisibility(View.GONE);
} else {
doing something...
}
}
#Override
public void onFailure(Call<RespostaTramita> call, Throwable t) {
...
}
});
}
public void baixarObrasGestor(){
List<Gestao> listaIdRequisicao = bancoDadosController.gerarListaRequisicaoGeoPB(userLogin);
iRequestsGeoPB requestsGeoPB = GeoPBService.getInstance().usarServico();
//make some requests to webservice
for (Gestao gestao : listaIdRequisicao){
...
Call<List<RespostaGeoPB>> callBaixarObras = requestsGeoPB.baixarObrasGestor(headers, paramRequisicao);
callBaixarObras.enqueue(new Callback<List<RespostaGeoPB>>() {
#Override
public void onResponse(Call<List<RespostaGeoPB>> call, Response<List<RespostaGeoPB>> response) {
...doing something
}
#Override
public void onFailure(Call<List<RespostaGeoPB>> call, Throwable t) {
Log.d("TESTE", "erro: " + t.getMessage());
}
});
}
selecionaUG(); //do the fragment transition
}
Personally I override Callback<T> this provides you option to include all custom events you want to raise like.
public abstract class RetryCallback<T> implements Callback<T> { ... }
If you only want to hear when loading completes this much skleton is enough. But make sure some exception is not raised out of your onResponse or onFailure. I have often seen transition without notice when some exception is raised. Pack your code inside try-catch and see if it is not the problem case.
public void onResponse(Call<T> call, Response<T> response) {
if(!response.isSuccessful()){
// ....
loadingComplete();
return;
}
// ...
loadingComplete();
}
#Override
public void onFailure(Call<T> call, Throwable t) {
// ...
loadingComplete();
}
Related
i tried to return list from the url that i get with retrofit. it works and i get the data but it wont return.
this is my code
public List<MovieResponse> loadCourses() {
ArrayList<MovieResponse> list = new ArrayList<>();
ApiServices apiService =
NetworkClient.getRetrofitClient().create(ApiServices.class);
Call<MovieResult> call = apiService.getMovies();
call.enqueue(new Callback<MovieResult>() {
#Override
public void onResponse(Call<MovieResult> call, Response<MovieResult> response) {
if (response.body() != null) {
ArrayList<MovieResponse> movies = new ArrayList<>();
movies = response.body().getResults();
Log.d("",""+movies);
list.addAll(movies);
Log.d("",""+list);
}
}
#Override
public void onFailure(Call<MovieResult> call, Throwable t) {
// Log error here since request failed
Log.e("error", t.toString());
}
});
return list;
}
when i print list inside onResponse it works and there are the data. but when i return it or trying to print list outside onResponse for example below ArrayList<MovieResponse> list = new ArrayList<>(); it not show the data.
please help what is actually wrong with it. i really appreciate it.
The simplest way is to define your movies list directly inside activity or fragment(in other words, a field member of the class).
It's not a good idea to return data from an asynchronous method.
Change the return type of the loadCourses method to void and instantiate the filed movies inside onResponse().
public class SomeActivity extends AppCompatActivity {
private ArrayList<MovieResponse> movies = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_some);
}
public void loadCourses() {
ApiServices apiService =
NetworkClient.getRetrofitClient().create(ApiServices.class);
Call<MovieResult> call = apiService.getMovies();
call.enqueue(new Callback<MovieResult>() {
#Override
public void onResponse(Call<MovieResult> call, Response<MovieResult> response) {
if (response.body() != null) {
movies = response.body().getResults();
...
}
}
#Override
public void onFailure(Call<MovieResult> call, Throwable t) {
...
}
});
}
}
It is because you are making asynchronous call which is being handled by a separate thread. So after call.enqueue(), the main thread directly jumps to return statement without waiting for API response, that's why you are getting empty list.
Assuming your API takes 1 sec to respond,
just for an experiment, you can try adding a sleep() for 3 sec right before your return statement, it should return all the movies.
If you must return from the method then go for retrofit synchronous call.
To make a sync call create a new thread in main thread and make call from there, it is not allowed to make network call from main thread because it blocks the thread.
I am looking at a code that I have to work on. And basically I have to add a validation to a listener of a button.
The code has already multiple validations. They are kind of set in a cascade.
The listener of the buttons calls an asyncCallBack method that if everything is ok, on the onsuccess part of the method calls for the next one, an that one on the next one, until it reaches the end and goes to the next page. I am not a fan of this approach because it is kind of messy. What would the best way to do that using best practices.
An example of the code:
Button btnOK = new Button("Aceptar");
btnOK.addListener(Events.Select, new Listener<ButtonEvent>() {
public void handleEvent(ButtonEvent e) {
myService.getInfo1(1, txt, "N",
new AsyncCallback<List<InfoService>>() {
public void onFailure(Throwable caught) {
// goes back
return
}
public void onSuccess(
List<Object> result) {
// do some validation with the result
validation2();
}
}
}
}
public void validation2(){
myService.getDireccionCanalesElectronicos(id, new AsyncCallback<MyResult>() {
public void onSuccess(MyResult result) {
// do some validation with the result
validation3();
}
...
}
}
public void validation3(){
myService.getDireccionCanalesElectronicos(id, new AsyncCallback<MyResult>() {
public void onSuccess(MyResult result) {
// do some validation with the result
validation4();
}
...
}
}
Is there a better way of doing this, it seems messy and hard to follow. Adding another validation is complicated. It doesnt seem like a good practice.
Create 1 method in the servlet that calls all the validation methods and do just one call in the client ?
public void validation()
{
boolean ok = validation1();
if (ok) ok = validation2();
return validation;
}
Using mirco services is sometimes hard to deal with. As #Knarf mentioned, this is a way to go. But sometime you may want to handle the calls on the client side. Another one will be using this tiny framework: sema4g. It will help you to solve your problem.
A solution might look like that:
First create the sem4g commands:
private SeMa4gCommand createGetInfoCommand() {
return new AsyncCommand() {
// create callback
MethodCallbackProxy<List<InfoService>> proxy = new MethodCallbackProxy<List<InfoService>>(this) {
#Override
protected void onProxyFailure(Method method,
Throwable caught) {
// Enter here the code, that will
// be executed in case of failure
}
#Override
protected void onProxySuccess(Method method,
List<InfoService> response) {
// Enter here the code, that will
// be executed in case of success
}
};
#Override
public void execute() {
// That's the place for the server call ...
myService.getInfo1(1, txt, "N", proxy);
}
};
}
do that for all your calls;
private SeMa4gCommand createCommandGetDireccionCanalesElectronicos() {
return new AsyncCommand() {
// create callback
MethodCallbackProxy<MyResult> proxy = new MethodCallbackProxy<MyResult>(this) {
#Override
protected void onProxyFailure(Method method,
Throwable caught) {
// Enter here the code, that will
// be executed in case of failure
}
#Override
protected void onProxySuccess(Method method,
List<MyResult> response) {
// Enter here the code, that will
// be executed in case of success
}
};
#Override
public void execute() {
// That's the place for the server call ...
myService. getDireccionCanalesElectronicos(id, proxy);
}
};
}
Once you have done this for all your calls, create a sema4g context and run it:
try {
SeMa4g.builder()
.addInitCommand(new InitCommand() {
#Override
public void onStart() {
// Enter here your code, that
// should be executed when
// the context is started
})
.addFinalCommand(new FinalCommand() {
#Override
public void onSuccess() {
// Enter here the code, that will
// be executed in case the context
// ended without error
}
#Override
public void onFailure() {
// Enter here the code, that will
// be executed in case the context
// ended with an error
})
.add(createGetInfoCommand())
.add(createCommandGetDireccionCanalesElectronicos())
.build()
.run();
} catch (SeMa4gException e) {
// Ups, something wrong with the context ...
}
For more informations, read the documentation. If you have questions, feel free to ask: SeMa4g Gitter room.
Hope that helps.
I'm trying to find a way to handle asynchronous network requests in Swift. My plan is to isolate these calls in their own class, so I need a way to handle callbacks. In Android, I'm doing something like the following using an Interface:
apiService.fetch(data, new Callback() {
#Override
public void onResponse(Response r) {
// success
}
#Override
public void onFailure(Error e) {
// error
}
});
Can someone point me in the direction on how I can handle this similarly in Swift 3? Thanks!
It's possible to have multiple completion handlers. Here is a short example:
func request(url:String, success:#escaping(Any) -> Void, failure:#escaping(Any?) -> Void)
{
let task = URLSession.shared.dataTask(with: URL.init(string: url)!) { (data, response, error) in
if let responseError = error
{
failure(responseError)
}
else if let responseData = data //Make additional checks if there is an error
{
success(responseData) //Call when you are sure that there is no error
}
else
{
failure(nil)
}
}
task.resume()
}
Example of usage:
self.request(url: "https://jsonplaceholder.typicode.com/posts", success: { (data) in
//Do if success
}) { (error) in
//Do if error
}
What can I use instead of addAll() method in my adapter, I'm using realm version 2.0.1 and that method is deprecated, I'm trying to get all the data from the API, save it to my database and pass it to my adapter, I'm using like this:
public void getData(int page) {
if (GlobalModel.existeConexao()) {
Call<PedidosResponse> call = ((NavigationMain) getActivity()).apiService.getPedidos(GlobalModel.getToken(), GlobalModel.geEmpresaId(), page);
call.enqueue(new Callback<PedidosResponse>() {
#Override
public void onResponse(Call<PedidosResponse> call, Response<PedidosResponse> response) {
if (response.isSuccessful()) {
for (int i = 0; i < response.body().getPedidos().size(); i++) {
Pedidos mPedido = response.body().getPedidos().get(i);
int myInt = (mPedido.isProjecao()) ? 1 : 0;
if (!mRepositorio.checkIfExists(mPedido.getId())) {
mRepositorio.addPedido(mPedido.getId(), mPedido.getCliente_id(), mPedido.getData_hora(), mPedido.getData_pedido_cliente(), mPedido.getPrevisao_entrega(), mPedido.getFrete_tipo(), myInt, mPedido.getObservacao(), mPedido.getAliquota_projecao(), mPedido.getStatus(), mPedido.getPedido_cliente());
}
}
arraypedidos = mRepositorio.findAllPedidos();
if (mPedidosAdapter == null) {
mPedidosAdapter = new PedidosAdapter(getActivity(), arraypedidos);
listpedidos.setAdapter(mPedidosAdapter);
} else {
mPedidosAdapter.setData(arraypedidos);
}
}
}
#Override
public void onFailure(Call<PedidosResponse> call, Throwable t) {
if (t.getMessage() != null) {
Log.v("pedidos", t.getMessage());
}
}
});
} else {
Toast.makeText(getActivity(), "Verifique sua conexão", Toast.LENGTH_SHORT).show();
}
}
But when I run the app I get this message:
java.lang.UnsupportedOperationException: This method is not supported by RealmResults.
That's because RealmResults is just a set of pointers that satisfy the condition defined in the query. You can't manipulate it, nor should you if you just intend to show every element in your adapter.
In fact, Realm was explicitly designed to simplify the workflow of "downloading data on a background thread and saving the data in a database", and "showing the data downloaded on a background thread automatically on the UI thread".
This is what RealmChangeListener is for.
Simply put, all of this code is unnecessary:
arraypedidos = mRepositorio.findAllPedidos();
if (mPedidosAdapter == null) {
mPedidosAdapter = new PedidosAdapter(getActivity(), arraypedidos);
listpedidos.setAdapter(mPedidosAdapter);
} else {
mPedidosAdapter.setData(arraypedidos);
}
And could be replaced with this:
public class SomeActivity extends AppCompatActivity {
PedidosAdapter pedidosAdapter;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.some_view);
pedidosAdapter = new PedidosAdapter(context, mRepositorio.findAllPedidos());
// set adapter, ...
}
}
And
public class PedidosAdapter extends RealmRecyclerViewAdapter<Pedidos, PedidosViewHolder> {
public PedidosAdapter(Context context, RealmResults<Pedidos> results) {
super(context, results, true);
}
// onBindViewHolder
// onCreateViewHolder
}
For this, use RealmRecyclerViewAdapter, unless you intend to handle the RealmChangeListener manually.
In my Android app, I'd like to implement success and error callbacks for when I get reading passages from my backend. In iOS, it would look like this:
In my Passage.h:
-(void)getPassagesWithSuccessCallback:(void (^)(NSArray<Passage *> *))success errorCallback:(void (^)(NSString *))errorString;
In my Passage.m:
-(void)getPassagesWithSuccessCallback:(void (^)(NSArray<Passage *> *))success errorCallback:(void (^)(NSString *))errorString {
MyApiInterface* api = [MyApiInterface sharedInstance];
[api sendGetRequestTo:#"passages" successCallback:[Passage modelListCallback:success] errorCallback:error];
}
In my Android app, I'm using Volley to handle my API requests, but I want to further encapsulate this API interfacing by having a Passage.java class with a public static void method that gets the passages. Something like this:
public static void getPassagesForFirebaseUser(FirebaseUser user, Context context) {
final String url = URL_BASE + "/passages.json" + "?auth=" + user.getToken(false);
final JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// convert JSON into ArrayList<Passage> object
// pass on this array of Passages in the success completion listener of the method that called this
// just like iOS does success(passages)
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// convert error to string
// pass on this errorString in the error completion listener of the method that called this
// just like iOS does error(errorString)
}
});
Volley.newRequestQueue(context).add(request);
}
Is there any way to get this kind of implementation flow?
You can use an Interface
public interface ICallbacks {
public void onResponse(JSONObject response);
public void onError(VolleyError error);
}
Then in your routine code just put a new instance of Callbacks (depending on ide that you work could autogenerate the methods)
public static void getPassagesForFirebaseUser(FirebaseUser user,
Context context, ICallbacks events) {
//here code and call ICallbacks methods
if(result){ events.onResponse(response); }
if(error){ events.onError(err); }
}
ultimately you can call the method with :
getPassagesForFirebaseUser(user, context, new ICallbacks(){
#Override
public void onResponse(JSONObject response){
//Success !!!
}
#Override
public void onError(VolleyError response){
//Error !!!
}
});
Sorry for my English, hope this help !