AsyncTask not returning results right away - android

After reading a few posts and reading on the developers page about ASYNCTASK, I came up with the following code, and assigned it to a button:
private class TalkToServerTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String response = "";
try {
InetAddress serverAddr = InetAddress.getByName(params[0]);
Socket s = new Socket(serverAddr, Integer.valueOf(params[1]));
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())), true);
// WHERE YOU ISSUE THE COMMANDS
out.println(params[2]);
// BufferedReader input = new BufferedReader(
// new InputStreamReader(s.getInputStream()));
DataInputStream dataInputStream = null;
dataInputStream = new DataInputStream(s.getInputStream());
st = dataInputStream.readLine().toString();
// String st = s.readLine();
// st = input.readLine();
// read line(s)
s.close();
return st;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
#Override
protected void onPostExecute(String result) {
serverresponse = result;
}
}
The idea being, that when a button is clicked, the ASyncTask sends the word "getDomains" to a console app running on my server, the server acts on this and sends back a string with the list of domains created on an email server.
I have verified that the server is receiving the command "getdomains", and it in turn replies with a pipe-delimited string of domains. The problem being however, that I've set a Toast to pop up with the results of the socket transaction, and the toast shows nothing. If I hit the button again, the Toast shows the list of domains. To me, it seems as if the socket is first returning an empty
Here is the button code:
case R.id.btnDomains:
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(this);
IpAddress = sp.getString("ipaddress", "0.0.0.0");
Serverport = sp.getString("tcpport", "12345");
buttonpressed = "domains";
// TalkToServerTask task = new TalkToServerTask();
new TalkToServerTask().execute(IpAddress, Serverport, "getDomains");
Intent buttonActivity = new Intent(MainActivity.this, Rules.class);
buttonActivity.putExtra(MainActivity.DOMAINLIST, serverresponse);
Toast.makeText(getApplicationContext(), serverresponse,
Toast.LENGTH_SHORT).show();
the variable "serverresponse" is what at first is showing empty, but then shows the list of servers.

As Thepoosh mentioned, AsyncTask is working on a separate thread.
Therefore the thread is being executed and didn't get result yet when you first time press the button.
What you should do is to show the data in onPostExecute method. Also you should pass the context to your AsyncTask.
public TalkToServerTask(Context context) {
this.context = context;
}
#Override
protected void onPostExecute(String result) {
Intent buttonActivity = new Intent(context, Rules.class);
buttonActivity.putExtra(MainActivity.DOMAINLIST, result);
Toast.makeText(context.getApplicationContext(), result, Toast.LENGTH_SHORT).show();
}

You just need to change your code a little,
You need to move this 3 lines,
Intent buttonActivity = new Intent(MainActivity.this, Rules.class);
buttonActivity.putExtra(MainActivity.DOMAINLIST, serverresponse);
// and also the line to startActivity() as well.
Toast.makeText(getApplicationContext(), serverresponse,
Toast.LENGTH_SHORT).show();
from your Switch..case to onPostExecute of the AsyncTask where you have written serverresponse = result
That's because the AsyncTask run in a different thread, while you have executed in Swtich...case it's not like that the next line of code will not get executed untill the AsyncTask finishes, So all dependent code should be written in onPostExecute of the Task.

AsynTask is run on a separate thread from the UI thread. So there are 2 threads running parallel. While you are trying to display the list in a toast on main UI thread, the AsynTask is still preparing to fetch the list, or probably creating sockets in its own thread. Hence the list data is still empty.
The postexecute method of Asynctask is run on the main UI thread, so its safe and correct to update the UI in it.

Related

which operation is exactly blocking the main thread in android

