Related
I got an error while running my Android project for RssReader.
Code:
URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
And it shows the below error:
android.os.NetworkOnMainThreadException
How can I fix this issue?
NOTE : AsyncTask was deprecated in API level 30.
AsyncTask | Android Developers
This exception is thrown when an application attempts to perform a networking operation on its main thread. Run your code in AsyncTask:
class RetrieveFeedTask extends AsyncTask<String, Void, RSSFeed> {
private Exception exception;
protected RSSFeed doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
} catch (Exception e) {
this.exception = e;
return null;
} finally {
is.close();
}
}
protected void onPostExecute(RSSFeed feed) {
// TODO: check this.exception
// TODO: do something with the feed
}
}
How to execute the task:
In MainActivity.java file you can add this line within your oncreate() method
new RetrieveFeedTask().execute(urlToRssFeed);
Don't forget to add this to AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET"/>
You should almost always run network operations on a thread or as an asynchronous task.
But it is possible to remove this restriction and you override the default behavior, if you are willing to accept the consequences.
Add:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
In your class,
and
Add this permission in the Android manifest.xml file:
<uses-permission android:name="android.permission.INTERNET"/>
Consequences:
Your app will (in areas of spotty Internet connection) become unresponsive and lock up, the user perceives slowness and has to do a force kill, and you risk the activity manager killing your app and telling the user that the app has stopped.
Android has some good tips on good programming practices to design for responsiveness:
NetworkOnMainThreadException | Android Developers
I solved this problem using a new Thread.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
The accepted answer has some significant downsides. It is not advisable to use AsyncTask for networking unless you really know what you are doing. Some of the down-sides include:
AsyncTask's created as non-static inner classes have an implicit reference to the enclosing Activity object, its context, and the entire View hierarchy created by that activity. This reference prevents the Activity from being garbage collected until the AsyncTask's background work completes. If the user's connection is slow, and/or the download is large, these short-term memory leaks can become a problem - for example, if the orientation changes several times (and you don't cancel the executing tasks), or the user navigates away from the Activity.
AsyncTask has different execution characteristics depending on the platform it executes on: prior to API level 4 AsyncTasks execute serially on a single background thread; from API level 4 through API level 10, AsyncTasks execute on a pool of up to 128 threads; from API level 11 onwards AsyncTask executes serially on a single background thread (unless you use the overloaded executeOnExecutor method and supply an alternative executor). Code that works fine when running serially on ICS may break when executed concurrently on Gingerbread, say if you have inadvertent order-of-execution dependencies.
If you want to avoid short-term memory leaks, have well-defined execution characteristics across all platforms, and have a base to build really robust network handling, you might want to consider:
Using a library that does a nice job of this for you - there's a nice comparison of networking libs in this question, or
Using a Service or IntentService instead, perhaps with a PendingIntent to return the result via the Activity's onActivityResult method.
IntentService approach
Downsides:
More code and complexity than AsyncTask, though not as much as you might think
Will queue requests and run them on a single background thread. You can easily control this by replacing IntentService with an equivalent Service implementation, perhaps like this one.
Um, I can't think of any others right now actually
Upsides:
Avoids the short-term memory leak problem
If your activity restarts while network operations are in-flight it can still receive the result of the download via its onActivityResult method
A better platform than AsyncTask to build and reuse robust networking code. Example: if you need to do an important upload, you could do it from AsyncTask in an Activity, but if the user context-switches out of the app to take a phone call, the system may kill the app before the upload completes. It is less likely to kill an application with an active Service.
If you use your own concurrent version of IntentService (like the one I linked above) you can control the level of concurrency via the Executor.
Implementation summary
You can implement an IntentService to perform downloads on a single background thread quite easily.
Step 1: Create an IntentService to perform the download. You can tell it what to download via Intent extras, and pass it a PendingIntent to use to return the result to the Activity:
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
public class DownloadIntentService extends IntentService {
private static final String TAG = DownloadIntentService.class.getSimpleName();
public static final String PENDING_RESULT_EXTRA = "pending_result";
public static final String URL_EXTRA = "url";
public static final String RSS_RESULT_EXTRA = "url";
public static final int RESULT_CODE = 0;
public static final int INVALID_URL_CODE = 1;
public static final int ERROR_CODE = 2;
private IllustrativeRSSParser parser;
public DownloadIntentService() {
super(TAG);
// make one and reuse, in the case where more than one intent is queued
parser = new IllustrativeRSSParser();
}
#Override
protected void onHandleIntent(Intent intent) {
PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT_EXTRA);
InputStream in = null;
try {
try {
URL url = new URL(intent.getStringExtra(URL_EXTRA));
IllustrativeRSS rss = parser.parse(in = url.openStream());
Intent result = new Intent();
result.putExtra(RSS_RESULT_EXTRA, rss);
reply.send(this, RESULT_CODE, result);
} catch (MalformedURLException exc) {
reply.send(INVALID_URL_CODE);
} catch (Exception exc) {
// could do better by treating the different sax/xml exceptions individually
reply.send(ERROR_CODE);
}
} catch (PendingIntent.CanceledException exc) {
Log.i(TAG, "reply cancelled", exc);
}
}
}
Step 2: Register the service in the manifest:
<service
android:name=".DownloadIntentService"
android:exported="false"/>
Step 3: Invoke the service from the Activity, passing a PendingResult object which the Service will use to return the result:
PendingIntent pendingResult = createPendingResult(
RSS_DOWNLOAD_REQUEST_CODE, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), DownloadIntentService.class);
intent.putExtra(DownloadIntentService.URL_EXTRA, URL);
intent.putExtra(DownloadIntentService.PENDING_RESULT_EXTRA, pendingResult);
startService(intent);
Step 4: Handle the result in onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RSS_DOWNLOAD_REQUEST_CODE) {
switch (resultCode) {
case DownloadIntentService.INVALID_URL_CODE:
handleInvalidURL();
break;
case DownloadIntentService.ERROR_CODE:
handleError(data);
break;
case DownloadIntentService.RESULT_CODE:
handleRSS(data);
break;
}
handleRSS(data);
}
super.onActivityResult(requestCode, resultCode, data);
}
A GitHub project containing a complete working Android Studio/Gradle project is available here.
You cannot perform network I/O on the UI thread on Honeycomb. Technically, it is possible on earlier versions of Android, but it is a really bad idea as it will cause your app to stop responding, and can result in the OS killing your app for being badly behaved. You'll need to run a background process or use AsyncTask to perform your network transaction on a background thread.
There is an article about Painless Threading on the Android developer site which is a good introduction to this, and it will provide you with a much better depth of an answer than can be realistically provided here.
There are two solutions of this problem.
Don't use a network call in the main UI thread. Use an async task for that.
Write the below code into your MainActivity file after setContentView(R.layout.activity_main);:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
And the below import statement into your Java file.
import android.os.StrictMode;
Do the network actions on another thread.
For example:
new Thread(new Runnable(){
#Override
public void run() {
// Do network action in this function
}
}).start();
And add this to file AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
Do not use strictMode (only in debug mode)
Do not change SDK version
Do not use a separate thread
Use Service or AsyncTask
See also Stack Overflow question:
android.os.NetworkOnMainThreadException sending an email from Android
You disable the strict mode using following code:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
This is not recommended: use the AsyncTask interface.
Full code for both the methods
Network-based operations cannot be run on the main thread. You need to run all network-based tasks on a child thread or implement AsyncTask.
This is how you run a task in a child thread:
new Thread(new Runnable(){
#Override
public void run() {
try {
// Your implementation goes here
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Put your code inside:
new Thread(new Runnable(){
#Override
public void run() {
try {
// Your implementation
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Or:
class DemoTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... arg0) {
//Your implementation
}
protected void onPostExecute(Void result) {
// TODO: do something with the feed
}
}
This happens in Android 3.0 and above. From Android 3.0 and above, they have restricted using network operations (functions that access the Internet) from running in the main thread/UI thread (what spawns from your on create and on resume methods in the activity).
This is to encourage using separate threads for network operations. See AsyncTask for more details on how to perform network activities the right way.
Using Android Annotations is an option. It will allow you to simply run any method in a background thread:
// normal method
private void normal() {
doSomething(); // do something in background
}
#Background
protected void doSomething()
// run your networking code here
}
Note, that although it provides benefits of simplicity and readability, it has its disadvantages.
The error is due to executing long running operations in main thread,You can easily rectify the problem by using AsynTask or Thread. You can checkout this library AsyncHTTPClient for better handling.
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onStart() {
// Called before a request is started
}
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// Called when response HTTP status is "200 OK"
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
// Called when response HTTP status is "4XX" (for example, 401, 403, 404)
}
#Override
public void onRetry(int retryNo) {
// Called when request is retried
}
});
You should not do any time-consuming task on the main thread (UI thread), like any network operation, file I/O, or SQLite database operations. So for this kind of operation, you should create a worker thread, but the problem is that you can not directly perform any UI related operation from your worker thread. For that, you have to use Handler and pass the Message.
To simplify all these things, Android provides various ways, like AsyncTask, AsyncTaskLoader, CursorLoader or IntentService. So you can use any of these according to your requirements.
The top answer of spektom works perfect.
If you are writing the AsyncTask inline and not extending as a class, and on top of this, if there is a need to get a response out of the AsyncTask, one can use the get() method as below.
RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();
(From his example.)
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads.
The error is the SDK warning!
For me it was this:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="10" />
The device I was testing my app on was 4.1.2 which is SDK Version 16!
Make the sure the target version is the same as your Android Target Library. If you are unsure what your target library is, right click your Project -> Build Path -> Android, and it should be the one that is ticked.
Also, as others have mentioned, include the correct permissions to access the Internet:
<uses-permission android:name="android.permission.INTERNET"/>
Use this in Your Activity
btnsub.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//Initialize soap request + add parameters
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME1);
//Use this to add parameters
request.addProperty("pincode", txtpincode.getText().toString());
request.addProperty("bg", bloodgroup.getSelectedItem().toString());
//Declare the version of the SOAP request
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
envelope.dotNet = true;
try {
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
//this is the actual part that will call the webservice
androidHttpTransport.call(SOAP_ACTION1, envelope);
// Get the SoapResult from the envelope body.
SoapObject result = (SoapObject) envelope.getResponse();
Log.e("result data", "data" + result);
SoapObject root = (SoapObject) result.getProperty(0);
// SoapObject s_deals = (SoapObject) root.getProperty(0);
// SoapObject s_deals_1 = (SoapObject) s_deals.getProperty(0);
//
System.out.println("********Count : " + root.getPropertyCount());
value = new ArrayList<Detailinfo>();
for (int i = 0; i < root.getPropertyCount(); i++) {
SoapObject s_deals = (SoapObject) root.getProperty(i);
Detailinfo info = new Detailinfo();
info.setFirstName(s_deals.getProperty("Firstname").toString());
info.setLastName(s_deals.getProperty("Lastname").toString());
info.setDOB(s_deals.getProperty("DOB").toString());
info.setGender(s_deals.getProperty("Gender").toString());
info.setAddress(s_deals.getProperty("Address").toString());
info.setCity(s_deals.getProperty("City").toString());
info.setState(s_deals.getProperty("State").toString());
info.setPinecode(s_deals.getProperty("Pinecode").toString());
info.setMobile(s_deals.getProperty("Mobile").toString());
info.setEmail(s_deals.getProperty("Email").toString());
info.setBloodgroup(s_deals.getProperty("Bloodgroup").toString());
info.setAdddate(s_deals.getProperty("Adddate").toString());
info.setWaight(s_deals.getProperty("waight").toString());
value.add(info);
}
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent(getApplicationContext(), ComposeMail.class);
//intent.putParcelableArrayListExtra("valuesList", value);
startActivity(intent);
}
}).start();
}
});
Just to spell out something explicitly:
The main thread is basically the UI thread.
So saying that you cannot do networking operations in the main thread means you cannot do networking operations in the UI thread, which means you cannot do networking operations in a *runOnUiThread(new Runnable() { ... }* block inside some other thread, either.
(I just had a long head-scratching moment trying to figure out why I was getting that error somewhere other than my main thread. This was why; this thread helped; and hopefully this comment will help someone else.)
This exception occurs due to any heavy task performed on the main thread if that performing task takes too much time.
To avoid this, we can handle it using threads or executers
Executors.newSingleThreadExecutor().submit(new Runnable() {
#Override
public void run() {
// You can perform your task here.
}
});
There are many great answers already on this question, but a lot of great libraries have come out since those answers were posted. This is intended as a kind of newbie-guide.
I will cover several use cases for performing network operations and a solution or two for each.
REST over HTTP
Typically JSON, but it can be XML or something else.
Full API Access
Let's say you are writing an app that lets users track stock prices, interest rates and currency exchange rates. You find an JSON API that looks something like this:
http://api.example.com/stocks // ResponseWrapper<String> object containing a
// list of strings with ticker symbols
http://api.example.com/stocks/$symbol // Stock object
http://api.example.com/stocks/$symbol/prices // PriceHistory<Stock> object
http://api.example.com/currencies // ResponseWrapper<String> object containing a
// list of currency abbreviation
http://api.example.com/currencies/$currency // Currency object
http://api.example.com/currencies/$id1/values/$id2 // PriceHistory<Currency> object comparing the prices
// of the first currency (id1) to the second (id2)
Retrofit from Square
This is an excellent choice for an API with multiple endpoints and allows you to declare the REST endpoints instead of having to code them individually as with other libraries like Amazon Ion Java or Volley (website: Retrofit).
How do you use it with the finances API?
File build.gradle
Add these lines to your module level build.gradle file:
implementation 'com.squareup.retrofit2:retrofit:2.3.0' // Retrofit library, current as of September 21, 2017
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' // Gson serialization and deserialization support for retrofit, version must match retrofit version
File FinancesApi.java
public interface FinancesApi {
#GET("stocks")
Call<ResponseWrapper<String>> listStocks();
#GET("stocks/{symbol}")
Call<Stock> getStock(#Path("symbol")String tickerSymbol);
#GET("stocks/{symbol}/prices")
Call<PriceHistory<Stock>> getPriceHistory(#Path("symbol")String tickerSymbol);
#GET("currencies")
Call<ResponseWrapper<String>> listCurrencies();
#GET("currencies/{symbol}")
Call<Currency> getCurrency(#Path("symbol")String currencySymbol);
#GET("currencies/{symbol}/values/{compare_symbol}")
Call<PriceHistory<Currency>> getComparativeHistory(#Path("symbol")String currency, #Path("compare_symbol")String currencyToPriceAgainst);
}
Class FinancesApiBuilder
public class FinancesApiBuilder {
public static FinancesApi build(String baseUrl){
return new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(FinancesApi.class);
}
}
Class FinancesFragment snippet
FinancesApi api = FinancesApiBuilder.build("http://api.example.com/"); //trailing '/' required for predictable behavior
api.getStock("INTC").enqueue(new Callback<Stock>(){
#Override
public void onResponse(Call<Stock> stockCall, Response<Stock> stockResponse){
Stock stock = stockCall.body();
// Do something with the stock
}
#Override
public void onResponse(Call<Stock> stockCall, Throwable t){
// Something bad happened
}
}
If your API requires an API key or other header, like a user token, etc. to be sent, Retrofit makes this easy (see this awesome answer to Add Header Parameter in Retrofit for details).
One-off REST API access
Let's say you're building a "mood weather" app that looks up the user's GPS location and checks the current temperature in that area and tells them the mood. This type of app doesn't need to declare API endpoints; it just needs to be able to access one API endpoint.
Ion
This is a great library for this type of access.
Please read msysmilu's great answer to How can I fix 'android.os.NetworkOnMainThreadException'?.
Load images via HTTP
Volley
Volley can also be used for REST APIs, but due to the more complicated setup required, I prefer to use Retrofit from Square as above.
Let's say you are building a social networking app and want to load profile pictures of friends.
File build.gradle
Add this line to your module level build.gradle file:
implementation 'com.android.volley:volley:1.0.0'
File ImageFetch.java
Volley requires more setup than Retrofit. You will need to create a class like this to setup a RequestQueue, an ImageLoader and an ImageCache, but it's not too bad:
public class ImageFetch {
private static ImageLoader imageLoader = null;
private static RequestQueue imageQueue = null;
public static ImageLoader getImageLoader(Context ctx){
if(imageLoader == null){
if(imageQueue == null){
imageQueue = Volley.newRequestQueue(ctx.getApplicationContext());
}
imageLoader = new ImageLoader(imageQueue, new ImageLoader.ImageCache() {
Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
#Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
return imageLoader;
}
}
File user_view_dialog.xml
Add the following to your layout XML file to add an image:
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/profile_picture"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
app:srcCompat="#android:drawable/spinner_background"/>
File UserViewDialog.java
Add the following code to the onCreate method (Fragment, Activity) or the constructor (Dialog):
NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());
Picasso
Picasso is another excellent library from Square. Please see the website for some great examples.
In simple words,
Do not do network work in the UI thread
For example, if you do an HTTP request, that is a network action.
Solution:
You have to create a new Thread
Or use the AsyncTask class
Way:
Put all your works inside
The run() method of the new thread
Or the doInBackground() method of the AsyncTask class.
But:
When you get something from a network response and want to show it on your view (like display response message in TextView), you need to return back to the UI thread.
If you don't do it, you will get ViewRootImpl$CalledFromWrongThreadException.
How-to
While using AsyncTask, update the view from the onPostExecute() method
Or call the runOnUiThread() method and update the view inside the run() method.
You are able to move a part of your code into another thread to offload the main thread and avoid getting ANR, NetworkOnMainThreadException, IllegalStateException (e.g., cannot access database on the main thread since it may potentially lock the UI for a long period of time).
There are some approaches that you should choose depends on the situation
Java Thread or Android HandlerThread:
Java threads are one-time use only and die after executing its run method.
HandlerThread is a handy class for starting a new thread that has a looper.
AsyncTask (deprecated in API level 30)
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
Since the main thread monopolizes UI components, it is not possible to access to some View, and that is why Handler comes to the rescue
[Executor framework]
ThreadPoolExecutor class that implements ExecutorService which gives fine control on the thread pool (E.g., core pool size, max pool size, keep alive time, etc.)
ScheduledThreadPoolExecutor - a class that extends ThreadPoolExecutor. It can schedule tasks after a given delay or periodically.
FutureTask
FutureTask performs asynchronous processing, however, if the result is not ready yet or processing has not complete, calling get() will be block the thread
AsyncTaskLoaders
AsyncTaskLoaders as they solve a lot of problems that are inherent to AsyncTask
IntentService
This is the de facto choice for long running processing on Android, a good example would be to upload or download large files. The upload and download may continue even if the user exits the app and you certainly do not want to block the user from being able to use the app while these tasks are going on.
JobScheduler
Effectively, you have to create a Service and create a job using JobInfo.Builder that specifies your criteria for when to run the service.
RxJava
Library for composing asynchronous and event-based programs by using observable sequences.
Coroutines (Kotlin)
The main gist of it is, it makes asynchronous code looks so much like synchronous
Read more here, here, here, and here.
Kotlin
If you are using Kotlin, you can use a coroutine:
fun doSomeNetworkStuff() {
GlobalScope.launch(Dispatchers.IO) {
// ...
}
}
New Thread and AsyncTask solutions have been explained already.
AsyncTask should ideally be used for short operations. Normal Thread is not preferable for Android.
Have a look at alternate solution using HandlerThread and Handler
HandlerThread
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
Handler:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Solution:
Create HandlerThread
Call start() on HandlerThread
Create Handler by getting Looper from HanlerThread
Embed your Network operation related code in Runnable object
Submit Runnable task to Handler
Sample code snippet, which address NetworkOnMainThreadException
HandlerThread handlerThread = new HandlerThread("URLConnection");
handlerThread.start();
handler mainHandler = new Handler(handlerThread.getLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
try {
Log.d("Ravi", "Before IO call");
URL page = new URL("http://www.google.com");
StringBuffer text = new StringBuffer();
HttpURLConnection conn = (HttpURLConnection) page.openConnection();
conn.connect();
InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
BufferedReader buff = new BufferedReader(in);
String line;
while ( (line = buff.readLine()) != null) {
text.append(line + "\n");
}
Log.d("Ravi", "After IO call");
Log.d("Ravi",text.toString());
}catch( Exception err){
err.printStackTrace();
}
}
};
mainHandler.post(myRunnable);
Pros of using this approach:
Creating new Thread/AsyncTask for each network operation is expensive. The Thread/AsyncTask will be destroyed and re-created for next Network operations. But with Handler and HandlerThread approach, you can submit many network operations (as Runnable tasks) to single HandlerThread by using Handler.
This works. I just made Dr.Luiji's answer a little simpler.
new Thread() {
#Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
Although above there is a huge solution pool, no one mentioned com.koushikdutta.ion: https://github.com/koush/ion
It's also asynchronous and very simple to use:
Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
#Override
public void onCompleted(Exception e, JsonObject result) {
// do stuff with the result or error
}
});
The main thread is the UI thread, and you cannot do an operation in the main thread which may block the user interaction. You can solve this in two ways:
Force to do the task in the main thread like this
StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);
Or create a simple handler and update the main thread if you want.
Runnable runnable;
Handler newHandler;
newHandler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
try {
//update UI
} catch (Exception e) {
e.printStackTrace();
}
}
};
newHandler.post(runnable);
And to stop the thread use:
newHandler.removeCallbacks(runnable);
For more information check this out: Painless threading
RxAndroid is another better alternative to this problem and it saves us from hassles of creating threads and then posting results on Android UI thread.
We just need to specify threads on which tasks need to be executed and everything is handled internally.
Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() {
#Override
public List<String> call() {
return mRestClient.getFavoriteMusicShows();
}
});
mMusicShowSubscription = musicShowsObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>>() {
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) { }
#Override
public void onNext(List<String> musicShows) {
listMusicShows(musicShows);
}
});
By specifiying (Schedulers.io()), RxAndroid will run getFavoriteMusicShows() on a different thread.
By using AndroidSchedulers.mainThread() we want to observe this Observable on the UI thread, i.e., we want our onNext() callback to be called on the UI thread.
I have created an AsyncTsak class in my project which downloads some information from web server. I am sure that it works well because when it is called by onCreate() , I can see the result . But unfortunately when I call it again via a button it doesn't work.
I am not sure but i think i have read somewhere about this problem . It said , we are permitted to use AsyncTask class only once.
AsyncTask class
class DownloadAdvertismentLevel2 extends AsyncTask<String,String,String>{
String [] ImageInformation=null;
protected void onPreExecute(){
// do nothing !
}
protected String doInBackground(String...Urls){
String Data="";
HttpURLConnection urlConnection = null;
try{
URL myUrl=new URL("http://10.0.2.2:80/Urgence/ads.aspx?Action=DownloadIds&TB="+TopBoundry+"&LB="+LowBoundry);
urlConnection = (HttpURLConnection)myUrl.openConnection();
BufferedReader in = new BufferedReader (new InputStreamReader(urlConnection.getInputStream()));
String temp="";
// Data is used to store Server's Response
while((temp=in.readLine())!=null)
{
Data=Data+temp;
}
}
catch(Exception ex){
Log.d("Er>doInBackground", ex.toString());
urlConnection.disconnect();
}
finally{
urlConnection.disconnect();
}
return Data;// it sends Result to onPostExcute
}
protected void onPostExecute(String Data){
createPhotoAlbum();
pb.closedProg();
}
}
onCreate
Here I don't have any problem . It works fine
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ads);
new DownloadAdvertismentLevel2().execute();
}
Via Button
ButtonSeeMore.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
Counting();
}});
Counting
public void Counting(){
if(TotalRows-6>0){
TopBoundry=TotalRows;
LowBoundry=TotalRows-6;
TotalRows=LowBoundry;
}
new DownloadAdvertismentLevel2().execute();
}
Please consider that I need to use this class till it shows the information. What would you suggest ?
To expand on what JVN said about AsyncTask
Each instance of Async task can only be executed once.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
http://developer.android.com/reference/android/os/AsyncTask.html (Under 'Threading Rules')
This doesn't stop you making a new instance -
public void Counting(){
if(TotalRows-6>0){
TopBoundry=TotalRows;
LowBoundry=TotalRows-6;
TotalRows=LowBoundry;
}
new DownloadAdvertismentLevel2().execute();
new DownloadAdvertismentLevel2().execute();
}
^ The code above will run your task twice.
Your code looks fine.
I would guess that the problem is (in order of likelihood)
1) On click isn't working
2) Post Execute isn't working as expected
3) The server response isn't being read correctly
4) Your Server isn't handling the request properly
But this would be obvious if you run your debugger or add some extra log outputs
1) I think you might be able to use the Async task only once in the class. But definitely it can be called multiple times.
2) please check if your button onclicklistener() function is really getting called on button click. try some logs in that.
because the code seems to be fine.
To allow multiple asycnh tasks run at the same time you need to use the 'executeOnExceuter mechanism:
See this note from the Android doucmentation:
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.
An example invocation would look like (this particular example is from a video manipulation app - the 'distributionTask' is an instance of a class that extends AsynchTask):
//Now execute synch task - to allow multiple AsynchTasks execute in parallel the
//'executeOnExecutor' call is required. It needs to be used with caution to avoid the usual synchronization issues and also
//to avoid too many threads being created
distributionTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Environment.getExternalStorageDirectory() + "/videoChunk_"+i+".mp4");
I got an error while running my Android project for RssReader.
Code:
URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
And it shows the below error:
android.os.NetworkOnMainThreadException
How can I fix this issue?
NOTE : AsyncTask was deprecated in API level 30.
AsyncTask | Android Developers
This exception is thrown when an application attempts to perform a networking operation on its main thread. Run your code in AsyncTask:
class RetrieveFeedTask extends AsyncTask<String, Void, RSSFeed> {
private Exception exception;
protected RSSFeed doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
} catch (Exception e) {
this.exception = e;
return null;
} finally {
is.close();
}
}
protected void onPostExecute(RSSFeed feed) {
// TODO: check this.exception
// TODO: do something with the feed
}
}
How to execute the task:
In MainActivity.java file you can add this line within your oncreate() method
new RetrieveFeedTask().execute(urlToRssFeed);
Don't forget to add this to AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET"/>
You should almost always run network operations on a thread or as an asynchronous task.
But it is possible to remove this restriction and you override the default behavior, if you are willing to accept the consequences.
Add:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
In your class,
and
Add this permission in the Android manifest.xml file:
<uses-permission android:name="android.permission.INTERNET"/>
Consequences:
Your app will (in areas of spotty Internet connection) become unresponsive and lock up, the user perceives slowness and has to do a force kill, and you risk the activity manager killing your app and telling the user that the app has stopped.
Android has some good tips on good programming practices to design for responsiveness:
NetworkOnMainThreadException | Android Developers
I solved this problem using a new Thread.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
The accepted answer has some significant downsides. It is not advisable to use AsyncTask for networking unless you really know what you are doing. Some of the down-sides include:
AsyncTask's created as non-static inner classes have an implicit reference to the enclosing Activity object, its context, and the entire View hierarchy created by that activity. This reference prevents the Activity from being garbage collected until the AsyncTask's background work completes. If the user's connection is slow, and/or the download is large, these short-term memory leaks can become a problem - for example, if the orientation changes several times (and you don't cancel the executing tasks), or the user navigates away from the Activity.
AsyncTask has different execution characteristics depending on the platform it executes on: prior to API level 4 AsyncTasks execute serially on a single background thread; from API level 4 through API level 10, AsyncTasks execute on a pool of up to 128 threads; from API level 11 onwards AsyncTask executes serially on a single background thread (unless you use the overloaded executeOnExecutor method and supply an alternative executor). Code that works fine when running serially on ICS may break when executed concurrently on Gingerbread, say if you have inadvertent order-of-execution dependencies.
If you want to avoid short-term memory leaks, have well-defined execution characteristics across all platforms, and have a base to build really robust network handling, you might want to consider:
Using a library that does a nice job of this for you - there's a nice comparison of networking libs in this question, or
Using a Service or IntentService instead, perhaps with a PendingIntent to return the result via the Activity's onActivityResult method.
IntentService approach
Downsides:
More code and complexity than AsyncTask, though not as much as you might think
Will queue requests and run them on a single background thread. You can easily control this by replacing IntentService with an equivalent Service implementation, perhaps like this one.
Um, I can't think of any others right now actually
Upsides:
Avoids the short-term memory leak problem
If your activity restarts while network operations are in-flight it can still receive the result of the download via its onActivityResult method
A better platform than AsyncTask to build and reuse robust networking code. Example: if you need to do an important upload, you could do it from AsyncTask in an Activity, but if the user context-switches out of the app to take a phone call, the system may kill the app before the upload completes. It is less likely to kill an application with an active Service.
If you use your own concurrent version of IntentService (like the one I linked above) you can control the level of concurrency via the Executor.
Implementation summary
You can implement an IntentService to perform downloads on a single background thread quite easily.
Step 1: Create an IntentService to perform the download. You can tell it what to download via Intent extras, and pass it a PendingIntent to use to return the result to the Activity:
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
public class DownloadIntentService extends IntentService {
private static final String TAG = DownloadIntentService.class.getSimpleName();
public static final String PENDING_RESULT_EXTRA = "pending_result";
public static final String URL_EXTRA = "url";
public static final String RSS_RESULT_EXTRA = "url";
public static final int RESULT_CODE = 0;
public static final int INVALID_URL_CODE = 1;
public static final int ERROR_CODE = 2;
private IllustrativeRSSParser parser;
public DownloadIntentService() {
super(TAG);
// make one and reuse, in the case where more than one intent is queued
parser = new IllustrativeRSSParser();
}
#Override
protected void onHandleIntent(Intent intent) {
PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT_EXTRA);
InputStream in = null;
try {
try {
URL url = new URL(intent.getStringExtra(URL_EXTRA));
IllustrativeRSS rss = parser.parse(in = url.openStream());
Intent result = new Intent();
result.putExtra(RSS_RESULT_EXTRA, rss);
reply.send(this, RESULT_CODE, result);
} catch (MalformedURLException exc) {
reply.send(INVALID_URL_CODE);
} catch (Exception exc) {
// could do better by treating the different sax/xml exceptions individually
reply.send(ERROR_CODE);
}
} catch (PendingIntent.CanceledException exc) {
Log.i(TAG, "reply cancelled", exc);
}
}
}
Step 2: Register the service in the manifest:
<service
android:name=".DownloadIntentService"
android:exported="false"/>
Step 3: Invoke the service from the Activity, passing a PendingResult object which the Service will use to return the result:
PendingIntent pendingResult = createPendingResult(
RSS_DOWNLOAD_REQUEST_CODE, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), DownloadIntentService.class);
intent.putExtra(DownloadIntentService.URL_EXTRA, URL);
intent.putExtra(DownloadIntentService.PENDING_RESULT_EXTRA, pendingResult);
startService(intent);
Step 4: Handle the result in onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RSS_DOWNLOAD_REQUEST_CODE) {
switch (resultCode) {
case DownloadIntentService.INVALID_URL_CODE:
handleInvalidURL();
break;
case DownloadIntentService.ERROR_CODE:
handleError(data);
break;
case DownloadIntentService.RESULT_CODE:
handleRSS(data);
break;
}
handleRSS(data);
}
super.onActivityResult(requestCode, resultCode, data);
}
A GitHub project containing a complete working Android Studio/Gradle project is available here.
You cannot perform network I/O on the UI thread on Honeycomb. Technically, it is possible on earlier versions of Android, but it is a really bad idea as it will cause your app to stop responding, and can result in the OS killing your app for being badly behaved. You'll need to run a background process or use AsyncTask to perform your network transaction on a background thread.
There is an article about Painless Threading on the Android developer site which is a good introduction to this, and it will provide you with a much better depth of an answer than can be realistically provided here.
There are two solutions of this problem.
Don't use a network call in the main UI thread. Use an async task for that.
Write the below code into your MainActivity file after setContentView(R.layout.activity_main);:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
And the below import statement into your Java file.
import android.os.StrictMode;
Do the network actions on another thread.
For example:
new Thread(new Runnable(){
#Override
public void run() {
// Do network action in this function
}
}).start();
And add this to file AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
Do not use strictMode (only in debug mode)
Do not change SDK version
Do not use a separate thread
Use Service or AsyncTask
See also Stack Overflow question:
android.os.NetworkOnMainThreadException sending an email from Android
You disable the strict mode using following code:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
This is not recommended: use the AsyncTask interface.
Full code for both the methods
Network-based operations cannot be run on the main thread. You need to run all network-based tasks on a child thread or implement AsyncTask.
This is how you run a task in a child thread:
new Thread(new Runnable(){
#Override
public void run() {
try {
// Your implementation goes here
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Put your code inside:
new Thread(new Runnable(){
#Override
public void run() {
try {
// Your implementation
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Or:
class DemoTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... arg0) {
//Your implementation
}
protected void onPostExecute(Void result) {
// TODO: do something with the feed
}
}
This happens in Android 3.0 and above. From Android 3.0 and above, they have restricted using network operations (functions that access the Internet) from running in the main thread/UI thread (what spawns from your on create and on resume methods in the activity).
This is to encourage using separate threads for network operations. See AsyncTask for more details on how to perform network activities the right way.
Using Android Annotations is an option. It will allow you to simply run any method in a background thread:
// normal method
private void normal() {
doSomething(); // do something in background
}
#Background
protected void doSomething()
// run your networking code here
}
Note, that although it provides benefits of simplicity and readability, it has its disadvantages.
The error is due to executing long running operations in main thread,You can easily rectify the problem by using AsynTask or Thread. You can checkout this library AsyncHTTPClient for better handling.
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onStart() {
// Called before a request is started
}
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// Called when response HTTP status is "200 OK"
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
// Called when response HTTP status is "4XX" (for example, 401, 403, 404)
}
#Override
public void onRetry(int retryNo) {
// Called when request is retried
}
});
You should not do any time-consuming task on the main thread (UI thread), like any network operation, file I/O, or SQLite database operations. So for this kind of operation, you should create a worker thread, but the problem is that you can not directly perform any UI related operation from your worker thread. For that, you have to use Handler and pass the Message.
To simplify all these things, Android provides various ways, like AsyncTask, AsyncTaskLoader, CursorLoader or IntentService. So you can use any of these according to your requirements.
The top answer of spektom works perfect.
If you are writing the AsyncTask inline and not extending as a class, and on top of this, if there is a need to get a response out of the AsyncTask, one can use the get() method as below.
RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();
(From his example.)
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads.
The error is the SDK warning!
For me it was this:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="10" />
The device I was testing my app on was 4.1.2 which is SDK Version 16!
Make the sure the target version is the same as your Android Target Library. If you are unsure what your target library is, right click your Project -> Build Path -> Android, and it should be the one that is ticked.
Also, as others have mentioned, include the correct permissions to access the Internet:
<uses-permission android:name="android.permission.INTERNET"/>
Use this in Your Activity
btnsub.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//Initialize soap request + add parameters
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME1);
//Use this to add parameters
request.addProperty("pincode", txtpincode.getText().toString());
request.addProperty("bg", bloodgroup.getSelectedItem().toString());
//Declare the version of the SOAP request
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
envelope.dotNet = true;
try {
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
//this is the actual part that will call the webservice
androidHttpTransport.call(SOAP_ACTION1, envelope);
// Get the SoapResult from the envelope body.
SoapObject result = (SoapObject) envelope.getResponse();
Log.e("result data", "data" + result);
SoapObject root = (SoapObject) result.getProperty(0);
// SoapObject s_deals = (SoapObject) root.getProperty(0);
// SoapObject s_deals_1 = (SoapObject) s_deals.getProperty(0);
//
System.out.println("********Count : " + root.getPropertyCount());
value = new ArrayList<Detailinfo>();
for (int i = 0; i < root.getPropertyCount(); i++) {
SoapObject s_deals = (SoapObject) root.getProperty(i);
Detailinfo info = new Detailinfo();
info.setFirstName(s_deals.getProperty("Firstname").toString());
info.setLastName(s_deals.getProperty("Lastname").toString());
info.setDOB(s_deals.getProperty("DOB").toString());
info.setGender(s_deals.getProperty("Gender").toString());
info.setAddress(s_deals.getProperty("Address").toString());
info.setCity(s_deals.getProperty("City").toString());
info.setState(s_deals.getProperty("State").toString());
info.setPinecode(s_deals.getProperty("Pinecode").toString());
info.setMobile(s_deals.getProperty("Mobile").toString());
info.setEmail(s_deals.getProperty("Email").toString());
info.setBloodgroup(s_deals.getProperty("Bloodgroup").toString());
info.setAdddate(s_deals.getProperty("Adddate").toString());
info.setWaight(s_deals.getProperty("waight").toString());
value.add(info);
}
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent(getApplicationContext(), ComposeMail.class);
//intent.putParcelableArrayListExtra("valuesList", value);
startActivity(intent);
}
}).start();
}
});
Just to spell out something explicitly:
The main thread is basically the UI thread.
So saying that you cannot do networking operations in the main thread means you cannot do networking operations in the UI thread, which means you cannot do networking operations in a *runOnUiThread(new Runnable() { ... }* block inside some other thread, either.
(I just had a long head-scratching moment trying to figure out why I was getting that error somewhere other than my main thread. This was why; this thread helped; and hopefully this comment will help someone else.)
This exception occurs due to any heavy task performed on the main thread if that performing task takes too much time.
To avoid this, we can handle it using threads or executers
Executors.newSingleThreadExecutor().submit(new Runnable() {
#Override
public void run() {
// You can perform your task here.
}
});
There are many great answers already on this question, but a lot of great libraries have come out since those answers were posted. This is intended as a kind of newbie-guide.
I will cover several use cases for performing network operations and a solution or two for each.
REST over HTTP
Typically JSON, but it can be XML or something else.
Full API Access
Let's say you are writing an app that lets users track stock prices, interest rates and currency exchange rates. You find an JSON API that looks something like this:
http://api.example.com/stocks // ResponseWrapper<String> object containing a
// list of strings with ticker symbols
http://api.example.com/stocks/$symbol // Stock object
http://api.example.com/stocks/$symbol/prices // PriceHistory<Stock> object
http://api.example.com/currencies // ResponseWrapper<String> object containing a
// list of currency abbreviation
http://api.example.com/currencies/$currency // Currency object
http://api.example.com/currencies/$id1/values/$id2 // PriceHistory<Currency> object comparing the prices
// of the first currency (id1) to the second (id2)
Retrofit from Square
This is an excellent choice for an API with multiple endpoints and allows you to declare the REST endpoints instead of having to code them individually as with other libraries like Amazon Ion Java or Volley (website: Retrofit).
How do you use it with the finances API?
File build.gradle
Add these lines to your module level build.gradle file:
implementation 'com.squareup.retrofit2:retrofit:2.3.0' // Retrofit library, current as of September 21, 2017
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' // Gson serialization and deserialization support for retrofit, version must match retrofit version
File FinancesApi.java
public interface FinancesApi {
#GET("stocks")
Call<ResponseWrapper<String>> listStocks();
#GET("stocks/{symbol}")
Call<Stock> getStock(#Path("symbol")String tickerSymbol);
#GET("stocks/{symbol}/prices")
Call<PriceHistory<Stock>> getPriceHistory(#Path("symbol")String tickerSymbol);
#GET("currencies")
Call<ResponseWrapper<String>> listCurrencies();
#GET("currencies/{symbol}")
Call<Currency> getCurrency(#Path("symbol")String currencySymbol);
#GET("currencies/{symbol}/values/{compare_symbol}")
Call<PriceHistory<Currency>> getComparativeHistory(#Path("symbol")String currency, #Path("compare_symbol")String currencyToPriceAgainst);
}
Class FinancesApiBuilder
public class FinancesApiBuilder {
public static FinancesApi build(String baseUrl){
return new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(FinancesApi.class);
}
}
Class FinancesFragment snippet
FinancesApi api = FinancesApiBuilder.build("http://api.example.com/"); //trailing '/' required for predictable behavior
api.getStock("INTC").enqueue(new Callback<Stock>(){
#Override
public void onResponse(Call<Stock> stockCall, Response<Stock> stockResponse){
Stock stock = stockCall.body();
// Do something with the stock
}
#Override
public void onResponse(Call<Stock> stockCall, Throwable t){
// Something bad happened
}
}
If your API requires an API key or other header, like a user token, etc. to be sent, Retrofit makes this easy (see this awesome answer to Add Header Parameter in Retrofit for details).
One-off REST API access
Let's say you're building a "mood weather" app that looks up the user's GPS location and checks the current temperature in that area and tells them the mood. This type of app doesn't need to declare API endpoints; it just needs to be able to access one API endpoint.
Ion
This is a great library for this type of access.
Please read msysmilu's great answer to How can I fix 'android.os.NetworkOnMainThreadException'?.
Load images via HTTP
Volley
Volley can also be used for REST APIs, but due to the more complicated setup required, I prefer to use Retrofit from Square as above.
Let's say you are building a social networking app and want to load profile pictures of friends.
File build.gradle
Add this line to your module level build.gradle file:
implementation 'com.android.volley:volley:1.0.0'
File ImageFetch.java
Volley requires more setup than Retrofit. You will need to create a class like this to setup a RequestQueue, an ImageLoader and an ImageCache, but it's not too bad:
public class ImageFetch {
private static ImageLoader imageLoader = null;
private static RequestQueue imageQueue = null;
public static ImageLoader getImageLoader(Context ctx){
if(imageLoader == null){
if(imageQueue == null){
imageQueue = Volley.newRequestQueue(ctx.getApplicationContext());
}
imageLoader = new ImageLoader(imageQueue, new ImageLoader.ImageCache() {
Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
#Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
return imageLoader;
}
}
File user_view_dialog.xml
Add the following to your layout XML file to add an image:
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/profile_picture"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
app:srcCompat="#android:drawable/spinner_background"/>
File UserViewDialog.java
Add the following code to the onCreate method (Fragment, Activity) or the constructor (Dialog):
NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());
Picasso
Picasso is another excellent library from Square. Please see the website for some great examples.
In simple words,
Do not do network work in the UI thread
For example, if you do an HTTP request, that is a network action.
Solution:
You have to create a new Thread
Or use the AsyncTask class
Way:
Put all your works inside
The run() method of the new thread
Or the doInBackground() method of the AsyncTask class.
But:
When you get something from a network response and want to show it on your view (like display response message in TextView), you need to return back to the UI thread.
If you don't do it, you will get ViewRootImpl$CalledFromWrongThreadException.
How-to
While using AsyncTask, update the view from the onPostExecute() method
Or call the runOnUiThread() method and update the view inside the run() method.
You are able to move a part of your code into another thread to offload the main thread and avoid getting ANR, NetworkOnMainThreadException, IllegalStateException (e.g., cannot access database on the main thread since it may potentially lock the UI for a long period of time).
There are some approaches that you should choose depends on the situation
Java Thread or Android HandlerThread:
Java threads are one-time use only and die after executing its run method.
HandlerThread is a handy class for starting a new thread that has a looper.
AsyncTask (deprecated in API level 30)
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
Since the main thread monopolizes UI components, it is not possible to access to some View, and that is why Handler comes to the rescue
[Executor framework]
ThreadPoolExecutor class that implements ExecutorService which gives fine control on the thread pool (E.g., core pool size, max pool size, keep alive time, etc.)
ScheduledThreadPoolExecutor - a class that extends ThreadPoolExecutor. It can schedule tasks after a given delay or periodically.
FutureTask
FutureTask performs asynchronous processing, however, if the result is not ready yet or processing has not complete, calling get() will be block the thread
AsyncTaskLoaders
AsyncTaskLoaders as they solve a lot of problems that are inherent to AsyncTask
IntentService
This is the de facto choice for long running processing on Android, a good example would be to upload or download large files. The upload and download may continue even if the user exits the app and you certainly do not want to block the user from being able to use the app while these tasks are going on.
JobScheduler
Effectively, you have to create a Service and create a job using JobInfo.Builder that specifies your criteria for when to run the service.
RxJava
Library for composing asynchronous and event-based programs by using observable sequences.
Coroutines (Kotlin)
The main gist of it is, it makes asynchronous code looks so much like synchronous
Read more here, here, here, and here.
Kotlin
If you are using Kotlin, you can use a coroutine:
fun doSomeNetworkStuff() {
GlobalScope.launch(Dispatchers.IO) {
// ...
}
}
New Thread and AsyncTask solutions have been explained already.
AsyncTask should ideally be used for short operations. Normal Thread is not preferable for Android.
Have a look at alternate solution using HandlerThread and Handler
HandlerThread
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
Handler:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Solution:
Create HandlerThread
Call start() on HandlerThread
Create Handler by getting Looper from HanlerThread
Embed your Network operation related code in Runnable object
Submit Runnable task to Handler
Sample code snippet, which address NetworkOnMainThreadException
HandlerThread handlerThread = new HandlerThread("URLConnection");
handlerThread.start();
handler mainHandler = new Handler(handlerThread.getLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
try {
Log.d("Ravi", "Before IO call");
URL page = new URL("http://www.google.com");
StringBuffer text = new StringBuffer();
HttpURLConnection conn = (HttpURLConnection) page.openConnection();
conn.connect();
InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
BufferedReader buff = new BufferedReader(in);
String line;
while ( (line = buff.readLine()) != null) {
text.append(line + "\n");
}
Log.d("Ravi", "After IO call");
Log.d("Ravi",text.toString());
}catch( Exception err){
err.printStackTrace();
}
}
};
mainHandler.post(myRunnable);
Pros of using this approach:
Creating new Thread/AsyncTask for each network operation is expensive. The Thread/AsyncTask will be destroyed and re-created for next Network operations. But with Handler and HandlerThread approach, you can submit many network operations (as Runnable tasks) to single HandlerThread by using Handler.
This works. I just made Dr.Luiji's answer a little simpler.
new Thread() {
#Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
Although above there is a huge solution pool, no one mentioned com.koushikdutta.ion: https://github.com/koush/ion
It's also asynchronous and very simple to use:
Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
#Override
public void onCompleted(Exception e, JsonObject result) {
// do stuff with the result or error
}
});
The main thread is the UI thread, and you cannot do an operation in the main thread which may block the user interaction. You can solve this in two ways:
Force to do the task in the main thread like this
StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);
Or create a simple handler and update the main thread if you want.
Runnable runnable;
Handler newHandler;
newHandler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
try {
//update UI
} catch (Exception e) {
e.printStackTrace();
}
}
};
newHandler.post(runnable);
And to stop the thread use:
newHandler.removeCallbacks(runnable);
For more information check this out: Painless threading
RxAndroid is another better alternative to this problem and it saves us from hassles of creating threads and then posting results on Android UI thread.
We just need to specify threads on which tasks need to be executed and everything is handled internally.
Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() {
#Override
public List<String> call() {
return mRestClient.getFavoriteMusicShows();
}
});
mMusicShowSubscription = musicShowsObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>>() {
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) { }
#Override
public void onNext(List<String> musicShows) {
listMusicShows(musicShows);
}
});
By specifiying (Schedulers.io()), RxAndroid will run getFavoriteMusicShows() on a different thread.
By using AndroidSchedulers.mainThread() we want to observe this Observable on the UI thread, i.e., we want our onNext() callback to be called on the UI thread.
I got an error while running my Android project for RssReader.
Code:
URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
And it shows the below error:
android.os.NetworkOnMainThreadException
How can I fix this issue?
NOTE : AsyncTask was deprecated in API level 30.
AsyncTask | Android Developers
This exception is thrown when an application attempts to perform a networking operation on its main thread. Run your code in AsyncTask:
class RetrieveFeedTask extends AsyncTask<String, Void, RSSFeed> {
private Exception exception;
protected RSSFeed doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();
} catch (Exception e) {
this.exception = e;
return null;
} finally {
is.close();
}
}
protected void onPostExecute(RSSFeed feed) {
// TODO: check this.exception
// TODO: do something with the feed
}
}
How to execute the task:
In MainActivity.java file you can add this line within your oncreate() method
new RetrieveFeedTask().execute(urlToRssFeed);
Don't forget to add this to AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET"/>
You should almost always run network operations on a thread or as an asynchronous task.
But it is possible to remove this restriction and you override the default behavior, if you are willing to accept the consequences.
Add:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
In your class,
and
Add this permission in the Android manifest.xml file:
<uses-permission android:name="android.permission.INTERNET"/>
Consequences:
Your app will (in areas of spotty Internet connection) become unresponsive and lock up, the user perceives slowness and has to do a force kill, and you risk the activity manager killing your app and telling the user that the app has stopped.
Android has some good tips on good programming practices to design for responsiveness:
NetworkOnMainThreadException | Android Developers
I solved this problem using a new Thread.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
The accepted answer has some significant downsides. It is not advisable to use AsyncTask for networking unless you really know what you are doing. Some of the down-sides include:
AsyncTask's created as non-static inner classes have an implicit reference to the enclosing Activity object, its context, and the entire View hierarchy created by that activity. This reference prevents the Activity from being garbage collected until the AsyncTask's background work completes. If the user's connection is slow, and/or the download is large, these short-term memory leaks can become a problem - for example, if the orientation changes several times (and you don't cancel the executing tasks), or the user navigates away from the Activity.
AsyncTask has different execution characteristics depending on the platform it executes on: prior to API level 4 AsyncTasks execute serially on a single background thread; from API level 4 through API level 10, AsyncTasks execute on a pool of up to 128 threads; from API level 11 onwards AsyncTask executes serially on a single background thread (unless you use the overloaded executeOnExecutor method and supply an alternative executor). Code that works fine when running serially on ICS may break when executed concurrently on Gingerbread, say if you have inadvertent order-of-execution dependencies.
If you want to avoid short-term memory leaks, have well-defined execution characteristics across all platforms, and have a base to build really robust network handling, you might want to consider:
Using a library that does a nice job of this for you - there's a nice comparison of networking libs in this question, or
Using a Service or IntentService instead, perhaps with a PendingIntent to return the result via the Activity's onActivityResult method.
IntentService approach
Downsides:
More code and complexity than AsyncTask, though not as much as you might think
Will queue requests and run them on a single background thread. You can easily control this by replacing IntentService with an equivalent Service implementation, perhaps like this one.
Um, I can't think of any others right now actually
Upsides:
Avoids the short-term memory leak problem
If your activity restarts while network operations are in-flight it can still receive the result of the download via its onActivityResult method
A better platform than AsyncTask to build and reuse robust networking code. Example: if you need to do an important upload, you could do it from AsyncTask in an Activity, but if the user context-switches out of the app to take a phone call, the system may kill the app before the upload completes. It is less likely to kill an application with an active Service.
If you use your own concurrent version of IntentService (like the one I linked above) you can control the level of concurrency via the Executor.
Implementation summary
You can implement an IntentService to perform downloads on a single background thread quite easily.
Step 1: Create an IntentService to perform the download. You can tell it what to download via Intent extras, and pass it a PendingIntent to use to return the result to the Activity:
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
public class DownloadIntentService extends IntentService {
private static final String TAG = DownloadIntentService.class.getSimpleName();
public static final String PENDING_RESULT_EXTRA = "pending_result";
public static final String URL_EXTRA = "url";
public static final String RSS_RESULT_EXTRA = "url";
public static final int RESULT_CODE = 0;
public static final int INVALID_URL_CODE = 1;
public static final int ERROR_CODE = 2;
private IllustrativeRSSParser parser;
public DownloadIntentService() {
super(TAG);
// make one and reuse, in the case where more than one intent is queued
parser = new IllustrativeRSSParser();
}
#Override
protected void onHandleIntent(Intent intent) {
PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT_EXTRA);
InputStream in = null;
try {
try {
URL url = new URL(intent.getStringExtra(URL_EXTRA));
IllustrativeRSS rss = parser.parse(in = url.openStream());
Intent result = new Intent();
result.putExtra(RSS_RESULT_EXTRA, rss);
reply.send(this, RESULT_CODE, result);
} catch (MalformedURLException exc) {
reply.send(INVALID_URL_CODE);
} catch (Exception exc) {
// could do better by treating the different sax/xml exceptions individually
reply.send(ERROR_CODE);
}
} catch (PendingIntent.CanceledException exc) {
Log.i(TAG, "reply cancelled", exc);
}
}
}
Step 2: Register the service in the manifest:
<service
android:name=".DownloadIntentService"
android:exported="false"/>
Step 3: Invoke the service from the Activity, passing a PendingResult object which the Service will use to return the result:
PendingIntent pendingResult = createPendingResult(
RSS_DOWNLOAD_REQUEST_CODE, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), DownloadIntentService.class);
intent.putExtra(DownloadIntentService.URL_EXTRA, URL);
intent.putExtra(DownloadIntentService.PENDING_RESULT_EXTRA, pendingResult);
startService(intent);
Step 4: Handle the result in onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RSS_DOWNLOAD_REQUEST_CODE) {
switch (resultCode) {
case DownloadIntentService.INVALID_URL_CODE:
handleInvalidURL();
break;
case DownloadIntentService.ERROR_CODE:
handleError(data);
break;
case DownloadIntentService.RESULT_CODE:
handleRSS(data);
break;
}
handleRSS(data);
}
super.onActivityResult(requestCode, resultCode, data);
}
A GitHub project containing a complete working Android Studio/Gradle project is available here.
You cannot perform network I/O on the UI thread on Honeycomb. Technically, it is possible on earlier versions of Android, but it is a really bad idea as it will cause your app to stop responding, and can result in the OS killing your app for being badly behaved. You'll need to run a background process or use AsyncTask to perform your network transaction on a background thread.
There is an article about Painless Threading on the Android developer site which is a good introduction to this, and it will provide you with a much better depth of an answer than can be realistically provided here.
There are two solutions of this problem.
Don't use a network call in the main UI thread. Use an async task for that.
Write the below code into your MainActivity file after setContentView(R.layout.activity_main);:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
And the below import statement into your Java file.
import android.os.StrictMode;
Do the network actions on another thread.
For example:
new Thread(new Runnable(){
#Override
public void run() {
// Do network action in this function
}
}).start();
And add this to file AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
Do not use strictMode (only in debug mode)
Do not change SDK version
Do not use a separate thread
Use Service or AsyncTask
See also Stack Overflow question:
android.os.NetworkOnMainThreadException sending an email from Android
You disable the strict mode using following code:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
This is not recommended: use the AsyncTask interface.
Full code for both the methods
Network-based operations cannot be run on the main thread. You need to run all network-based tasks on a child thread or implement AsyncTask.
This is how you run a task in a child thread:
new Thread(new Runnable(){
#Override
public void run() {
try {
// Your implementation goes here
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Put your code inside:
new Thread(new Runnable(){
#Override
public void run() {
try {
// Your implementation
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Or:
class DemoTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... arg0) {
//Your implementation
}
protected void onPostExecute(Void result) {
// TODO: do something with the feed
}
}
This happens in Android 3.0 and above. From Android 3.0 and above, they have restricted using network operations (functions that access the Internet) from running in the main thread/UI thread (what spawns from your on create and on resume methods in the activity).
This is to encourage using separate threads for network operations. See AsyncTask for more details on how to perform network activities the right way.
Using Android Annotations is an option. It will allow you to simply run any method in a background thread:
// normal method
private void normal() {
doSomething(); // do something in background
}
#Background
protected void doSomething()
// run your networking code here
}
Note, that although it provides benefits of simplicity and readability, it has its disadvantages.
The error is due to executing long running operations in main thread,You can easily rectify the problem by using AsynTask or Thread. You can checkout this library AsyncHTTPClient for better handling.
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onStart() {
// Called before a request is started
}
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// Called when response HTTP status is "200 OK"
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
// Called when response HTTP status is "4XX" (for example, 401, 403, 404)
}
#Override
public void onRetry(int retryNo) {
// Called when request is retried
}
});
You should not do any time-consuming task on the main thread (UI thread), like any network operation, file I/O, or SQLite database operations. So for this kind of operation, you should create a worker thread, but the problem is that you can not directly perform any UI related operation from your worker thread. For that, you have to use Handler and pass the Message.
To simplify all these things, Android provides various ways, like AsyncTask, AsyncTaskLoader, CursorLoader or IntentService. So you can use any of these according to your requirements.
The top answer of spektom works perfect.
If you are writing the AsyncTask inline and not extending as a class, and on top of this, if there is a need to get a response out of the AsyncTask, one can use the get() method as below.
RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();
(From his example.)
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads.
The error is the SDK warning!
For me it was this:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="10" />
The device I was testing my app on was 4.1.2 which is SDK Version 16!
Make the sure the target version is the same as your Android Target Library. If you are unsure what your target library is, right click your Project -> Build Path -> Android, and it should be the one that is ticked.
Also, as others have mentioned, include the correct permissions to access the Internet:
<uses-permission android:name="android.permission.INTERNET"/>
Use this in Your Activity
btnsub.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//Initialize soap request + add parameters
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME1);
//Use this to add parameters
request.addProperty("pincode", txtpincode.getText().toString());
request.addProperty("bg", bloodgroup.getSelectedItem().toString());
//Declare the version of the SOAP request
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
envelope.dotNet = true;
try {
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
//this is the actual part that will call the webservice
androidHttpTransport.call(SOAP_ACTION1, envelope);
// Get the SoapResult from the envelope body.
SoapObject result = (SoapObject) envelope.getResponse();
Log.e("result data", "data" + result);
SoapObject root = (SoapObject) result.getProperty(0);
// SoapObject s_deals = (SoapObject) root.getProperty(0);
// SoapObject s_deals_1 = (SoapObject) s_deals.getProperty(0);
//
System.out.println("********Count : " + root.getPropertyCount());
value = new ArrayList<Detailinfo>();
for (int i = 0; i < root.getPropertyCount(); i++) {
SoapObject s_deals = (SoapObject) root.getProperty(i);
Detailinfo info = new Detailinfo();
info.setFirstName(s_deals.getProperty("Firstname").toString());
info.setLastName(s_deals.getProperty("Lastname").toString());
info.setDOB(s_deals.getProperty("DOB").toString());
info.setGender(s_deals.getProperty("Gender").toString());
info.setAddress(s_deals.getProperty("Address").toString());
info.setCity(s_deals.getProperty("City").toString());
info.setState(s_deals.getProperty("State").toString());
info.setPinecode(s_deals.getProperty("Pinecode").toString());
info.setMobile(s_deals.getProperty("Mobile").toString());
info.setEmail(s_deals.getProperty("Email").toString());
info.setBloodgroup(s_deals.getProperty("Bloodgroup").toString());
info.setAdddate(s_deals.getProperty("Adddate").toString());
info.setWaight(s_deals.getProperty("waight").toString());
value.add(info);
}
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent(getApplicationContext(), ComposeMail.class);
//intent.putParcelableArrayListExtra("valuesList", value);
startActivity(intent);
}
}).start();
}
});
Just to spell out something explicitly:
The main thread is basically the UI thread.
So saying that you cannot do networking operations in the main thread means you cannot do networking operations in the UI thread, which means you cannot do networking operations in a *runOnUiThread(new Runnable() { ... }* block inside some other thread, either.
(I just had a long head-scratching moment trying to figure out why I was getting that error somewhere other than my main thread. This was why; this thread helped; and hopefully this comment will help someone else.)
This exception occurs due to any heavy task performed on the main thread if that performing task takes too much time.
To avoid this, we can handle it using threads or executers
Executors.newSingleThreadExecutor().submit(new Runnable() {
#Override
public void run() {
// You can perform your task here.
}
});
There are many great answers already on this question, but a lot of great libraries have come out since those answers were posted. This is intended as a kind of newbie-guide.
I will cover several use cases for performing network operations and a solution or two for each.
REST over HTTP
Typically JSON, but it can be XML or something else.
Full API Access
Let's say you are writing an app that lets users track stock prices, interest rates and currency exchange rates. You find an JSON API that looks something like this:
http://api.example.com/stocks // ResponseWrapper<String> object containing a
// list of strings with ticker symbols
http://api.example.com/stocks/$symbol // Stock object
http://api.example.com/stocks/$symbol/prices // PriceHistory<Stock> object
http://api.example.com/currencies // ResponseWrapper<String> object containing a
// list of currency abbreviation
http://api.example.com/currencies/$currency // Currency object
http://api.example.com/currencies/$id1/values/$id2 // PriceHistory<Currency> object comparing the prices
// of the first currency (id1) to the second (id2)
Retrofit from Square
This is an excellent choice for an API with multiple endpoints and allows you to declare the REST endpoints instead of having to code them individually as with other libraries like Amazon Ion Java or Volley (website: Retrofit).
How do you use it with the finances API?
File build.gradle
Add these lines to your module level build.gradle file:
implementation 'com.squareup.retrofit2:retrofit:2.3.0' // Retrofit library, current as of September 21, 2017
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' // Gson serialization and deserialization support for retrofit, version must match retrofit version
File FinancesApi.java
public interface FinancesApi {
#GET("stocks")
Call<ResponseWrapper<String>> listStocks();
#GET("stocks/{symbol}")
Call<Stock> getStock(#Path("symbol")String tickerSymbol);
#GET("stocks/{symbol}/prices")
Call<PriceHistory<Stock>> getPriceHistory(#Path("symbol")String tickerSymbol);
#GET("currencies")
Call<ResponseWrapper<String>> listCurrencies();
#GET("currencies/{symbol}")
Call<Currency> getCurrency(#Path("symbol")String currencySymbol);
#GET("currencies/{symbol}/values/{compare_symbol}")
Call<PriceHistory<Currency>> getComparativeHistory(#Path("symbol")String currency, #Path("compare_symbol")String currencyToPriceAgainst);
}
Class FinancesApiBuilder
public class FinancesApiBuilder {
public static FinancesApi build(String baseUrl){
return new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(FinancesApi.class);
}
}
Class FinancesFragment snippet
FinancesApi api = FinancesApiBuilder.build("http://api.example.com/"); //trailing '/' required for predictable behavior
api.getStock("INTC").enqueue(new Callback<Stock>(){
#Override
public void onResponse(Call<Stock> stockCall, Response<Stock> stockResponse){
Stock stock = stockCall.body();
// Do something with the stock
}
#Override
public void onResponse(Call<Stock> stockCall, Throwable t){
// Something bad happened
}
}
If your API requires an API key or other header, like a user token, etc. to be sent, Retrofit makes this easy (see this awesome answer to Add Header Parameter in Retrofit for details).
One-off REST API access
Let's say you're building a "mood weather" app that looks up the user's GPS location and checks the current temperature in that area and tells them the mood. This type of app doesn't need to declare API endpoints; it just needs to be able to access one API endpoint.
Ion
This is a great library for this type of access.
Please read msysmilu's great answer to How can I fix 'android.os.NetworkOnMainThreadException'?.
Load images via HTTP
Volley
Volley can also be used for REST APIs, but due to the more complicated setup required, I prefer to use Retrofit from Square as above.
Let's say you are building a social networking app and want to load profile pictures of friends.
File build.gradle
Add this line to your module level build.gradle file:
implementation 'com.android.volley:volley:1.0.0'
File ImageFetch.java
Volley requires more setup than Retrofit. You will need to create a class like this to setup a RequestQueue, an ImageLoader and an ImageCache, but it's not too bad:
public class ImageFetch {
private static ImageLoader imageLoader = null;
private static RequestQueue imageQueue = null;
public static ImageLoader getImageLoader(Context ctx){
if(imageLoader == null){
if(imageQueue == null){
imageQueue = Volley.newRequestQueue(ctx.getApplicationContext());
}
imageLoader = new ImageLoader(imageQueue, new ImageLoader.ImageCache() {
Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
#Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
return imageLoader;
}
}
File user_view_dialog.xml
Add the following to your layout XML file to add an image:
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/profile_picture"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
app:srcCompat="#android:drawable/spinner_background"/>
File UserViewDialog.java
Add the following code to the onCreate method (Fragment, Activity) or the constructor (Dialog):
NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());
Picasso
Picasso is another excellent library from Square. Please see the website for some great examples.
In simple words,
Do not do network work in the UI thread
For example, if you do an HTTP request, that is a network action.
Solution:
You have to create a new Thread
Or use the AsyncTask class
Way:
Put all your works inside
The run() method of the new thread
Or the doInBackground() method of the AsyncTask class.
But:
When you get something from a network response and want to show it on your view (like display response message in TextView), you need to return back to the UI thread.
If you don't do it, you will get ViewRootImpl$CalledFromWrongThreadException.
How-to
While using AsyncTask, update the view from the onPostExecute() method
Or call the runOnUiThread() method and update the view inside the run() method.
You are able to move a part of your code into another thread to offload the main thread and avoid getting ANR, NetworkOnMainThreadException, IllegalStateException (e.g., cannot access database on the main thread since it may potentially lock the UI for a long period of time).
There are some approaches that you should choose depends on the situation
Java Thread or Android HandlerThread:
Java threads are one-time use only and die after executing its run method.
HandlerThread is a handy class for starting a new thread that has a looper.
AsyncTask (deprecated in API level 30)
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
Since the main thread monopolizes UI components, it is not possible to access to some View, and that is why Handler comes to the rescue
[Executor framework]
ThreadPoolExecutor class that implements ExecutorService which gives fine control on the thread pool (E.g., core pool size, max pool size, keep alive time, etc.)
ScheduledThreadPoolExecutor - a class that extends ThreadPoolExecutor. It can schedule tasks after a given delay or periodically.
FutureTask
FutureTask performs asynchronous processing, however, if the result is not ready yet or processing has not complete, calling get() will be block the thread
AsyncTaskLoaders
AsyncTaskLoaders as they solve a lot of problems that are inherent to AsyncTask
IntentService
This is the de facto choice for long running processing on Android, a good example would be to upload or download large files. The upload and download may continue even if the user exits the app and you certainly do not want to block the user from being able to use the app while these tasks are going on.
JobScheduler
Effectively, you have to create a Service and create a job using JobInfo.Builder that specifies your criteria for when to run the service.
RxJava
Library for composing asynchronous and event-based programs by using observable sequences.
Coroutines (Kotlin)
The main gist of it is, it makes asynchronous code looks so much like synchronous
Read more here, here, here, and here.
Kotlin
If you are using Kotlin, you can use a coroutine:
fun doSomeNetworkStuff() {
GlobalScope.launch(Dispatchers.IO) {
// ...
}
}
New Thread and AsyncTask solutions have been explained already.
AsyncTask should ideally be used for short operations. Normal Thread is not preferable for Android.
Have a look at alternate solution using HandlerThread and Handler
HandlerThread
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
Handler:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Solution:
Create HandlerThread
Call start() on HandlerThread
Create Handler by getting Looper from HanlerThread
Embed your Network operation related code in Runnable object
Submit Runnable task to Handler
Sample code snippet, which address NetworkOnMainThreadException
HandlerThread handlerThread = new HandlerThread("URLConnection");
handlerThread.start();
handler mainHandler = new Handler(handlerThread.getLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
try {
Log.d("Ravi", "Before IO call");
URL page = new URL("http://www.google.com");
StringBuffer text = new StringBuffer();
HttpURLConnection conn = (HttpURLConnection) page.openConnection();
conn.connect();
InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
BufferedReader buff = new BufferedReader(in);
String line;
while ( (line = buff.readLine()) != null) {
text.append(line + "\n");
}
Log.d("Ravi", "After IO call");
Log.d("Ravi",text.toString());
}catch( Exception err){
err.printStackTrace();
}
}
};
mainHandler.post(myRunnable);
Pros of using this approach:
Creating new Thread/AsyncTask for each network operation is expensive. The Thread/AsyncTask will be destroyed and re-created for next Network operations. But with Handler and HandlerThread approach, you can submit many network operations (as Runnable tasks) to single HandlerThread by using Handler.
This works. I just made Dr.Luiji's answer a little simpler.
new Thread() {
#Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
Although above there is a huge solution pool, no one mentioned com.koushikdutta.ion: https://github.com/koush/ion
It's also asynchronous and very simple to use:
Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
#Override
public void onCompleted(Exception e, JsonObject result) {
// do stuff with the result or error
}
});
The main thread is the UI thread, and you cannot do an operation in the main thread which may block the user interaction. You can solve this in two ways:
Force to do the task in the main thread like this
StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);
Or create a simple handler and update the main thread if you want.
Runnable runnable;
Handler newHandler;
newHandler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
try {
//update UI
} catch (Exception e) {
e.printStackTrace();
}
}
};
newHandler.post(runnable);
And to stop the thread use:
newHandler.removeCallbacks(runnable);
For more information check this out: Painless threading
RxAndroid is another better alternative to this problem and it saves us from hassles of creating threads and then posting results on Android UI thread.
We just need to specify threads on which tasks need to be executed and everything is handled internally.
Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() {
#Override
public List<String> call() {
return mRestClient.getFavoriteMusicShows();
}
});
mMusicShowSubscription = musicShowsObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>>() {
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) { }
#Override
public void onNext(List<String> musicShows) {
listMusicShows(musicShows);
}
});
By specifiying (Schedulers.io()), RxAndroid will run getFavoriteMusicShows() on a different thread.
By using AndroidSchedulers.mainThread() we want to observe this Observable on the UI thread, i.e., we want our onNext() callback to be called on the UI thread.
I'm using this AsyncTask for calling the skype page https://login.skype.com/json/validator?new_username=username for understand if a certain skype contact already exsists.
public class SkypeValidateUserTask extends AsyncTask<String, Void, String>{
protected String doInBackground(String...urls){
String response = "";
for(String url:urls){
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try{
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s="";
while((s=buffer.readLine()) != null){
response+=s;
}
}catch(Exception ex){
ex.printStackTrace();
}
}
return response;
}
public void onPostExecute(String result){
String status="";
try{
JSONObject obj=new JSONObject(result);
status=obj.getString("status");
}catch(Exception ex){
ex.printStackTrace();
}
//Log.i("RISULTATO: ","STATO: "+status);
}
}
The main activity call this task for getting skype validation user result. The code is:
String skype = "name.surname.example";
if(!skype.equalsIgnoreCase("")){
// check if the skype contact exists
SkypeValidateUserTask task = new SkypeValidateUserTask();
task.execute(new String[] {"https://login.skype.com/json/validator?new_username="+skype});
// here I need to obtain the result of the thread
}
My problems are:
I need to get the result of the task (the String status) in the main activity.
After the task.execute call, the next code in main activity is executed without wait for result returned from asynctask.
It is dengerious to use get() method to get the result from async task because It blocks the UI Thread.
use This Thread where I provided a reusable solutionCallback mechanism to get result from async thread without blocking UI Thread
I have implemented that with the help of lapslaz
public JsonData(YourActivityClass activity)
{
this.activity=activity;
mProgressDialog = new ProgressDialog(activity);
}
protected void onPostExecute(String jsondata) {
if (mProgressDialog != null || mProgressDialog.isShowing()){
mProgressDialog.dismiss();
}
if(jsondata!=null) {
activity.yourcallback(jsondata)
}
}
And define the yourcallback() in YourActivityClass
private void yourcallback(String data) {
jsonRecordsData=data;
showRecordsFromJson();
}
Start your AsyncTask on the main thread. In the preExecute method of the AsyncTask, you can start a ProgressDialog to indicate to the user that you're doing something that takes a few seconds. Use doInBackground to perform the long-running task (checking for valid Skype username, in your case). When it is complete, onPostExecute will be called. Since this runs on the UI thread, you can handle the result and perform further actions depending on it. Don't forget to close the ProgressDialog in onPostExecute.
That's why asyncTask is here. You can not make a blocking function call in UI thread because that will make your app unresponsive.
OnPostExcute Method is called on the UI/Main thread. you need to move your logic there to continue analyzing the result.
If your AsyncTask is an inner class of your main activity then you can just call a function in the main activity and pass it the result
Since it looks like it isn't, you can create constructor in your Async and pass it the Context from your main activity so you can pass the variable back to main activity
Also, the purpose of the AyncTask is to not block your UI thread, put your logic in a separate function that the AsyncTask will call
You need to implement a call-back mechanism in your AsyncTask. So instead of this:
task.execute(...);
// use results of task
Your structure should be:
task.execute(...);
// go do something else while task has a chance to execute
public void statusAvailable(String status) {
// use results of task
}
and in onPostExecute:
public void onPostExecute(String result) {
. . .
status=obj.getString("status");
activity.statusAvailable(status);
}
Getting the result out of the AsyncTask is easy . . . just the Google docs don't make it clear how to do it. Here's a quick run down.
task.execute(params);
will start the AsyncTask and pass to the doInBackground method whatever parameters you include. Once doInBackground finishes, it passes the result of its functions to onPostExecute. One would think that onPostExecute would be able to just return whatever you sent it. It doesn't. To get the result of doInBackground, which was sent to onPostExecute you need to call
task.get();
the .get() method automaticlly waits until the task has completed execution and then returns whatever the result of onPostExecute is back to the UI thread. You can assign the result to whatever variable you want and use normally after that - for example
JSONObject skypeStuff = task.get()
Put another way - just like the AsynTask does not start on it's own, it does not return on its own. The same way you need to .execute() from the UI thread, you need to call .get() from the UI thread to extract the result of the task.