I have a worker thread that runs in an infinite loop. If it's queue of http requests is empty it waits. As soon as a http request is added to the queue it gets notified and executes this http request. This works all fine but I have some questions on this:
I'm doing it something like this (shortened!):
mHttpClient = new DefaultHttpClient();
mHttpPost = new HttpPost(MyHttpClient.getAbsoluteUrl(url);
while (true)
{
// Check if the queue is empty, if so -> wait
StringEntity se = new StringEntity(queue.poll());
mHttpPost.setEntity(se);
HttpResponse response = mHttpClient.execute(mHttpPost);
}
The question is: is this the most efficient way to do it if the queue has like 100 items? Does the http connection remain open all the time or does it get connected again and again? And if it remains open, is it a good idea to leave it open all the time when the app is running, or should I close it until new items are added to the queue?
The second question is concerning the infinite loop. I need the thread to run all the time when the app is running but the still the infinite loop doesn't look nice. I know I could make something like: while(!cancelled) but I don't call a thread.cancel() method anyway because I mean there is no App.onDestroy() event where I could call thread.cancel(), right? How would you handle that? Because I'd actually want to save the queue to "disk" when the thread is killed by the system but how can this be done?
Sorry for the long text and my bad english
Related
I'm feeling frustrating. After few day, I raise the white flag and ask for help.
I've used this code sample:
https://github.com/sht5/Android-tcp-server-and-client
But every time I try to establish a connection the memory uses is increased by about 500KB, so if the client disconnects and then reconnects without closing the application after many attempts the memory becomes saturated.
I have already tried various methods including
cancel (true) in AsyncTask's doInbackground,
close and force the socket and in, out objects to null
call System.gc ()
but none of this worked.
I'm not sure, but try to invoke AsyncTask as
new InitTCPClientTask().execute(new Void[0]);
instead of
InitTCPClientTask task = new InitTCPClientTask();
task.execute(new Void[0]);
How can I check whether Volley gets the results of a JsonObjectRequest from the cache or from the network?
I need to show a progress dialog when it needs a network connection but not when the results are quickly received from the cache.
my request looks something like this
volleyQueue = Volley.newRequestQueue(this);
JsonObjectRequest jr = new JsonObjectRequest(Request.Method.POST, url, null, new Response.Listener<JSONObject>(){...stuff}, new Response.ErrorListener(){...errorstuff});
jr.setShouldCache(true);
volleyQueue.add(jr);
I did this by overriding Request#addMarker and checking for a "cache-hit" marker being added:
public class MyRequest<T> extends Request<T> {
protected boolean cacheHit;
#Override
public void addMarker(String tag) {
super.addMarker(tag);
cacheHit = false;
if (tag.equals("cache-hit")){
cacheHit = true;
}
}
}
Before making the Request you can get the cache from the Request Queue and check if the Entry is not null.
mRequestQueue.getCache().get("key");
The key for each request is usually the URL.
I guess you should have to check if the Entry has expired too.
Volley has a built in way to know if image requests are immediate through the ImageContainer class, but it doesn't seem to have a similar mechanism for other requests such a JSON object request.
It seems that you have 2 main choices:
You can set a timer for something like 300ms after you request the JSON (test for the best time). When the timer is done, check to see if you have the result already, otherwise show the dialog. I know this is a bit of a "hack" but it could be good enough.
Edit the Volley code to add an "isImmediate" flag to every request. There are multiple ways to achieve this. I suggest starting at CacheDispatcher
Starting from Tim Kelly's answer.
by the time you check "cacheHit", it'll be reverted to false and you'll not know that it's a cache hit because many other tags are received after "cacheHit" is received and before the "onResponse" is called.
So, add
if(tag.equals("network-http-complete")){
cacheHit = false;
}
and remove cacheHit = false;
adb shell setprop log.tag.Volley VERBOSE
Run this command in your terminal, you may need to set 'adb' in your path in order to use that command, it should be located in your sdk/platform-tools/ dir.
This will provide much more detailed volley logs and will show something along the lines of an execution stack for a volley request which exhibits cache hits or misses.
I want to create an autoCompleteTextview with the suggestion from the web-service. On text change I call the web service with the text entered.
public String searchpalace_Searchtext(String serchtext)
{
String resultString = "";
try {
String searchtext = URLEncoder.encode(String.valueOf(serchtext), "UTF-8");
HttpClient Clientloc = new DefaultHttpClient();
String URL = baseUrl + "places?name=" + searchtext;
HttpGet httpget = new HttpGet(URL);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
resultString = Clientloc.execute(httpget, responseHandler);
}
catch (Exception e) {
resultString = "";
}
return resultString;
}
This function is called from the asyncTask when reach character is entered or deleted. Now when the text is entered fast the I want to cancel the pending request when the new request is arrived. How can I cancel the previous request?
You can go through each queued task and call the cancel() method. Check if the task was cancelled using isCancelled(). Do not trigger async tasks for every change in the text box. You can introduce a small delay to avoid unnecessary creation of AsyncTask objects.
You can use Android volley network tool kid for cancel the HttpRequest,
If HttpClient.execute() can be interrupted, AsyncTask.cancel(true) will do it if you pass (true). The docs don't say if it's interruptable or not, experiment.
If it doesn't then you may need to investigate the toolkit suggested in another answer.
Anyway you can check isCancelled() and not apply the result. Probably not a huge overhead once the connection has been started.
Note that, depending on Android version, sometimes multiple AsyncTasks can run in parallel (donut - honecomb) and sometimes they only run one at a time and queue up (honeycomb onwards). You can change the thread executor to allow them to run in parallel, see the AsyncTask class docs, but this will affect the rest of your app too.
Also note you're not allowed to re-use an AsyncTask once it's been run.
Fairly new to Android and created/tested my app using Android 2.3.5 (Gingerbread). I have multiple database connections I used HTTP Post (but did not use AsyncTask) and everything worked great. I then tested it on Android 4.0.3 (Ice Cream Sandwhich) and I'm not able to connect to the database, therefore my app does not work.
Wondering what do I need to consider to allow this working app to run on Ice Cream Sandwhich? I did move the database connection out of the UI Thread (but not AsyncTask) and it still does not connect.
Here is my class I created outside of my UI Thread:
public class InputsRecapGetTask {
public InputsRecapGetTask(InputsRecap activity,
ProgressDialog progressDialog) {
this.activity = activity;
this.progressDialog = progressDialog;
getDatabase();
}
public void getDatabase() {
// TODO Auto-generated method stub
progressDialog.show();
// create new default httpClient
HttpClient httpclient = new DefaultHttpClient();
// create new http post with url to php file as pararmenter
HttpPost httppost = new HttpPost(
"http://test.com/returnBBD.php");
// assign input text to strings
user = Login.userStatic;
Did you examine the logs? IIRC, Android 4 requires that http requests are not done from the main thread. There must be a message telling this.
On the other hand, please keep in mind that
if you turn the screen, the Activity that created the AsyncTask may
be removed from the screen (forever) and replaced by another
Activity; it (the 1st Activity) will receive the result, but will not show anything;
in Android 4, all AsyncTasks are by default serviced by a single
thread; this guarantees that responses arrive in the order the
requests are made, but also means that the 2nd request will start only after the
1st one finishes (or times out).
According to MVC, the data retrieval must be done by the model, not by the controller (Activity) whose lifetime is that of a View.
I'm trying to connect a USB-Device ( build by myself ) to communicate with my development board ( ODROID-X )
Unfortunately, the examples are very little, as far as the asynchronous communication. I'd some problems with the interrupt driven data exchange - how to build the connection by using the asynchronous interrupt mode?
In one direction, the transmission was possible ... but in both it doesn't work. Is there an example like this:
send a ByteBuffer with endpoint_OUT
get a message from device on endpoint_IN
both in interrupt mode.
Thanks a lot for your support.
Hardy
Perhaps I am misunderstanding the question here.
The sample missile lanucher app that is part of the API package from level 12 onwards uses the queue() and requestWait() methods to handle interrupt type endpoints.
Requests are either In or Out and depend on the direction of the EndPoint.
The code for a pretty noddy request->reply looks something like this. You would want to structure real code differently but this gives you the gist of what needs to happen (I hope)
public void run() {
int bufferMaxLength=mEndpointOut.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferMaxLength);
UsbRequest request = new UsbRequest(); // create an URB
request.initialize(mConnection, mEndpointOut);
buffer.put(/* your payload here */;
// queue the outbound request
boolean retval = request.queue(buffer, 1);
if (mConnection.requestWait() == request) {
// wait for confirmation (request was sent)
UsbRequest inRequest = new UsbRequest();
// URB for the incoming data
inRequest.initialize(mConnection, mEndpointIn);
// the direction is dictated by this initialisation to the incoming endpoint.
if(inRequest.queue(buffer, bufferMaxLength) == true){
mConnection.requestWait();
// wait for this request to be completed
// at this point buffer contains the data received
}
}
}
If you are actually looking for a way to run this IO in an asynchronous manner without binding a thread to it, then I think you need to consider using the DeviceConnection.getFilehandle() method to return a standard file handle which in theory you can then use as if it were any other file type resource. I would note however that I have not tried this.
If neither of these addresses the issue please revise the question to clarify what you are struggling to find examples of.
I hope this helps.