android.os.NetworkOnMainThreadException

android.os.NetworkOnMainThreadException

解决事情应该优先解决一件事情,总是三心二意,最后塞翁失马

问题分析

由于代码是这样写的,我认为跟线程有关系;

Drawable drawable = Drawable.createFromStream(new URL(response.getResult().get(0).getBgurl()).openStream(), null);

如果下发的是空的话,应该会crash住,并且报空指针错误,但是并不是,这儿的逻辑就是加载图片显示;debug了一下 是Loop的时候报出的,下发的并不是没有数据;

查阅资料

       The exception that is thrown when an application attempts to perform a networking operation on its main thread.
       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, but it's heavily discouraged. See the document Designing for Responsiveness.
                    Also see StrictMode.*/

在Android4.0之后在主线程里面执行Http请求都会报NetworkOnMainThreadException的异常,是不应该再主线程中进行网络请求和UI操作的,这些操作往往耗费大量时间,会造成主线程的阻塞。

解决方案

把runOnUiThread替换为

new Thread(new Runnable){@override public void run()}.start();
  • 但是又报错了提示:
  java.lang.IllegalArgumentException: You must call this method on the main thread

查看错误源码

        //判断是不是主线程
        Util.assertMainThread();
        if (view == null) {
            throw new IllegalArgumentException("You must pass in a non null View");
        }
    
        if (!isTransformationSet && view.getScaleType() != null) {
            switch (view.getScaleType()) {
            //center_crop的意思是将我们的图片尺寸按照imageview的尺寸进行适当缩放展示中心区域
                case CENTER_CROP:
                    applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    applyFitCenter();
                    break;
                //$CASES-OMITTED$
                default:
                    // Do nothing.
            }
        }
        //关键句 上面的代码主要是图片处理 
        return into(glide.buildImageViewTarget(view, transcodeClass));
    }

可以看到 如果当前传入的view为空的话就会报错
You must pass in a non null View

这里讲到了Util.assertMainThread();方法,在之前的with和into里都没有见过这个方法。其实从名字我们已经可以看出一二:
如果没有在主线程就会报错;
这时候我们需要把Glide.with(content).info().show();放到RunOnUiThread里面就可以了;

知识要点: RunOnUiThread 和 new Thread(new Runnable()).start() 的区别

  • same:都是开辟子线程 -->可以更新ui,和进行网络请求;
  • diff:部分第三方框架依赖于–>runOnUiThread比如–>glide.with(context).into();就是依赖,如果在使用 into()方法的时候没有在runOnUiThread或者主线程就会崩溃,提示
    You must pass in a non null View;
先说一下 RunonUiThread
  • runOnUiThread的线程的源代码是:
     * thread, then the action is executed immediately. If the current thread is
     * not the UI thread, the action is posted to the event queue of the UI thread.
     *
     * @param action the action to run on the UI thread
     */
    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

  • 首先判断是不是主线程,如果是的话,直接重写run方法;

  • 如果不是呢?

  • 使用Looper来处理,looper需要注意三个地方:

  • (1).线程默认没有 Looper
    (2).你可创建一个 Looper 并将它绑定到一个线程
    (3).每一个线程只能绑定一个 Looper

  • 调用looper.prepare 是判断是否绑定线程(,一个looper只能绑定一个线程),而调用looper.loop()是开始循环;当我们创建looper的时候,会创建一个消息队列,而这个消息队列里面存放的是什么,就是message;
    如果我们希望一个 Runnable 在指定的线程运行,我们只需要将它放到一个消息里,并将这个消息放到对应线程的 Looper 消息队列就可以了!

这时候就需要使用 handler来处理消息

  • 他有什么作用呢?
    (1).它负责向 Looper 的队列添加消息,当轮到消息执行时,它负责在 Looper 所在的线程中执行同一条消息。

(2).当一个 Handler 被创建的时候,会被指向一个指定的 Looper(即,指向一个指定的线程)

如果我们希望消息持有一个任务(一个 Runnable),我们简单的将 Runnable 对象传递给 post() 方法就可以:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值