Send lots of data from Android - android

I have an application in Android, it sends several data in short time. Aprox. 2500 request.
This process is very time-consuming.
What advice can you give me to improve the time?
Thanks

You can use multiple Thread to send data to the server in the background.
If you are updating UI component after the execution use AsyncTask. But you have to run AsyncTask parallelly. You can do that by AsyncTaskCompat.executeParallel(Your AsyncTask);
If you wish to send data even your app closed. You can use service.

I'd recommend using Retrofit. It handles a lot of threading issues you might be struggling with.
Here's an example from their website.
You'd create an interface for the API you're looking to receive:
public interface GitHubService {
#GET("users/{user}/repos")
Call<List<Repo>> listRepos(#Path("user") String user);
}
You build a retrofit class
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
And finally you get a call object:
Call<List<Repo>> repos = service.listRepos("octocat");
Consuming the call object requires enqueueing a Callback. Here's an example using a different Retrofit service (TaskService in this case):
TaskService taskService = ServiceGenerator.createService(TaskService.class);
Call<List<Task>> call = taskService.getTasks();
call.enqueue(new Callback<List<Task>>() {
#Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
if (response.isSuccessful()) {
// tasks available
} else {
// error response, no access to resource?
}
}
#Override
public void onFailure(Call<List<Task>> call, Throwable t) {
// something went completely south (like no internet connection)
Log.d("Error", t.getMessage());
}
}
Source

Related

Android Retrofit + Rxjava flowable completes too early

I am trying to send an io.reactivex.Flowable from a Spring RestController to an Android application that uses Retrofit and Rxjava. If I use the browser to check what the Rest endpoint returns, I get a series of values as expected but in Android I get only one value and then it calls the onComplete method. What am I missing?
Spring Controller:
#GetMapping("/api/reactive")
public Flowable<String> reactive() {
return Flowable.interval(1, TimeUnit.SECONDS).map(sequence -> "\"Flowable-" + LocalTime.now().toString() + "\"");
}
Retrofit repository:
#GET("reactive")
Flowable<String> testReactive();
Main service:
public useReactive() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Values.BASE_URL)
.addConverterFactory(JacksonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
userRepository = retrofit.create(UserRepository.class);
Flowable<String> reactive = userRepository.testReactive();
Disposable disp = reactive.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new ResourceSubscriber<String>() {
#Override
public void onNext(String s) {
logger.log(Level.INFO, s);
Toast.makeText(authActivity, s, Toast.LENGTH_SHORT).show();
}
#Override
public void onError(Throwable t) {
t.printStackTrace();
}
#Override
public void onComplete() {
logger.log(Level.INFO, "Completed");
Toast.makeText(authActivity, "Completed", Toast.LENGTH_SHORT).show();
}
});
}
Upon calling the useReactive() method, I get only one value "Flowable-..." and then "Completed".
Even though the Retrofit service has return type Flowable<String>, calling testReactive() will only make one HTTP call on the Android device.
The type Flowable is merely for compatibility, in practice it will end up being a Flowable that emits a single value and then terminates.
This is just how Retrofit works.
You would need to find another solution if you want to continually receive new values that are being emitted from the server, perhaps GRPC or polling the server.

How to implement POST method in AsyncTask to write JSON data through API in android studio?

I want to POST JSON data having nested objects in it with the help of Asynctask in android studio, but I don't have good knowledge of API implementation in android studio. I am all new in android studio. I have successfully POST this data from POSTMAN, but I am not able to implement the code for it, also I don't have any tutorials for Asynctask. Please help me to implement code for this.
This is my Json data having nested Objects in it:
You don't need Async, Volley does it in the background for you. Put your JSONObject in the method instead of 'new JSONObject'. And YourURL - i.e '/api/route/'.
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest request_json = new JsonObjectRequest(YourURL, new JSONObject(params)),
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
//Do what you want on response
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//If there's an error...
}
});
//Add process to queue to get JSON in background thread
queue.add(request_json);
Nowadays a better/simpler approach would be to use a libary like Retrofit to do all the magic for you.
You can simply send a Java instance model to an API endpoint. Retrofit takes care of converting it to json when using the GsonConverterFactory class and sends the json to the endpoint you provided with the given HTTP method.
Best and Simple Library for Implementation for API services by third party library made by Square, Retrofit a Easy HTTP Client.
Why Retrofit? because, Retrofit automatically creates the background thread ,Parse the Json using GSON converter and get a call success and Failure call back directly on main thread. Without writing too much boiler plate code of AsyncTask and Parsing JSON and getting the result on main thread.
Make Retrofit Client.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
RetrofitInterface service = retrofit.create(RetrofitInterface.class);
Make Method in RetrofitInterface.
#POST("users/new")
Call<User> yourMethod(#Body UserType user);
Now Call your method and It will make your success and Failure Callback method
Call<List<Repo>> repos = service.yourMethod("octocat");
And then Call enque method to automatic create background thread.
repos.enqueue(new Callback<List<Repo>>() {
#Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
#Override
public void onFailure(Call<MainResponse> call, Throwable t) {
}
});

Android, Retrofit 2 POST request

I'm new to Android developing and I don't know how to do this, I've searched on the internet, but everything I've tried so far doesn't work. What I'm trying to do, is to send string to the server and the key must be "interval=". This is what I have so far, but it doesn't work. I'm getting string time2 from spinner, but for now it doesn't matter, because I know that the spinner part works and POST doesn't.
PostInterface service = retrofit.create(PostInterface.class);
service.postTime(time2);
and interface
#FormUrlEncoded
#POST
Call<Response> postTime(#Field("interval=") String time);
What I'm supposed to do net and how can I test it with http://requestb.in/ (never used it before, I just saw it can be used for POST testing)?
Why do you use retrofit in the first place ?
It's a good library, but if you're new to Android, i suggest to start with HttpClient.
In your sample, the execute method was not called.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://requestb.in/")
.addConverterFactory(GsonConverterFactory.create())
.build();
PostInterface service = retrofit.create(PostInterface.class);
Call<Response> call = service.postTime(time2);
call.execute()
In your interface (replace xxx by the token given by requestbin)
#FormUrlEncoded
#POST("xxxxxxx")
Call<Response> postTime(#Field("interval=") String time);
ps: Be aware that you should not launch any http calls on the main thread.
if you are posting a form field, you should remove the "=" from "interval="
fields are key and values, no need for the "="
if you want a test client for posts and get you can try postman
please clarify your question more if this is not what you expected as an answer
as #Mickael Monsang Answer
dont' use call.execute directly better use
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<Response> call, Response<Response> response) {}}
#Override
public void onFailure(Call<String> call, Throwable t) {
}
}
});

