Java 如何修复“android.os.NetworkOnMainThreadException”?

Java 如何修复“android.os.NetworkOnMainThreadException”?,java,android,android-networking,networkonmainthread,Java,Android,Android Networking,Networkonmainthread,我在为RssReader运行Android项目时出错 代码: 并显示以下错误: android.os.NetworkOnMainThreadException 如何解决此问题?您无法在上的UI线程上执行网络。从技术上讲,这在早期版本的Android上是可能的,但这是一个非常糟糕的主意,因为它会导致你的应用程序停止响应,并可能导致操作系统因为你的应用程序表现不好而杀死你的应用程序。您需要运行后台进程或使用AsyncTask在后台线程上执行网络事务 Android开发者网站上有一篇关于这方面的文章

我在为RssReader运行Android项目时出错

代码:

并显示以下错误:

android.os.NetworkOnMainThreadException

如何解决此问题?

您无法在上的UI线程上执行网络。从技术上讲,这在早期版本的Android上是可能的,但这是一个非常糟糕的主意,因为它会导致你的应用程序停止响应,并可能导致操作系统因为你的应用程序表现不好而杀死你的应用程序。您需要运行后台进程或使用AsyncTask在后台线程上执行网络事务

Android开发者网站上有一篇关于这方面的文章,这是一篇很好的介绍,它将为您提供比这里实际提供的答案更深入的答案。

注意:AsyncTask在API级别30中被弃用。

当应用程序尝试在其主线程上执行网络操作时,会引发此异常。在以下位置运行代码:

不要忘记将此添加到AndroidManifest.xml文件:

您几乎应该始终在线程上运行网络操作,或者作为异步任务运行网络操作

但是,如果您愿意接受后果,则可以删除此限制并覆盖默认行为

加:

在你们班上

在android manifest.xml文件中添加此权限:

<uses-permission android:name="android.permission.INTERNET"/>
后果:

你的应用程序将在互联网连接不稳定的区域变得无响应和锁定,用户感觉到速度缓慢,必须进行强制杀戮,你将冒着活动管理器杀戮你的应用程序并告诉用户应用程序已停止的风险

Android提供了一些关于良好编程实践的好提示,以设计响应能力:
您可以使用以下代码禁用严格模式:

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = 
        new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
不建议这样做:使用AsyncTask接口


这个问题有两种解决方案

1不要在主UI线程中编写网络调用,使用异步任务

2在setContentViewR.layout.activity_main之后,将以下代码写入MainActivity文件

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
下面是导入语句到java文件中

import android.os.StrictMode;

我用一个新线程解决了这个问题

上衣很好用

如果您是以内联方式编写AsyncTask,而不是作为类进行扩展,并且最重要的是,如果需要从AsyncTask中获取响应,可以使用下面的get方法

RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();
从他的例子来看

不要仅在调试模式下使用strictMode 不要更改SDK版本 不要使用单独的螺纹 使用服务或异步任务

另见问题:


这种情况发生在Android 3.0及以上版本中。从Android 3.0和更高版本开始,他们限制使用访问互联网的网络操作功能,使其不能在主线程/UI线程中运行,而这些功能是由活动中的on create和on resume方法产生的

这是为了鼓励使用单独的线程进行网络操作。有关如何以正确的方式执行网络活动的更多详细信息,请参阅。

对我来说,这是:

<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="10" />
我测试应用程序的设备是4.1.2,是SDK版本16

确保目标版本与Android目标库相同。如果不确定目标库是什么,请右键单击项目->构建路径->Android,它应该是勾选的目标库

此外,如其他人所述,包括访问Internet的正确权限:

<uses-permission android:name="android.permission.INTERNET"/>

在另一个线程上执行网络操作

例如:

并将其添加到AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

您不应该在主线程UI线程上执行任何耗时的任务,如任何网络操作、文件I/O或SQLite数据库操作。因此,对于这种操作,您应该创建一个工作线程,但问题是您不能直接从工作线程执行任何与UI相关的操作。为此,您必须使用Handler并传递消息


为了简化所有这些事情,Android提供了各种方式,比如AsyncTask、AsyncTaskLoader、CursorLoader或IntentService。因此,您可以根据需要使用其中任何一个。

基于网络的操作不能在主线程上运行。您需要在子线程上运行所有基于网络的任务或实现AsyncTask

以下是在子线程中运行任务的方式:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
公认的答案有一些明显的负面影响。除非您真的知道自己在做什么,否则不建议使用AsyncTask进行联网。一些不利因素包括:

