I am developing an android application, I am new to thread and i apologize if my question is stupid, I used AsyncTask`s doInBackground method for converting Stream to String and then in onPostExecute method,app will begetting JSON Object.
I launched my application in Emulator (API 17) and it launched prefect but when I am launching it on my smart phone (galaxy s5) it is taking too long,maybe 10 or 15 seconds.
I think doInBackground method is causing this problem.
This is my Main Class and doing all here :
This is where i call my Asynctask Class and send a parameter with POST method :
final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("register_number", phoneNumber.getText().toString()));
Log.i("LOG", "params hastttttttttt" + params.toString());
//
// Commands.readRegisterNumber(params);
// new readData().execute(params);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
new readData().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
} else {
new readData().execute(params);
}
I define my Asynctask class here :
private class readData extends AsyncTask<List<? extends NameValuePair>, Void, String>
doInBackground method of Asynctask Class :
#Override
protected String doInBackground(List<? extends NameValuePair>... params) {
List<? extends NameValuePair> param = params[0];
try {
HttpClient client = new DefaultHttpClient();
HttpPost method = new HttpPost("http://192.168.10.110:2233/api/register");
method.setEntity(new UrlEncodedFormEntity(param));
HttpResponse response = client.execute(method);
InputStream inputStream = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder builder = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
builder.append(line);
}
result = builder.toString();
}
catch (IOException e) {
e.printStackTrace();
}
return result;
}
and here is onPostExecute method :
#Override
protected void onPostExecute(String result) { //doInBackground khorujish ro mide be in
if (result != null) {
try {
G.registerNumber.clear();
JSONObject object = new JSONObject(result);
StructRegisterNumber structRegisterNumber = new StructRegisterNumber();
structRegisterNumber.status = object.optString("status");
structRegisterNumber.code = object.optString("code");
structRegisterNumber.message = object.optString("message");
G.registerNumber.add(structRegisterNumber);
StructRegisterNumber registerNumber = G.registerNumber.get(0);
if (registerNumber.status != null && registerNumber.code != null) {
if (Integer.parseInt(registerNumber.status) == -1) {
Intent intent = new Intent(ActivityRegisterNumber.this, ActivityRegisterCode.class);
ActivityRegisterNumber.this.startActivity(intent);
}
}
progressDialog.dismiss();
}
catch (JSONException e) {
e.printStackTrace();
}
} else {
progressDialog.dismiss();
}
}
There are many reason why it may be slow on a real device:
On a real device network speed will depend on the available wifi/network range and is more susceptible to packet loss.
On a real device multiple applications will be running simultaneously and background thread has lower priority than services and other applications. I would recommend using SDK tool Systrace (with sched option) to see CPU cycles received by the background thread.
This is not exactly solving your problem but as you are simply loading data from the network in your AsyncTask you should consider using a networking library such as Volley which makes live a lot easier. They even have support for Gson that can automatically parse your returned Json to objects automatically.
Documentation:
https://developer.android.com/training/volley/index.html
Library itself:
https://android.googlesource.com/platform/frameworks/volley
Related
I've class with methods
class Wrapper {
public static String AuthIn(String Login, String Password){
String response = HTTPRequest.POST(client, GetAuthUrl(), RequestBuilder.AuthInVk(login, password));
System.out.println(response);
}
public static String GetInfoUser(){
String response = HTTPRequest.GET(client, "http://site1.com");
System.out.println(response);
}
}
When i call this methods in MainActivity class and get error message "Main thread ..... etc"
How write Wrapper class in AsyncTask ?
Here is a nice example taken from codexpedia, for more details please check their site.
public class MainActivity extends AppCompatActivity {
TextView tvWeatherJson;
Button btnFetchWeather;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvWeatherJson = (TextView) findViewById(R.id.tv_weather_json);
btnFetchWeather = (Button) findViewById(R.id.btn_fetch_weather);
btnFetchWeather.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new FetchWeatherData().execute();
}
});
}
private class FetchWeatherData extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
URL url = new URL("http://api.openweathermap.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7&appid=2de143494c0b295cca9337e1e96b00e0");
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
return forecastJsonStr;
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
tvWeatherJson.setText(s);
Log.i("json", s);
}
}
}
If you want to pass data into the async task doInBackground or onPostExcute and more check this stackoverflow comment : what-arguments-are-passed-into-asynctaskarg1-arg2-arg3
Keep in mind that your AsyncTask won't stop even when the activity has destroyed. A better way to create a network call from an activity is with an Handler Or just use an asyncHttp client lib such as ok-http , google volley :)
You always must perform network request form other thread than UI thread. So you can create abstarct class (network dispatcher) which extend AsyncTask or Thread or Runnable and add abstarct method which will be called in run/doInBackground/etc. Next implement abstarct method in your method. But it a little improvement to your boilerplate code. Also you can use JavaRx (AndroidRx) to perform networking method. Also you can use Retrofit with JavaRx.
EDIT
I see you edit your question. If you want use AsyncTask you should implement it and perform request in doInBackgroud
I wrote a Restful WCF service and it is deployed on IIS. I have been attempting to consume the WCF Service using a AsyncTask Thread. I built the thread in to the main UI class so that I can update the GUI.
public class ServiceRunning extends AsyncTask<String, Void, String>{
private Exception exception;
String line = "";
public void setLine(String line)
{
this.line = line;
}
public String getLine()
{
return line;
}
#Override
protected String doInBackground(String... url) {
try
{
DefaultHttpClient httpClient = new DefaultHttpClient();
URI uri = new URI(url[0]);
HttpGet httpget = new HttpGet(uri);
httpget.setHeader("Accept", "application/json");
httpget.setHeader("Content-type", "application/json; charset=utf-8");
HttpResponse response = httpClient.execute(httpget);
HttpEntity responseEntity = response.getEntity();
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
// while ((line = rd.readLine()) != null) {
// Log.d("****Status Line***", "Webservice: " + line);
// }
while((line = rd.readLine()) != null)
{
setLine(line);
Log.d("****Status Line***", "Webservices: " + getLine());
}
}
catch (Exception e)
{
e.printStackTrace();
}
return "String :" + line;
}
protected void onPostExecute(String result) {
TextView txt = (TextView)findViewById(R.id.textView1);
txt.setText(getLine());
}
}
In the code, I write the response to a String and I attempt to display it after execution. For some resound, when I run the program I don't get the response, I get a blank TextView but the message displays in the Eclipse LogCat. I cant find the problem, what causes this?
AsyncTask is tied to the activity kicking it off. If you rotate the device or the app goes into the background, is added or removed from a dock, the original activity is destroyed. The AsyncTask continues though and responds to the original activity that is no longer visible.
You are better off using an IntentService or Service to call web services, it is a much more reliable pattern.
Hey all I am writing an android aplication which gets a JSON object from a node.js server. My code is below (I do not have access to the server code). Is there any way to consistently check the server for a change in the JSON object (if they update it)? Right now it only does one GET and stops. I want to be able to query for a change and continue working with the new updates. Thoughts? Thanks.
Called from OnCreate():
new Read().execute("JSONkey");
Here is my Read ASyncTask:
public class Read extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String...param) {
try {
read_json = getCoords();
httpText.append(read_json.toString() + "\n");
try{
}catch(Exception e){ e.printStackTrace(); }
JSONArray data = read_json.getJSONArray(param[0]);
for (int i = 0; i < data.length(); ++i){
JSONObject info = data.getJSONObject(i);
Coordinate pt = new Coordinate(info.getInt("point"), info.getString("name"), info.getDouble("lat"), info.getDouble("long"));
coords.put(pt.getPoint(), pt);
coordList.add(new GeoPoint(pt.getLat(),pt.getLong()));
}
return "Success"; //get "text"
} catch (Exception e){
return "Fail";
}
}
#Override
protected void onPostExecute(String result){
//Doing something with JSON
//new Read().execute("coords"); tried doing this, but I feel it is not right.
}
}
and the GetCoords():
public JSONObject getCoords()
throws ClientProtocolException, IOException, JSONException{
StringBuilder url = new StringBuilder(URL);
HttpGet get = new HttpGet(url.toString());
HttpResponse response = client.execute(get);
int status = response.getStatusLine().getStatusCode();
if(status == 200){
HttpEntity entity = response.getEntity();
String data = EntityUtils.toString(entity);
JSONObject last = new JSONObject(data);
return last;
}else{
return null;
}
}
The proper way to do this is with a WebSocket but given the constrain of not being able to control the server side, your best bet is to
Put your code inside a service:
http://developer.android.com/reference/android/app/IntentService.html
Then use the Alarm Manager to schedule periodic updates.
http://developer.android.com/reference/android/app/AlarmManager.html
This question already has answers here:
NetworkOnMainThreadException [duplicate]
(5 answers)
Closed 8 years ago.
I'm trying to get data from my server using JSON and put the retrieved data to arrays
this is the fonction to retrieve category,intitule,id_news,images
public void getNewsFromServer(int beg){
InputStream is = null;
String result = "";
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("beg", Integer.toString(beg)));
try {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(strURL);
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();
}
// conversion of the query into string
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is,
"iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
Toast.makeText(context, e.toString(),Toast.LENGTH_LONG).show();
}
try {
JSONArray jArray = new JSONArray(result);
for (int i = 0; i < jArray.length(); i++) {
JSONObject json_data = jArray.getJSONObject(i);
id_news[i] = Integer.toString(json_data.getInt("id_news"));
categorie[i] = json_data.getString("categorie");
intitule[i] = json_data.getString("intitule");
image[i] = json_data.getString("image");
}
}catch (Exception e){
Toast.makeText(context, e.toString(),
Toast.LENGTH_LONG).show();
}
}
And this the MainActivity.java
String [] id_news= new String [20];
String [] categorie= new String [20];
String [] intitule= new String [20];
String [] image= new String [20];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
try{
//get data from the server and put it in tables
getNewsFromServer(beg);
}catch(NullPointerException e)
{
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
e.getStackTrace();
}
}
but i always get NULLPointerException
help please
these the logCat trace
this the initialisation of the context Context context = this;
but it generate another exceptions NetworkOnMainThreadException and NullPointerException and JSONException:End of input at character 0..
The NPE comes from Toast initialization. Make sure the context you pass there is not null.
Since you use the toasts in exception catch blocks, log the exception stacktraces with e.g. e.printStackTrace() to get a hold on the root cause. (Prime suspect: NetworkOnMainThreadException)
For NetworkOnMainThreadException, do your network ops on a background thread. See How to fix android.os.NetworkOnMainThreadException? for more.
In your call to Toast, the context variable is most likely null.
Never catch a NullPointerException. Make sure it never gets thrown.
As laalto points out the NPE is coming in Toast statement.
Can you give a code snippet of how you have initialized context.
Also try using getActivity() there once and see if it solves the issue.
If it does then override onAttach() and initialize your context inside it. As directly giving getActivity() is not a good practice.
NetworkOnMainThreadException is caused because you should make network calls on a separate thread.
use something like:
Thread thread = new Thread()
{
#Override
public void run() {
try {
//your network calls here
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
i fixe the problem by using the AsynkTask
private class Asyn_GetNewsFromServer extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
getNewsFromServer(beg);
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
//do what ever you want
}
}
thx for your help
I have an asynctask which gets its data through php. The asynctask works fine, it passes the values to a global arraylist. However, when i try to call the variable on onCreate after .execute(), it returns a null size/value(s). I would like to know why this global variable returns a null when its supposed to have a value. Thanks in advance!
this is the code for asyntask:
private class get_pendingreq extends AsyncTask<String, Integer, String>
{
#Override
protected String doInBackground(String... arg0)
{
InputStream is = null;
String result = "";
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url+"pending_requests.php");
List<NameValuePair> parameter = new ArrayList<NameValuePair>();
parameter.add(new BasicNameValuePair("email", globalVariables.accountemail));
httppost.setEntity(new UrlEncodedFormEntity(parameter));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e)
{
Log.e("log_tag", "Error in http connection " + e.toString());
}
try
{
BufferedReader reader = new BufferedReader(
new InputStreamReader(is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e)
{
Log.e("log_tag", "Error converting result " + e.toString());
}
return result;
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
try
{
/* JSON parsing starts here */
JSONObject jArray = new JSONObject(result);
/*globalVariables.pendingdate = new ArrayList<String>();*/
JSONArray request = jArray.getJSONArray("request");
for (int i = 0; i < request.length(); i++)
{
JSONObject e = request.getJSONObject(i);
/* puts values to arraylist<String> */
globalVariables.pendingdate.add(e.getString("date"));
}
Log.d("striiing", globalVariables.pendingdate.toString());
} catch (JSONException e)
{
e.printStackTrace();
}
}
}
Main activity:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.calendar);
new get_pendingreq().execute();
System.out.print("alalala" + globalVariables.pendingdate.size());
}//this returns null
Global Variable:
public static ArrayList<String> pendingdate = new ArrayList<String>;
Because AsyncTask not finished. Put System.out.print("finish"); in onPostExcute() and see who is printed first.
The idea behind an AsyncTask is that it runs asynchronously from the main thread, thus on a background thread. That way it doesn't block the execution of any code on the main thread.
Knowing that, the following lines will execute right after each other:
new get_pendingreq().execute();
System.out.print("alalala" + globalVariables.pendingdate.size());
Your get_pendingreq class will not do any actual work until after a small delay, meaning that after calling the first lines in above snippet, nothing has really happened. You've only instructed the platform to start the async task somewhere in the near future.
Now, the globalVariables.pendingdate field you're accessing on the second line will not have any values until the async task finishes its work. That doesn't happen until onPostExecute() is executed. In other words: you're trying to print the values at the wrong moment in time.
Simply move that print to the end of the async task's onPostExectute() method (but obviously before the return - why's that even there at all?).
I highly recommend you have a read through the AsyncTask class documentation and the Processes and Threads article.
It is clear form the name indeed AsyncTask runs Asynchronously ...
Let me explain taking your code into consideration:
new get_pendingreq().execute();
This line will create a new thread for execution and it will run
asynchronously and so the next line(i.e.System.out.print("alalala" +
globalVariables.pendingdate.size());) gets executed immidiatly after this line without waiting the async task to get executed completly.so put this system.print line inside
the post execute method...
Are u sure, that globalVariables.pendingdate.add(e.getString("date")); realy have field "data" ?