Testing real network responses with retrofit

Before I get the obligatory "you shouldn't be testing real network responses for XYZ reasons!", it should be noted that I am not asking whether or not I should.
I am asking specifically how I would go about doing so, if I wanted to.
After a few hours of struggle I've successfully managed a proper response from Volley, and have that test going.
The problem I'm having now, is that call.enque(...) seems to hang on the RobolectricTestRunner. Unlike Volley, I can't peek in and see whats going on in there (for Volley, the challenge was not realizing that Looper.getMainLooper doesn't get properly created.)
So, all I am doing is trying to make a simple request to the server via Retrofit. The issue, as I said, is that the entire system hangs at call.enqueue, and there is no error or response ever (even when my await is longer). The network call works fine with volley, but I am getting this snag here with Retrofit. Here's the code if you want to try it. And of course, the function works fine when the app is running.
//in NetworkManager.class
public void someCall(HashMap properties, NetworkResponseListener listener){
this.okHttpClient = new OkHttpClient.Builder().cache(new Cache(appContext, 35 * 1024 * 1024)).build();
this.retrofit = new Retrofit.Builder().baseUrl(httpPath + apiHost).client(okHttpClient).build();
this.myService = retrofit.create(MyService.class);
Call call = myService.someRequest(properties);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
listener.onSuccess(response);
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
listener.onError(t);
}
});
}
Service:
interface MyService {
#GET("/api/SomeEndpoint/")
Call<ResponseBody> someRequest(#QueryMap Map<String, Object> params);
}
Test:
#Test
public void testSomeCall() throws Exception {
//Network class has setup OkHttpClient/Service/Retrofit already
NetworkResponseListener listener = new NetworkResponseListener() {
#Override
public void onSuccess(Response response) {
this.response = response;
}
#Override
public void onError(Throwable error) {
//
}
};
NetworkManager.someCall(this.properties, listener);
await().atMost(30, TimeUnit.SECONDS).until(ResponseReceived());
}
Everyone's response on stackoverflow has been 'don't test real network responses', which is really not helpful.
Solution is pretty much exactly the same as for volley.
Retrofit2 will default to the platform callback executor, which will not be correctly instantiated in a test.
Solution is simple. If you wish to test retrofit with real network calls, you must change the callbackExector. Here's what I ended up doing:
retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.client(okHttpClient).callbackExecutor(Executors.newSingleThreadExecutor())
Network tests are running successfully.

Mapping rest model to domain model in Android

I want to keep my domain model and rest model separate so that I don't have to worry about changing the domain model when rest API changes. Also, I get to work with UI-friendly format by converting rest model to domain model.
I use retrofit to consume Restful web service. In onResponse(), I am mapping the rest model into domain model. I hate instantiating bunch of objects on the main thread. What are some clean ways to map not on main thread?
String username = "test";
Call<User> call = apiService.getUser(username);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
int statusCode = response.code();
User user = response.body();
// Want to convert rest model to domain model for my use
Account account = AccountMapper.map(user);
}
#Override
public void onFailure(Call<User> call, Throwable t) {
// Log error here since request failed
}
});
Generally you want a converter. The converter's job is to interpret from the external Api to your domain context/models. Converters can be implemented as "Factories". You pass the factory method the right parameters and it'll return to you something that your domain understands/can use.
Now, when you say "not instantiating on the main thread": It sounds like you have answered your own question because that sounds like you are suggesting concurrency through threads. Unless you concurrently spin up a new thread, you can move the code around but you'll always be on the "main" thread.
after you get the response just call map{ someMapper().map(from, to)}
here would be the general interface for all your mappers:
interface Mapper<FROM, TO> {
fun map(model: FROM): TO
}

Categories

Resources