Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have an Android project built in Xamarin (.NET) I wish to convert to native Java. In the Xamarin app I have built an API class used to access HTTP data utilising Generics, which looks like this:
public class InventoryAPI {
HttpClientHandler handler;
Uri baseAddress;
HttpClient client;
public InventoryAPI() {
// .. Init code here
}
public async Task<Response> EnrolMultipleItemsAsync(EnrolItemModel[] _items) {
try {
var result = await PostAsync<Response>("api/inventory/enrolmultipleitems", _items);
Console.WriteLine(result.Message);
return result;
}
catch (Exception ex) {
App.Current.Logger.LogInfo("Exception at InventoryAPI - Error: EnrolItemAsync:");
App.Current.Logger.LogError(ex.Message);
throw ex;
}
}
public Response EnrolMultipleItems(EnrolItemModel[] _items) {
try {
var result = Post<Response>("api/inventory/enrolmultipleitems", _items);
return result;
}
catch (Exception ex) {
App.Current.Logger.LogInfo("Exception at InventoryAPI - Error: EnrolItem:");
App.Current.Logger.LogError(ex.Message);
throw ex;
}
}
private async Task<T> PostAsync<T>(string apiLocation, object postData) {
var response = await client.PostAsync(apiLocation, postData.ToHttpContentString());
T result = default(T);
if (response.StatusCode == HttpStatusCode.OK) {
var json = await (response.Content.ReadAsStringAsync());
result = DeserializeJson<T>(json);
}
return result;
}
private T Post<T>(string apiLocation, object postData) {
var response = client.PostAsync(apiLocation, postData.ToHttpContentString()).Result;
T result = default(T);
if (response.StatusCode == HttpStatusCode.OK) {
var json = response.Content.ReadAsStringAsync().Result;
result = DeserializeJson<T>(json);
}
return result;
}
public T DeserializeJson<T>(string json) {
var parsed = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json);
return parsed;
}
}
I like this style of API and it has worked well in the Xamarin app, so now I wish to port this to Java - and here's where I'm stuck!
Here's what I have so far:
public class APIDownloader extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... ts) {
String url = ts[0].toString();
return Get(url);
}
private String Get(String url) {
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
HttpEntity entity = null;
String result = "";
try {
//Execute and get the response.
HttpResponse response = httpclient.execute(httpget);
entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity);
//final JSONArray jObject = new JSONArray(EntityUtils.toString(entity));
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Catch no internet connectivity exception
e.printStackTrace();
}
return result;
}
}
And then a separate API class:
public class InventoryAPI {
public List<LocationModel> GetAllLocations() throws IOException {
String url = "https://domain.com/api/inventory/getall";
String response = null;// Get(url);
try {
response = new APIDownloader().execute(url).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Gson gson = new Gson();
LocationModel[] mcArray = gson.fromJson(response, LocationModel[].class);
return Arrays.asList(mcArray);
}
}
Whilst the Java code above does work just fine (I've only implemented the GET so far) it does seem like it's going to get out of hand very quickly, especially after I port the POST methods in the C# library to the Java package.
What would be the best approach to replicate the Xamarin API Class I have above in Java?
If you're going to go native Java then do yourself a favor and use Retrofit. That will save you a ton of code in your API layer. Regular Java Http stuff is ugly, Retrofit makes it much easier.
When you get comfortable, look at RxAndroid (RxJava) to really help with some of your Async code.
Related
I'm writing a android chat application with socket.io-client-java.I want to check whether the client user exist at first.So I need to send a command like "user/exist" to server url and get the response from server.I need to wait the server response then can go to next step.But the socket.io use the asynchronous callback.For getting the response synchronous I known the Furture and Callable only.So I tried the way using code as below:
//this is request method using socket.io
public JSONObject request(final String method,final String url,final JSONObject data){
final JSONObject responseObj = new JSONObject();
if (mSocket.connected()) {
mSocket.emit(method, reqObj, new Ack() {
#Override
public void call(Object... objects) {
System.out.println("get Ack");
try {
responseObj.put("body", (JSONObject) objects[0]);
}catch (JSONException e){
e.printStackTrace();
}
}
})
}
}
//this is Callable call implement
#Override
public JSONObject call(){
return request("get","https://my-chat-server/user/exist",new JSONObject());
}
//this is call method in activity
ExecutorService executor = Executors.newCachedThreadPool();
Future<JSONObject> response = executor.submit(mApiSocket);
executor.shutdown();
JSONObject respObj = new JSONObject();
JSONObject respBody = new JSONObject();
try {
respObj = response.get();
respBody = respObj.getJSONObject("body");
}catch (ExecutionException e){
}catch(InterruptedException e1){
}catch(JSONException e2){
}
But it dose not work.The respObj is null.
How can i get the reponse synchronous?
I am a green hand on java and forgive my poor chinese english.
Any help would be appreciated!
I known the js can use Promise and await like below:
//request method
static request(method, url, data) {
return new Promise((resolve, reject) => {
this.socket.emit(method,
{
url: url,
method,
data,
},
async (res) => {
if (res.statusCode == 100) {
resolve(res.body, res);
} else {
throw new Error(`${res.statusCode} error: ${res.body}`);
reject(res.body, res);
}
}
)
})
}
//call method
response = await mSocket.request('get','https://my-chat-server/user/exist', {
first_name: 'xu',
last_name: 'zhitong',
});
I'm not sure this is the best way but we can wait for the callback as follows:
#Nullable
Object[] emitAndWaitForAck(#NotNull String event, #Nullable Object[] args,
long timeoutMillis) {
Object[][] response = new Object[1][1];
Semaphore lock = new Semaphore(0);
socketClient.emit(event, args, ackArgs -> {
response[0] = ackArgs;
lock.release();
});
try {
boolean acquired = lock.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
if (acquired) {
return response[0];
}
} catch (InterruptedException ignored) {
}
return null;
}
Assuming your socket.io server returns one argument containing the body (or null) you would call it something like this:
String method = "get";
String url = "https://my-chat-server/user/exist";
long timeoutMillis = 5000;
Object[] args = emitAndWaitForAck(method, new String[]{url}, timeoutMillis);
JSONObject response = (JSONObject) args[0];
The task is simple, but I want to do it in the right way and I would love to hear your expert advice because I am novice in android developing.
First the application is just for me so I really don't care about security and stuff.
So my objective is like this:
I have a large amount of data that I want to transfer to my MYSQL database, the easiest way for me is to use HTTP POST method, but I am concerned about the part that the application may get stuck or some data won't pass because of the many POST requests that are gonna be.
So how exactly should I pass the data using POST request with insuring that all of the requests will be sent one by one without skipping any or losing data ?
Just the logic behind this would be enough I don't really need the code part.
Hopefully I was clear enough.
Retrofit FTW. Makes networking easy on Android (RESTful) and it include Gson.
Speaking of Gson... You mention you might be making many POSTs? If so, you should probably convert your data to JSON instead, and send it over the network that way. Google's Gson is a fantastic way to easily convert a Java object to JSON.
http://square.github.io/retrofit/
https://github.com/google/gson
Before reading: this is my way for implementing posts and gets, this is not the best way ever, but just the best way for my needs, feel free to edit/not use/implement it yourself
I personally prefer OkHTTP library, it is easy to use and easy to implement.
Implementation is really easy, just add this row in your Gradle app-level
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
Then I created an helper class for get and post calls (I don't need many configurations, so a static one for me was enough, if you need more stuff you can easily implement. Also the timeouts are set for my needs and you can chenge them freely)
private String ConsumeGetRequest(String path) {
int tries = 0;
boolean isMyException = true;
while (tries <= 3 && isMyException) {
try {
isMyException = false;
tries++;
Response response = executeRequestBody(path, null);
if (response != null && response.body() != null)
return response.body().string();
else
return "";
} catch (ConnectException e) {
e.printStackTrace();
if (e.getMessage().contains("Failed to connect to") && tries <= 3) {
isMyException = true;
}
} catch (Exception ex) {
ex.printStackTrace();
return "";
}
}
return "";
}
private Pair<Boolean, String> ConsumePostRequest(String path, String postData) {
int tries = 0;
String errorMsg = null;
boolean isMyException = true;
//you can ignore this while, it was for our internal reasons and it's just a check.
while (tries <= 3 && isMyException) {
try {
isMyException = false;
tries++;
Response response = executeRequestBody(path, postData);
if (response != null && response.body() != null)
return new Pair<>(response.isSuccessful(), response.body().string());
else
return new Pair<>(false, null);
} catch (ConnectException e) {
errorMsg = e.getMessage();
if (e.getMessage().contains("Failed to connect to") && tries <= 3) {
isMyException = true;
}
} catch (Exception ex) {
errorMsg = ex.getMessage();
}
}
return new Pair<>(false, errorMsg);
}
private Response executeRequestBody(String path, String postData) throws IOException {
String url = String.format("%s%s/", RuntimeHelper._baseWebServiceIP, path);
if (okHttpClient == null) {
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.build();
}
Request.Builder builder = new Request.Builder().url(url);
if (postData != null && !postData.isEmpty()) {
RequestBody body = RequestBody.create(RuntimeHelper._okHttpTypeJson, postData);
builder = builder.post(body);
}
Request request = builder.build();
return okHttpClient.newCall(request).execute();
}
with those two methods (a couple of examples) I create my path and I call the proper method for my needs.
//Post
public boolean setAlerts(String postData) {
String path = String.format("api/wfm/v1/set-alerts/%s/%s", authToken, resourceId);
return ConsumePostRequest(path, postData).first;
}
//Post
public String isAlertUpdated(String lastDownloadDate) {
String path = String.format("api/wfm/v1/is-alert-updated/%s/%s", authToken, lastDownloadDate);
return ConsumeGetRequest(path);
}
Then with an AsyncTask you can perform the operation without blocking UI
public class NewAlertAsyncTask extends AsyncTask<String, String, Boolean> {
Context context;
private WebApiMethodsController webApiMethodsController;
AuthenticatedUser authenticatedUser;
public NewAlertAsyncTask(Context ctx) {
this.context = ctx;
authenticatedUser = AuthenticatedUser.getIstance(context);
webApiMethodsController = new WebApiMethodsController(authenticatedUser.getAuthenticationTokenID().toString(), authenticatedUser.getResourceID().toString(), context);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
}
#Override
protected Boolean doInBackground(String... datas) {
Boolean result;
try {
result = webApiMethodsController.setAlerts(datas[0]);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return result;
}
#Override
protected void onPostExecute(Boolean s) {
if(s){
//manage succes, I use this
mCallback.onNewAlertCreated();
}
else{
//manage error
}
}
}
mine is a really simple structure, you can implement it with callbacks, status progress, deeper return status check, ...
You can simply call the asynctask with this
NewAlertAsyncTask newAlertAsyncTask = new NewAlertAsyncTask(getActivity());
newAlertAsyncTask.execute(gson.toJson(alertList));
I'm experiencing a (in my view) really weird problem. I have an Android Project in Android Studio containing the following code:
if(AppSettings.isNetworkAvailable(context, showDialog)) {
return null;
}
else {
HttpResponse httpResponse = null;
AsyncHttpGet asyncHttpGet = new AsyncHttpGet(mHttpClient, mHttpContext);
String url = BASE_URI + atPath;
asyncHttpGet.execute(url);
try {
httpResponse = asyncHttpGet.get();
System.out.println("Response: " + httpResponse);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if(isAccepted(httpResponse)) {
return httpResponse;
} else {
return null;
}
}
This code returns null at runtime and gives no output. The debugger cursor jumps from the first if-clause (which returns true) directly to the last return statement without declaring or initializing any of the variables.
I have also tried removing the else as it should work without it, but that makes no difference. Does anyone have an idea where the problem could be?
EDIT: I should add: the code works just fine without the initial if-clause and returns a valid HttpResponse.
if the AppSettings.isNetworkAvailable(context, showDialog) is true, return null is the correct behaviour.
If you want to enter the else part, use this:
if(AppSettings.isNetworkAvailable(context, showDialog)) {
HttpResponse httpResponse = null;
AsyncHttpGet asyncHttpGet = new AsyncHttpGet(mHttpClient, mHttpContext);
String url = BASE_URI + atPath;
asyncHttpGet.execute(url);
try {
httpResponse = asyncHttpGet.get();
System.out.println("Response: " + httpResponse);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if(isAccepted(httpResponse)) {
return httpResponse;
} else {
return null;
}
}
I have an application in which an Android device is connected to a data acquisition system and the data is stored in a local db. I want to monitor in real time the data on a second Android as well. In order to enhance performance, I set up my own Apache server (XAMPP) on a Windows machine. I wrote two php scripts; one to store data in Memcache and one to get data from memcache. The Android devices are using HttpClient to call the scripts. I used memcache in order to eliminate some delays of writing to database. Below is the code used for sending and receiving the data... For testing, it is a simple loop (counter) with a thread delay. If I set the delay for 1 second, the textview is updated and runs smoothly. When I drop the delay to 0.1 seconds, it runs fine for a few seconds and then stutters (pauses) for 3-5 seconds. It continues this process of intermittent pausing while running. If I drop the delay to 0.01 seconds, the system crashes. My Apache server is connected to directly to my router. The Android devices are connected to my WiFi. My question is whether or not I'm doing something fundamentally wrong. I thought with memcache, I would easily be able to do 0.01 s sampling of data. Is my code properly handling the AsyncTasks? How can I prevent the Android system from apparently becoming "overloaded" with new tasks? It is as if I need a method to determine when a task is complete such that the next task can be called. I appreciate any feedback regarding php, httpclient, etc...anything that affects performance.
EDIT: My system no longer crashes when I drop the delay to 0.01 sec. I now have a catch for the null value in the onpostexecute method. However, I still get stutters/freezes.
private void startsendingdata() {
loop = 0;
if (sendingdatathread != null)
sendingdatathread.interrupt();
sendingdatathread = new Thread() {
public void run() {
while (loop < 5000) {
try {
runOnUiThread(new Runnable() {
#Ov
erride
public void run() {
new SendDataTask().execute();
loop++;
myvar = Integer.toString(loop);
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
};
sendingdatathread.start();
}
private class SendDataTask extends AsyncTask<String, Integer, Double> {
#Override
protected Double doInBackground(String... params) {
postData();
return null;
}
protected void onPostExecute(Double result) {
}
public void postData() {
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
// put all variables here (with connection code attached)
nameValuePairs.add(new BasicNameValuePair("connectioncode",
connectioncode));
nameValuePairs.add(new BasicNameValuePair("myvar", myvar));
httppostsend
.setEntity(new UrlEncodedFormEntity(nameValuePairs));
response = httpclient.execute(httppostsend);
response.getEntity().consumeContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void startgettingdata() {
if (gettingdatathread != null)
gettingdatathread.interrupt();
gettingdatathread = new Thread() {
public void run() {
while (true) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
new GetDataTask().execute();
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
};
gettingdatathread.start();
}
private class GetDataTask extends AsyncTask<String, Integer, Double> {
#Override
protected Double doInBackground(String... params) {
getData();
return null;
}
protected void onPostExecute(Double result) {
if (!line.isEmpty() && line!=null&&connectioncode.length() >= 6) {
tvLapTime.setText("MyVar: " + myvar);
}
}
public void getData() {
if (connectioncode.length() >= 6) {
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("connectioncode",
connectioncode));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
response = httpclient.execute(httppost);
entity = response.getEntity();
is = entity.getContent();
line = convertInputStreamToString(is);
response.getEntity().consumeContent();
} catch (ClientProtocolException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
// convert inputstream to String
private static String convertInputStreamToString(InputStream inputStream)
throws IOException {
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));
String result = "";
while ((line = bufferedReader.readLine()) != null)
result += line;
try {
json = new JSONObject(result);
} catch (JSONException e1) {
e1.printStackTrace();
}
if (json != null) {
try {
myvar = json.getString(connectioncode + "myvar");
} catch (JSONException e) {
e.printStackTrace();
}
}
inputStream.close();
return result;
}
Do away with startsendingdata() and startgettingdata(). In the onPostExecute() of the tasks initiate the start of the next task. Now you are sure a task is finished before starting a new one. For instance you could start a timer which executes the next task.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
And Error's are:
error opening trace file:No Such file or directory(2);
java.lang.IllegalStateException: Manager is shut down. at
org.apache.http.impl.conn.SingleClientConnManager.assertStillUp(SingleClientConnManager.java:174)
org.apache.http.impl.conn.SingleClientConnManager.getConnection(bla
bla bla .java:212)
org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(---.java:190)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:326)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
org.apache.http.impl.client.AbstractHttpClient.xecute(AbstractHttpClient.java:487)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
and more...
public class ReqClass {
public static final String TAG = ReqClass.class.getSimpleName();
//creating new ResClass object
ResClass resp = new ResClass();
//sending request
HttpResponse response;
//making the request - containst (url,header,entity);
HttpPost request;
//New HTTP Client
HttpClient httpClient = new DefaultHttpClient();
//our code in JSON or XML to Send Request
private String s;
//This variable contains the total number of keys
private int size;
// Map
Map<String,String> code = new HashMap<String, String>();
// Adding only Key Value parameters
public void addparametr (String key, String value){
code.put(key,value);
}
public String getS(){
return s;
}
//Adding Key Value and size of new map.
public void addparametr (String key, String value, int nOfValues){
}
public void Build(String lang){
//List Of keys
List<String> keys=new ArrayList<String>(code.keySet());
//k = keys; v = values;
String k="",v="";
// size = size of Map;
size=code.size();
// if we want to make our JSON Code to send Request
if (lang=="json"){
s="";
s+="{";
for (int i=0; i<size; i++){
k=keys.get(i);
v=code.get(k);
if (i==size-1) s=s+'"'+k+'"'+": "+'"'+v+'"';
else s=s+'"'+k+'"'+": "+'"'+v+'"'+',';
}
s=s+"}";
}
if (lang =="xml"){
s="";
s+="<code>";
for (int i=0; i<size; i++){
k=keys.get(i);
v=code.get(k);
s=s+'<'+k+'>'+v+"</"+k+'>';
}
s=s+"</code>";
}
}
// The Send Request Method - need link parameter and our JSON or XML code
public ResClass SendR (String url, String lang){
String valueOfSize = String.valueOf(size);
request= new HttpPost(url);
//adding a Header
request.addHeader("Header - Request Size", valueOfSize);
//adding request's body (Entity)
HttpEntity entity;
try {
entity = new StringEntity(s, "UTF-8");
request.setEntity(entity);
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
BackGroundTask doItInBackGround = new BackGroundTask();
doItInBackGround.execute();
//closing our connection
httpClient.getConnectionManager().shutdown();
return resp;
}
private class BackGroundTask extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
try {
//execute - means sending
response = httpClient.execute(request);
//adding new response to our Response Class
resp.addNewResponse(response);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
Log.e(TAG, "Exception caught: ", e);
}
return null;
}
}
}
You are calling getConnectionManager().shutdown() just after starting AsyncTask so before executing doInBackground method connection is shutdown . so use onPostExecute for close connection as:
protected void onPostExecute(Long result) {
// call shutdown() here
httpClient.getConnectionManager().shutdown();
}