创建为非静态内部类的AsyncTask具有对封闭活动对象、其上下文和该活动创建的整个视图层次结构的隐式引用。此引用防止在AsyncTask的后台工作完成之前对活动进行垃圾收集。如果用户的连接速度慢,和/或下载量大,这些短期内存泄漏可能会成为一个问题-例如,如果方向改变了几次,而您没有取消 执行任务,或用户导航离开活动。 AsyncTask具有不同的执行特征,这取决于它在哪个平台上执行:在API级别4之前,AsyncTask在单个后台线程上串行执行;从API级别4到API级别10,异步任务在多达128个线程的池中执行;从API级别11开始,AsyncTask在单个后台线程上串行执行,除非使用重载的executeOnExecutor方法并提供替代执行器。在ICS上串行运行的代码在姜饼上并发执行时可能会中断,比如说,如果您无意中有执行依赖项的顺序。 如果您希望避免短期内存泄漏,在所有平台上都有定义良好的执行特性,并且有一个构建真正健壮的网络处理的基础,您可能需要考虑:

使用一个能为您完成这项工作的库-在中或中有一个很好的网络库比较 改为使用服务或IntentService,可能使用PendingEvent通过活动的onActivityResult方法返回结果。 意向服务方法 反面:

比AsyncTask更多的代码和复杂性,尽管没有您想象的那么多 将请求排队并在单个后台线程上运行它们。您可以通过将IntentService替换为等效的服务实现来轻松控制这一点,如。 嗯,实际上我现在想不出还有其他人 正面:

避免了短期内存泄漏问题 如果您的活动在网络运行过程中重新启动,它仍然可以通过onActivityResult方法接收下载结果 构建和重用健壮的网络代码的平台比AsyncTask更好。示例:如果您需要执行重要的上载,您可以从活动中的AsyncTask执行,但如果用户上下文切换到应用程序之外以接听电话,则系统可能会在上载完成之前关闭应用程序。使用活动服务终止应用程序的可能性较小。 如果您使用自己的IntentService并发版本(如我上面链接的版本),您可以通过Executor控制并发级别。 实施总结 您可以实现IntentService,以便在单个后台线程上轻松执行下载

步骤1:创建IntentService以执行下载。您可以通过Intent extra告诉它要下载什么,并向其传递一个PendingEvent以用于将结果返回到活动:

步骤2:在清单中注册服务:

<service
        android:name=".DownloadIntentService"
        android:exported="false"/>
步骤4:在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);
}

包含完整工作的Android Studio/Gradle项目的Github项目可用。

这仅适用于针对SDK或更高版本的应用程序。针对早期SDK版本的应用程序可以在其主事件循环线程上进行联网

在你的活动中使用这个

使用是一种选择。它将允许您在后台线程中简单地运行任何方法:

// normal method
private void normal() {
    doSomething(); // do something in background
}

@Background
protected void doSomething() 
    // run your networking code here
}

注意,尽管它提供了简单性和可读性的优点,但也有其缺点

简单地说一下:

主线程基本上是UI线程

因此,如果说不能在主线程中执行网络操作,则意味着不能在UI线程中执行网络操作,这意味着也不能在其他线程中的*runOnUiThreadnew Runnable{…}*块中执行网络操作


我只是花了很长一段时间试图弄明白为什么我在主线程之外的其他地方出现了这个错误。这就是为什么;这条线有帮助;希望此评论能帮助其他人。

此错误是由于在主线程中执行长时间运行的操作造成的,您可以使用或轻松地纠正此问题。您可以签出此库以获得更好的处理

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
    }
});

如果在主线程上执行的任何繁重任务占用太多时间,则会发生此异常

为了避免这种情况,我们可以使用线程或执行器来处理它

将您的代码放入:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
或:


这很有效。只是让Luiji博士的答案简单了一点

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();

尽管上面有一个巨大的解决方案池,但没有人提到com.koushikdutta.ion:

它也是异步的,使用非常简单:

简言之

不要在UI线程中执行网络工作

例如,如果您执行HTTP请求,则这是一个网络操作

解决方案:

您必须创建一个新线程 或使用 方式:

把你所有的作品都放进去

新线程的run方法 或AsyncTask类的doInBackground方法。 但是:

当您从网络响应中获得一些内容并希望在视图上显示它时(如在TextView中显示响应消息),您需要返回到UI线程

如果不这样做,您将获得ViewRootImpl$CalledFromErrorThreadException

怎么做

使用AsyncTask时,从onPostExecute方法更新视图 或者调用方法和update e在run方法中查看。
解决这个问题还有另一种非常方便的方法——使用rxJava的并发功能。您可以在后台执行任何任务,并以非常方便的方式将结果发布到主线程,所以这些结果将交给处理链

