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.
While working on some serious project in Android Studio you might’ve happened to come across this nasty error in the above line and all the worlds tried to tear apart. Well, this article has the perfect solution on how to get rid of that ‘android.os.NetworkOnMainThreadException’ error! Read to fix it!
Method #1: The Async Task Way
Believe it or not but when a program tries to perform a networking activity on its main thread, this exception is thrown. Use AsyncTask to run your code. After adopting the async task you could call up the below method to run your task.
Java
new
RetriveDSAConcepts().execute(GeeksforGeeks);
GeekTip: Don’t forget to add:
<uses-permission android:name=”android.permission.INTERNET”/>
in your projects manifest file!
Method #2: Overriding the Default Methods
Almost all network actions should be performed in a thread or as an asynchronous task. However, if you are willing to face the penalties, you can remove this restriction and override the default behavior.
Java
StrictMode.ThreadPolicy gfgPolicy =
new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(gfgPolicy);
Consequences:
Your app will become unresponsive and lock up (in locations with patchy internet connection), the user will sense slowness and will have to forcibly quit the program, and you risk the activity management deleting your app and informing the user that it has stopped.
Method #3: Disabling Strict Mode
We all know what Strict Mode in Android is, and if you are unable to achieve your task, then you can try disabling the Strict Mode in your application. To bypass it, simply go ahead and add this to your NetworkActivity.java.
Java
if
(android.os.Build.VERSION.SDK_INT >
9
) {
StrictMode.ThreadPolicy gfgPolicy =
new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(gfgPolicy);
}
Method #4: Changing the Worker Thread Manually
If the above methods don’t work out for you, you can manually change the network task to a side thread, and then wait for the result then include it in the main thread, so that the user doesn’t feel sluggish. Add the code below to your NetworkActivity.java file to change the thread.
Reference Article: How Does Threading Work in Android?
Java
Thread gfgThread =
new
Thread(
new
Runnable() {
@Override
public
void
run() {
try
{
}
catch
(Exception e) {
e.printStackTrace();
}
}
});
gfgThread.start();
Method #5: Using Android Annotations
You can also use the Android Annotations to fix this error and get back going, just add the below code to your Java file and see things move!
Java
private
void
gfg()
{
fetchData();
}
@Background
protected
void
fetchData()
}
And just like adding these simple code snippets could help you get rid of that error forever, and you’re back working on that important project once again!
Last Updated :
13 Sep, 2022
Like Article
Save Article
-
View Larger Image
How to resolve android.os.NetworkOnMainThreadException
Hello friends, I have seen so many new developers facing a specific error android.os.NetworkOnMainThreadException
Why this android crash happened
Main this application crash happened on Android’s Honeycomb(3.0) and above, but it’s works fine on Android’s older versions(2.x). Its because Honeycomb(3.0) and above that version are much stricter about abuse against the UI Thread. For example, when an Android device running 3.0 or above detects a network access on the UI thread, a NetworkOnMainThreadException
will be thrown:
Solution of this crash
E/AndroidRuntime(673): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.ExampleActivity}: android.os.NetworkOnMainThreadException
Creating New Android Project
So let’s start by creating a new android project
1. Create a new project in Eclipse from File ⇒ New ⇒ Android Application Project. I had left my main activity name as MainActivity.java and gave the package name as info.androidstation.networkonmainthread
2. As we are fetching the Data by making HTTP calls, we need to add INTERNET permission in our AndroidManifest.xml file. Open AndroidManifest.xml and add the following permission.
<uses-permission android:name="android.permission.INTERNET" />
3. We are also checking weather the internet is available or not? We need to add ACCESS_NETWORK_STATE permission in our AndroidManifest.xml file. Open AndroidManifest.xml and add the following permission.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="info.androidstation.networkonmainthread" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.INTERNET" /><!-- This permission is for Internet connection established. --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><!-- This permission is to check weather Internet connection is available or not --> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
4. We are now creating a Utility class called Utility.java. In this class we will check weather internet is available or not? We will also download data from the url using GET method and after that we will read all the downloaded data and convert it into simple string.
Utility.java
package info.androidstation.networkonmainthread.utility; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.URL; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.util.Log; public class Utility { private static String TAG = "Utility Log"; public static boolean isOnline(Context ctx)//Checking Internet is available or not { ConnectivityManager connMgr = (ConnectivityManager) ctx .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isConnected()) return true; else return false; } // Given a URL, establishes an HttpUrlConnection and retrieves // the web page content as a InputStream, which it returns as // a string. public static String downloadDataFromUrl(String myurl) throws IOException { InputStream is = null; try { URL url = new URL(myurl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(10000); // time in milliseconds conn.setConnectTimeout(15000); // time in milliseconds conn.setRequestMethod("GET"); // request method GET OR POST conn.setDoInput(true); // Starts the query conn.connect(); // calling the web address int response = conn.getResponseCode(); Log.d(TAG, "The response is: " + response); is = conn.getInputStream(); // Convert the InputStream into a string String contentAsString = readInputStream(is); return contentAsString; // Makes sure that the InputStream is closed after the app is // finished using it. } finally { if (is != null) { is.close(); } } } // Reads an InputStream and converts it to a String. public static String readInputStream(InputStream stream) throws IOException { int n = 0; char[] buffer = new char[1024 * 4]; InputStreamReader reader = new InputStreamReader(stream, "UTF8"); StringWriter writer = new StringWriter(); while (-1 != (n = reader.read(buffer))) writer.write(buffer, 0, n); return writer.toString(); } }
5. I am adding a TextView to show the downloaded data. Open the layout file of your main activity and add a TextView element.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="info.androidstation.networkonmainthread.MainActivity" > <TextView android:id="@+id/tvData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:isScrollContainer="true" android:scrollbars="vertical" /> </RelativeLayout>
6. In main activity class (MainActivity.java) I have declared things; one inner class extends AsyncTask and another one is function. Asynctask will call the downloadData function of Utility class in doInBackground override method it’s the separate thread which will not affect to the UI thread. while function directly call the downloadData function from the UI thread so this will throw exception.
MainActivity.java
package info.androidstation.networkonmainthread; import info.androidstation.networkonmainthread.utility.Utility; import java.io.IOException; import android.app.ProgressDialog; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.method.ScrollingMovementMethod; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private TextView tvData; private String url = "http://www.androidstation.info/people.json"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvData = (TextView) findViewById(R.id.tvData); tvData.setMovementMethod(new ScrollingMovementMethod()); // getDataFromUrl(); // Connect url from the main thread for get data this will throw NetworkOnMainThreadExcection new GetJSONTask().execute(url); //execute asynctask object this will resolve NetworkOnMainThreadExcection } private void getDataFromUrl() { try { tvData.setText(Utility.downloadDataFromUrl(url)); } catch (IOException e) { e.printStackTrace(); } } // Uses AsyncTask to create a task away from the main UI thread(For Avoid // NetworkOnMainThreadException). This task takes a // URL string and uses it to create an HttpUrlConnection. Once the // connection // has been established, the AsyncTask downloads the contents of the data as // an InputStream. Than, the InputStream is converted into a string, which // is // displayed in the TextView by the AsyncTask's onPostExecute method. Which // called after doInBackgroud Complete private class GetJSONTask extends AsyncTask<String, Void, String> { private ProgressDialog pd; // onPreExecute called before the doInBackgroud start for display // progress dialog. @Override protected void onPreExecute() { super.onPreExecute(); pd = ProgressDialog.show(MainActivity.this, "", "Loading", true, false); // Create and show Progress dialog } @Override protected String doInBackground(String... urls) { try { return Utility.downloadDataFromUrl(urls[0]); } catch (IOException e) { return "Unable to retrieve data. URL may be invalid."; } } // onPostExecute displays the results of the doInBackgroud and also we // can hide progress dialog. @Override protected void onPostExecute(String result) { pd.dismiss(); tvData.setText(result); } } }
This Example Output Will look like this:
Hope you all find this tutorial useful. Happy coding. 🙂
Share This Story, Choose Your Platform!
Page load link
На этот вопрос уже много замечательных ответов, но с тех пор, как эти ответы были опубликованы, появилось много замечательных библиотек. Это предназначено как своего рода новичок-гид.
Я расскажу о нескольких вариантах использования для выполнения сетевых операций и решения или двух для каждого.
ReST по HTTP
Обычно Json, может быть XML или что-то еще
Полный доступ к API
Скажем, вы пишете приложение, которое позволяет пользователям отслеживать цены акций, процентные ставки и курсовые курсы. Вы найдете Json API, который выглядит примерно так:
http://api.example.com/stocks //ResponseWrapper<String> object containing a list of Srings 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)
Модернизация с площади
Это отличный выбор для API с несколькими конечными точками и позволяет объявлять конечные точки REST вместо того, чтобы кодировать их отдельно, как с другими библиотеками, такими как ion или Volley. (веб-сайт: http://square.github.io/retrofit/)
Как вы используете его с API финансов?
build.gradle
Добавьте эти строки на уровень модуля buid.gradle:
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
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);
}
FinancesApiBuilder
public class FinancesApiBuilder {
public static FinancesApi build(String baseUrl){
return new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(FinancesApi.class);
}
}
Фундамент Фрагмент
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
}
}
Если вашему API требуется ключ API или другой заголовок, такой как токен пользователя и т.д., Retrofit делает это проще (подробнее см. Этот удивительный ответ: https://stackoverflow.com/questions/42898920/add-header-parameter-in-retrofit).
Один доступ к API-интерфейсу ReST
Скажем, вы создаете приложение “погода в настроении”, которое просматривает местоположение GPS-пользователей и проверяет текущую температуру в этой области и сообщает им настроение. Для этого типа приложения не требуется объявлять конечные точки API; ему просто нужно иметь доступ к одной конечной точке API.
ион
Это отличная библиотека для такого типа доступа.
Пожалуйста, прочитайте msysmilu отличный ответ (https://stackoverflow.com/questions/6343166/how-do-i-fix-android-os-networkonmainthreadexception)
Загружать изображения через HTTP
залп
Volley также может использоваться для API-интерфейсов ReST, но из-за более сложной настройки я предпочитаю использовать Retrofit from Square, как указано выше (http://square.github.io/retrofit/)
Скажем, вы строите приложение для социальных сетей и хотите загружать фотографии друзей друзей.
build.gradle
Добавьте эту строку в свой уровень модуля buid.gradle:
implementation 'com.android.volley:volley:1.0.0'
ImageFetch.java
Volley требует больше настроек, чем дооснащение. Вам нужно будет создать такой класс, чтобы настроить RequestQueue, ImageLoader и ImageCache, но это не так уж плохо:
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;
}
}
user_view_dialog.xml
Добавьте следующее в свой XML файл макета, чтобы добавить изображение:
<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"/>
UserViewDialog.java
Добавьте следующий код в метод onCreate (Fragment, Activity) или конструктор (Dialog):
NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());
Пикассо
Еще одна отличная библиотека с площади. Пожалуйста, посетите сайт для некоторых замечательных примеров: http://square.github.io/picasso/
Error Description:
- Error while running an 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();
click below button to copy the code. By – android tutorial – team
- And it shows the below error:
android.os.NetworkOnMainThreadException
click below button to copy the code. By – android tutorial – team
Solution 1:
- 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;
}
}
protected void onPostExecute(RSSFeed feed) {
// TODO: check this.exception
// TODO: do something with the feed
}
}
click below button to copy the code. By – android tutorial – team
How to execute the task:
In MainActivity.java file we can add this line within the oncreate() method
new RetrieveFeedTask().execute(urlToRssFeed);
click below button to copy the code. By – android tutorial – team
- Don’t forget to add this to AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET"/>
click below button to copy the code. By – android tutorial – team
Solution 2 :
- You should almost always run network operations on a thread or as an asynchronous task. But if you know better and are willing to accept the consequences, and must do network operations on the main thread, you can override the default behavior:
Add:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
click below button to copy the code. By – android tutorial – team
- In your class, ADD this permission in android manifest.xml file:
<uses-permission android:name="android.permission.INTERNET"/>
click below button to copy the code. By – android tutorial – team
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.
Solution 3:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
click below button to copy the code. By – android tutorial – team
Solution 4 :
- Do not use strictMode (only in debug mode)
- Do not change SDK version
- Do not use a separate thread
Use Service or AsyncTask