when you make a network connection in Android you are blocking the main thread , so you have to move "some" of this task to a new thread
I have 2 questions on this part
1- which of the following operation is blocking the main thread (A or B)
//A:
HttpURLConnection c = (HttpURLConnection) (new URL(url)).openConnection();
//B:
InputStream stream=c.getInputStream();
2- if "both" of the above (A & B) must run in a new thread , dose it have a bad effect to run each one in a new separate thread? take a look to the following code:
//I temporary removed try & catch to simplify the code
public class connect{
HttpURLConnection c; String url;
public connect(String url){
this.url=url;
new Thread(new Runnable{
#override public void run(){
c = (HttpURLConnection) (new URL(url)).openConnection();
}
});
}
public InputStream get(){
return c.getInputStream();
//or make this one in a new thread
}
public InputStream post(Sring params){
c.setRequestMethod("POST");
//.. make some code for posting data , and then call get()
//thats why i cannot perform c.getInputStram() at the same time with openConnection()
return get()
}
}
which of the following operation is blocking the main thread (A or B)?
It is pretty evident that both operations A and B will block the main thread. Just calling the following on the main thread will throw an exception(NetworkOnMainThreadException) right away:
HttpURLConnection c = (HttpURLConnection) (new URL(url)).openConnection();
Also when you are calling the following line on main thread:
InputStream stream=c.getInputStream();
You are simply trying to read a stream of bytes over a network. Now there are various factors that will determine the time taken by this operation to complete. For instance, network speed, overall number of bytes that you want to read, etc. The application should not really need to wait and stay idle till the reading process has been completed. All the UI related process should be able to run and consume the resources as a user reacts with your application which will not be possible because of the ongoing byte reading process which is actually blocking the main thread.
if both A and B must run in a new thread , dose it have
a bad effect to run each one in a new separate thread?
Technically, yes it is bad to run both in separate threads. Besides why would you want to do so? Before initiating stream reading process you need to make sure that the connection has been opened. Calling A and B in separate threads will raise concurrency issues. You must call B after A so if you even resolve concurrency issues, it will be of no use to make two separate threads.
EDIT:
So as you said in comments that you want to avoid using AsyncTask. An alternative for that is Java Threads. Check out the following sample usage of threads:
static public class MyThread extends Thread {
#Override
public void run() {
try {
// add your url and open connecttion here
HttpURLConnection c = (HttpURLConnection) (new URL("your url here")).openConnection();
// read stream or whatever data you want
InputStream stream = c.getInputStream();
} catch (Exception e) {
e.printStackTrace();
} finally {
//close your connection & wipe input stream here.
}
}
}
Now here is how we can call this thread:
private Thread downloadThread = new MyThread();
downloadThread.start();
At any time, you can also check if your thread is running or not by using the following code:
if (downloadThread != null && downloadThread.isAlive()) {
// do something when thread is alive here
}
This solution uses handler to connect main thread with background thread(the thread that does the HTTP connection stuff)
public class MainActivity extends AppCompatActivity {
Thread mThread;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startThread();
}
public void startThread(){
String url = "www.google.com";
String result = "";
mThread = new Thread(new Runnable() {
public void run() {
InputStream is = null;
HttpURLConnection conn;
try {
ConnectivityManager connMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = null;
if (connMgr != null) {
networkInfo = connMgr.getActiveNetworkInfo();
}
if (networkInfo != null && networkInfo.isConnected() && !mThread.isInterrupted()) {
conn = (HttpURLConnection) url.openConnection();
is = conn.getInputStream();
//Here you get the result from inputStream
}
threadMsg(result);
}catch (IOException e){
e.printStackTrace();
}
finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void threadMsg(String msg) {
if (msg != null && !msg.equals("") && !mThread.isInterrupted()) {
Message msgObj = handler.obtainMessage();
Bundle b = new Bundle();
b.putString("message", msg);
msgObj.setData(b);
handler.sendMessage(msgObj);
}
}
private Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
String result = msg.getData().getString("message");
// What you want to do in UI thread
}
};
});
mThread.start();
}

android asynctask crash when trying to load an heavy page