第一个经过验证的答案建议是使用AsynTask。是的,这是一个解决方案,但现在已经过时了,因为有新的工具

String getUrl() {
    return "SomeUrl";
}

private Object makeCallParseResponse(String url) {
    return null;
    //
}

private void processResponse(Object o) {

}
getUrl方法提供URL地址,它将在主线程上执行

makeCallParseResponse..-实际工作

processResponse..-将在主线程上处理结果

异步执行的代码如下所示:

rx.Observable.defer(new Func0<rx.Observable<String>>() {
    @Override
    public rx.Observable<String> call() {
        return rx.Observable.just(getUrl());
    }
})
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.io())
    .map(new Func1<String, Object>() {
        @Override
        public Object call(final String s) {
            return makeCallParseResponse(s);
        }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Object>() {
        @Override
        public void call(Object o) {
             processResponse(o);
        }
    },
    new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            // Process error here, it will be posted on
            // the main thread
        }
    });
最后一个依赖项包括对.mainThread调度程序的支持

有。

新的线程和解决方案已经解释过了

AsyncTask最好用于短期操作。对于Android来说,普通线程是不可取的

使用和查看替代解决方案

手摇线

用于启动具有活套的新线程的Handy类。然后可以使用循环器创建处理程序类。请注意,仍然必须调用start

处理程序:

处理程序允许您发送和处理与线程MessageQueue关联的消息和可运行对象。每个处理程序实例都与一个线程和该线程的消息队列相关联。当您创建一个新的处理程序时,它被绑定到正在创建它的线程的线程/消息队列-从那时起,它将向该消息队列传递消息和可运行文件,并在它们从消息队列中出来时执行它们

解决方案:

创建HandlerThread

在HandlerThread上调用start

通过从HanlerThread获取循环器来创建处理程序

将网络操作相关代码嵌入到可运行对象中

将可运行任务提交给处理程序

示例代码段,用于处理NetworkOnMainThreadException

使用此方法的优点:

为每个网络操作创建新的线程/异步任务的成本很高。线程/异步任务将被销毁并重新创建,以用于下一次网络操作。但使用Handler和HandlerThread方法,您可以使用Handler将许多网络操作作为可运行任务提交给单个HandlerThread。 RxAndroid是解决这个问题的另一个更好的选择,它使我们不必为创建线程然后在Android UI线程上发布结果而烦恼。 我们只需要指定需要在哪些线程上执行任务,并在内部处理所有事情

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);
    }
});
通过指定Schedulers.io,RxAndroid将在不同的线程上运行getFavoriteMusicShows

通过使用AndroidSchedulers.mainThread,我们希望在UI线程上观察到这种可观察性,也就是说,我们希望在UI线程上调用onNext回调


主线程是UI线程,您不能在主线程中执行可能阻止用户交互的操作。您可以通过两种方式解决此问题:

强制在主线程中执行以下任务

StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);
或者创建一个简单的处理程序,并根据需要更新主线程

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);
要停止线程,请使用:

newHandler.removeCallbacks(runnable);

有关更多信息,请查看:

关于这个问题,已经有很多很好的答案,但是自从这些答案发布后,已经有很多很好的库出现了。这是一种新手指南

我将介绍几个用于执行网络操作的用例,以及每个用例的一两个解决方案

HTTP上的ReST 通常,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)
FinancesApi.java

财务片段

ImageFetch.java

截击需要更多的设置,而不是改装。您需要创建一个类似这样的类来设置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;
    }
}
毕加索
另一个来自广场的优秀图书馆。请访问该站点以获取一些很好的示例:

您可以将部分代码移动到另一个线程中,以卸载主线程并避免获取,例如,无法访问主线程上的数据库,因为它可能会长时间锁定UI

根据具体情况,您应该选择一些方法

Java还是Android

Java线程是一次性使用的,在执行其run方法后死亡

HandlerThread是一个方便的类,用于启动具有活套的新线程

API级别30中已弃用

AsyncTask被设计成一个围绕线程和处理程序的助手类,并不构成通用线程框架。AsyncTasks理想情况下应用于最长几秒钟的短期操作。如果需要让线程长时间运行,强烈建议您使用java.util.concurr提供的各种API ent包,如Executor、ThreadPoolExecutor和FutureTask

因为主线程垄断了UI组件,所以不可能访问某些视图,这就是为什么处理程序处于救援状态

ThreadPoolExecutor类,该类实现ExecutorService,可对线程池进行精细控制,例如,核心池大小、最大池大小、保持活动时间等

ScheduledThreadPoolExecutor-扩展ThreadPoolExecutor的类。它可以在给定延迟后或定期安排任务

FutureTask执行异步处理,但是,如果结果尚未就绪或处理尚未完成,则调用get将阻塞线程

AsyncTaskLoader解决了AsyncTask固有的许多问题

这是Android上长时间运行处理的实际选择,上传或下载大型文件就是一个很好的例子。即使用户退出应用程序,上传和下载也可能会继续,您当然不想在这些任务正在进行时阻止用户使用应用程序

实际上,您必须创建一个服务,并使用JobInfo.Builder创建一个作业,该作业指定您何时运行该服务的条件

使用可观察序列编写异步和基于事件的程序的库

科特林

它的主要要点是,它使异步代码看起来非常像同步代码



有关更多信息,请阅读NetworkOnMainThreadException上的更多,,

。这解释了为什么Android 3.0及以上版本会出现这种情况。要想进入rite track,首先阅读Android中的网络请求,然后我建议学习Volley。有许多替代库可以解决这个问题。很多都列在清单上。如果你得到更多,我们就接受它们:你需要在一个独立于主UI线程的线程上运行internet活动。由于Android早期版本中存在一个bug,系统没有将写入主线程上的TCP套接字标记为严格的模式冲突。安卓7.0修复了这个错误。表现出这种行为的应用程序现在抛出一个android.os.NetworkOnMainThreadException。-所以,我们中的一些人直到最近才达到这个目标!是的,会有错误发生。表示应用程序在5秒内没有响应。这是一个非常糟糕的答案。您不应该更改线程的策略,而是要编写更好的代码:不要在主线程上进行网络操作@Sandeep你和其他观众也应该读这篇文章。遵循第二种解决方案是一种糟糕的做法。异步是正确执行此操作的方法。如果你改变政策,你就像是在隐藏你的问题!让我来解释一下你在这里做什么:网络管理员是卫报,卫报告诉你:不要自食其力。。。你的解决方案是:让我们回到过去,那时没有监护人——现在我可以自由地在我的脚上开枪——我也采取了这种方法,没有任何问题。Guardian有时太挑剔了。也许值得强调的是,如果你使用一个服务,你仍然需要创建一个单独的线程-在主线程上运行的服务回调。另一方面,IntentService在后台线程上运行其onHandleIntent方法。对于长时间运行的操作,不应使用AsyncTask!指导原则规定最多2到3秒。@Gavriel它会创建您注释的所有内容的副本,无论是方法、活动、片段、单例等,因此代码量是原来的两倍,编译时间也更长。由于库中的bug,它也可能有一些问题。调试和查找错误将变得更加困难。匿名Runnable不是最好的方法,因为它有一个对封闭类的隐式引用,并防止在线程完成之前对其进行GC调用!此外,该线程将以与主/美线程相同的优先级运行,与生命周期方法和UI帧速率竞争!简单而精彩!!!你怎么把参数传给这个?哇,谢谢你的解释,我现在明白了。我看到一个应用程序,它在java类中实现了ThreadPolicy,我有点搞不清楚它在做什么。当网络不足时,我看到了你所说的后果。因此,在主线程上运行网络操作只在android中有问题,而不是在java编写的标准java编解码器中,但不适用于android应用程序。因此,在主线程上运行网络操作只在android中有问题,而不是在标准java编解码器中用java编写,但不适用于android应用程序。??
Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
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
    }
}
new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
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
    }
});
String getUrl() {
    return "SomeUrl";
}

private Object makeCallParseResponse(String url) {
    return null;
    //
}

private void processResponse(Object o) {

}
rx.Observable.defer(new Func0<rx.Observable<String>>() {
    @Override
    public rx.Observable<String> call() {
        return rx.Observable.just(getUrl());
    }
})
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.io())
    .map(new Func1<String, Object>() {
        @Override
        public Object call(final String s) {
            return makeCallParseResponse(s);
        }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Object>() {
        @Override
        public void call(Object o) {
             processResponse(o);
        }
    },
    new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            // Process error here, it will be posted on
            // the main thread
        }
    });
   compile 'io.reactivex:rxjava:1.1.5'
   compile 'io.reactivex:rxandroid:1.2.0'
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);
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);
    }
});
StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);
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);
newHandler.removeCallbacks(runnable);
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)
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
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);
}
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
    }
}
implementation 'com.android.volley:volley:1.0.0'
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;
    }
}
<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"/>
NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());