I'm programming an app with my brother, and today unfortunately, I encountered with a problem.
When the app load a php page via my asynctask class it works fine. but I would like to program this situation: if the remote server is down, or crash, and doesnt display the right page, the application will show error message. but instead, the app crashes =[
I tried to load this page, for example:
http://alonadoni.com/sql3.php
(I want to simulate that there is a problem with the server. the regular page is sql2.php and it works fine when the server works)
When the app try to load this page (sql3.php) , the app crashes.
I did another experiment : I created a file sql3.php, and wrote "aaaaaaaa" in the page, the app doesn't crash in this situation. it downloaded the data "aaaaa". in this case, the app show jsonexecption error.
Unfortunately, I can't get logcat because my old computer can't run emulators, and my phone also can't connect to my computer on developer mode =[ When I try application I create an apk then transfer the file to my phone and install.
my code is:
in OnCreate:
String serverURL = sss() + "sql3.php?imei=" + imei;
new LongOperation().execute(serverURL);
outside OnCreate:
private class LongOperation extends AsyncTask<String, Void, Void> {
private final HttpClient Client = new DefaultHttpClient();
private String Error = null;
protected void onPreExecute() {
}
protected Void doInBackground(String... urls) {
try {
HttpGet httpget = new HttpGet(urls[0]);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
data[x] = Client.execute(httpget, responseHandler);
} catch (ClientProtocolException e) {
Error = e.getMessage();
Toast.makeText(getApplicationContext(),"error2" , Toast.LENGTH_LONG).show();
cancel(true);
} catch (IOException e) {
Error = e.getMessage();
Toast.makeText(getApplicationContext(),"error34" , Toast.LENGTH_LONG).show();
cancel(true);
}
return null;
}
public void onPostExecute(Void unused) {
if (Error != null) {
} else {
try {
JSONObject json = new JSONObject(data[x]);
name = json.getString("name");
} catch (JSONException e) {
Toast.makeText(getApplicationContext(),"e" + e, Toast.LENGTH_LONG).show();
}
}
x++;
}
}
DoInBackground of asynctask needs to contain only NON UI work , hence referring to context and performing UI operations in UI thread may cause crash.
You can perform UI operations in postexecute of asynctask.
Hence Removing toast from above code which refers to UI operation will solve your issue

AsyncTask hangs on at beginning

AsyncTask works fine in Android 4.x, but not for Android 2.3.6. I've step-by-step debugged Android 2.3.6 with a physical mobile device.
It hangs on here:
myTask = new GetDataFromServer();
GetDataFromServer is the class of AsyncTask.
What's going on?
Here under is my code, I only used 1 AsyncTask in my code and received messages from server.
that's all.
class GetDataFromServer extends AsyncTask<String, String, String>
{
protected void onPreExecute ()
{
progressDialog1=ProgressDialog.show(MainActivity.this, "Loading data", "Please wait...",true);
}
protected String doInBackground(String... params)
{
String resulttxt="";
try {
serverIp = InetAddress.getByName("192.168.1.123");
int serverPort=31000;
Socket clientSocket=new Socket(serverIp,serverPort);
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write(params[0]);
bw.flush();
BufferedReader br=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
resulttxt=br.readLine();
if(resulttxt.contains("OK"))
{
publishProgress(resulttxt);
}
else
{
publishProgress(resulttxt);
clientSocket.close();
bw.close();
br.close();
return null;
}
resulttxt="";
resulttxt=br.readLine();
resulttxt=resulttxt.trim();
clientSocket.close();
} catch (IOException e) {
if(Status_txt!=null)
Status_txt.append( "Server is done.");
}
catch (NetworkOnMainThreadException e){
if(Status_txt!=null)
Status_txt.append( "NetworkOnMainThreadException");
}
return resulttxt;
}
protected void onProgressUpdate(String...inStr){
String[] strData=inStr[0].split("_");
String szTemp="Last Purchase Date: ";
szTemp+=strData[1];
szTemp+=" ,Valid days: ";
szTemp+=strData[2];
//Status_txt.setText(szTemp);
if(Status_txt!=null)
Status_txt.setText("You Are The Super User");
}
protected void onPostExecute(String data) {
tl_prediction2.removeAllViews();
if (data == null)
{
}
else {
if((data.contains("#")==true) || (data.contains("*")==true)
||data.contains("&")==true)
{
String[] arrayTmp=data.split("#");
for(Integer i=0;i<arrayTmp.length;i++)
{
String[] SubArrayTmp=arrayTmp[i].split("_");
tl_prediction2.addView(generateRow(4,SubArrayTmp));
}
}
}
progressDialog1.dismiss();
}
};
Since you haven't posted any code, I could only give you some random probable solutions:
May be your AsyncTask is taking a lot of time to download. Trying increasing its priority using android.os.Process.setThreadPriority(9) inside doInBackground()
Check if you have other previous running long AsyncTask in your code. AsyncTask by default operates on a single background thread. That means your AsyncTask task wouldn't be executed unless your previous AsyncTask are done. To allow parallel execution use executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params). You can read more here
Check for Internet and other permissions in Manifest. This is mostly where people make mistake.
AsyncTask works with ThreadPool. If there too many synctasks are executing, the later AsyncTask will be blocked by others. I think you can use the thread tool in DDMS to check the How many ayncTasks are executing.

Http Response inside a service in Android

Hi I have a service in Android that handles the HTTP method POST as specified below. Now, I need to call an Intent in
replaceResourceSegment()
method. It has a handler that takes nearly 90 seconds to complete the task. Within that time, control exits the handler block. But I want my program to continue within handler for POST. In short, I want my service to pause for sometime inside the POST handler, till my Intent (with handler) completes its execution and I need to delay sending the response of HTTP Post. Can some one guide me how to do this implementation?
if(method.equals("POST"))
{
conn.receiveRequestEntity((HttpEntityEnclosingRequest)request);
HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
String content_type = ""+entity.getContentType();
JSONReceived = EntityUtils.toString(entity);
if(content_type.contains("json"))
{
Log.d(TAG,"Content received is: "+JSONReceived);
bufferedWriter = new BufferedWriter(new FileWriter(new File(getFilesDir()+File.separator+constants.UPDATED_SCRIPT_FILE)));
bufferedWriter.write(JSONReceived);
bufferedWriter.close();
try {
parseJSON(JSONReceived);
replaceResourceSegment(); //Call to an intent with startActivityForResult()
continueExecution(); //Continue the execution from here
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG,"IOException line 157");
}
Code for sending response back:
HttpResponse postResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
postResponse.setEntity(new StringEntity("Got it"));
conn.sendResponseHeader(postResponse);
conn.sendResponseEntity(postResponse);
I managed to solve the problem by using a boolean variable with default value false. It will be checked periodically and keeps the control inside the POST method's handler.
android.os.SystemClock.sleep(30000); //Sleeps for 30 seconds and invoke busy waiting in a thread
Thread syncThread = new Thread(new LoopCheck());
syncThread.start();
synchronized(syncThread)
{
Log.d(TAG,"Inside synchronized blockk");
try
{
syncThread.wait();
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
The thread class is defined as below:
class LoopCheck extends Thread{
public LoopCheck(){
}
public void run(){
while(true)
{
try {
Thread.sleep(10000);
if(write)
{
write = false;
synchronized(syncThread)
{
syncThread.notify();
}
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Screen Halt while Communication(Client/Server) in Android

I have an application in which there is Google map, location overlays on Google map and a separate thread which send the current location of device to server after every 30 seconds. The problem is that when the thread sends the location to server the screen of device halted until the server respond. Here is the following code,
Global Object
private Handler handlerTimer = new Handler();
In onCreate Method
handlerTimer.removeCallbacks(taskUpdateStuffOnDialog );
handlerTimer.postDelayed(taskUpdateStuffOnDialog , 100);
And here is the taskUpdateStuffOnDialog
private Runnable taskUpdateStuffOnDialog = new Runnable()
{
public void run()
{
try
{
URL url3 = new URL("http://"+ appState.getURL()+"//iLocator/IDForClient.php?reg_no="+ Device_ID[0]);
HttpURLConnection conn = (HttpURLConnection) url3.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String quote = reader.readLine();
while (quote != null)
{
Device_ID = quote.split("\n");
quote = reader.readLine();
bCheckID = true;
}//End While
positionOverlay.setID(Device_ID[0]);
addEvent(Device_ID[0]);
}//End try
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(MainMapActivity.this, "Communication Issue",Toast.LENGTH_LONG).show();
}//End catch
handlerTimer.postDelayed(this, 9000);
}
};
Please tell me what is wrong with my code.
The problem is that, although you're spawning a new Thread, you aren't spawning a new process. Everything you're doing is still in the user interface process, and that's blocking. You can find more information on the topic on developer.android.com.
The quickest and easiest way to get around this is using the IntentService class. It will only allow one HTTP request to be executed at a time, but will take care of all the problems for you.
Try using the AsyncTask for connecting to the Server. See an example here: http://developer.android.com/reference/android/os/AsyncTask.html

Categories

Resources