简体   繁体   English

当我在单独的线程(实现 Runnable)上运行 class 时,为什么会出现“android.os.NetworkOnMainThreadException”?

[英]Why do I get “android.os.NetworkOnMainThreadException” when I run the class on a separate thread (implementing Runnable)?

In my app I have a queue with items in a database that should be sent to a server.在我的应用程序中,我有一个队列,其中包含应发送到服务器的数据库中的项目。 Since I want this queue to be monitored continuously and since this task includes network communication I have made a class that implements Runnable that I call my QueueWorkerThread.因为我希望这个队列被持续监控并且因为这个任务包括网络通信,所以我制作了一个实现 Runnable 的 class,我称之为我的 QueueWorkerThread。 But for some reason I still get the "android.os.NetworkOnMainThreadException" and I don't understand why?但由于某种原因,我仍然得到“android.os.NetworkOnMainThreadException”,我不明白为什么? I've tried searching for similar issues here on SO, but anything even close is using AsyncTask and since that class apparently will become depricated in API level 30 I don't want to use it (I want this app to work for a long time).我已经尝试在 SO 上搜索类似的问题,但任何接近的东西都在使用 AsyncTask 并且因为 class 显然会在 API 级别 30 中被贬低我不想使用它(我希望这个应用程序可以长时间工作)。 Is my Runnable somehow running something back on the main thread?我的 Runnable 是否以某种方式在主线程上运行某些东西? Is that even possible?这甚至可能吗?

Here's the code for my QueueWorker Thread:这是我的 QueueWorker 线程的代码:

public class QueueWorkerThread implements Runnable{
private final static String TAG = "QueueWorkerThread";
private AtomicBoolean alive = new AtomicBoolean(true);
private Context mContext;
private FragmentRefreshInterface mFragmentRefreshInterface;
private NetworkStatusInterface mNetworkStatusInterface;

public QueueWorkerThread(Context context, FragmentRefreshInterface fragmentRefreshInterface, NetworkStatusInterface networkStatusInterface) {
    mContext = context;
    mFragmentRefreshInterface = fragmentRefreshInterface;
    mNetworkStatusInterface = networkStatusInterface;
    Log.d(TAG," Thread Started");
}

public void quit(){
    alive.set(false);
}

public void makeReady(){
    alive.set(true);
}

@Override
public void run() {
    SQLiteDatabase database = SQLiteHelper.getSingleton(mContext).getWritableDatabase();
    ServerCommunicationHelper communicationHelper = new ServerCommunicationHelper(mFragmentRefreshInterface,mNetworkStatusInterface);
    while (alive.get()){
        TracerQueueVO tracerQueueVO = SQLiteHelper.getSingleton(mContext).getNextQueueVOFromDatabase(database);

        if(tracerQueueVO.getTracerId()!=null){
            int result = communicationHelper.uploadQueueVO(tracerQueueVO, mContext);
            if(result == ServerCommunicationHelper.UPLOAD_OK){
                SQLiteHelper.getSingleton(mContext).removeQueueVOFromDatabase(database,tracerQueueVO);
            }else{
                SQLiteHelper.getSingleton(mContext).updateQueueVOInDatabase(database,tracerQueueVO);
            }
        }
        try {
            sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

} }

This is the code in MainActivity where I start my Thread:这是我开始线程的 MainActivity 中的代码:

private void startQueueWorkerThread(){
    if (mQueueWorkerThread == null){
        mQueueWorkerThread = new QueueWorkerThread(mContext,this, this);
        new Thread(mQueueWorkerThread).start();
    } else {
        mQueueWorkerThread.makeReady();
        mQueueWorkerThread.run();
    }
}

Here's the code in my ServerCommunicationHelper where the error occurs:这是我的 ServerCommunicationHelper 中发生错误的代码:

public int uploadQueueVO(ItemQueueVO queueVO, Context context){
int result = 0;
try {
    String json = queueVO.getData();
    byte[] base64 = Base64.encode(json.getBytes(),0);
    final OkHttpClient CLIENT = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(MediaType.parse("text/plain; charset=utf8"),base64))
                .build();
        Response response = CLIENT.newCall(request).execute();

        if (response.isSuccessful()){
            result = UPLOAD_OK;
        }else{
            result = UPLOAD_FAILED;
        }

    } catch (Exception e) {
        e.printStackTrace();
        result = UPLOAD_FAILED;
    }
    return result;

And this is the stack trace:这是堆栈跟踪:

W/System.err: android.os.NetworkOnMainThreadException
    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1565)
W/System.err:     at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:389)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
W/System.err:     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
    at java.net.Socket.connect(Socket.java:621)
    at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:73)
W/System.err:     at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:245)
    at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:165)
W/System.err:     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)
    at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
W/System.err:     at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
W/System.err:     at okhttp3.RealCall.execute(RealCall.java:77)
    at com.xxxxxx.xx.network.ServerCommunicationHelper.uploadQueueVO(ServerCommunicationHelper.java:136)
W/System.err:     at com.xxxxxx.xx.queue.QueueWorkerThread.run(QueueWorkerThread.java:49)
    at com.xxxxxx.xx.MainActivity.startQueueWorkerThread(MainActivity.java:1193)
    at com.xxxxxx.xx.MainActivity.onResume(MainActivity.java:373)
    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1454)
    at android.app.Activity.performResume(Activity.java:8105)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4529)
W/System.err:     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4572)
    at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2220)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:237)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:8016)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1076)

In the else part, you are calling run methods directly which will execute the network call on mail thread, hence the exceptionelse部分,您直接调用run方法,这将在邮件线程上执行网络调用,因此出现异常

// this method is being called in onResume so
// second time, mQueueWorkerThread.run will be executed on main thread
private void startQueueWorkerThread(){
    if (mQueueWorkerThread == null){
        mQueueWorkerThread = new QueueWorkerThread(mContext,this, this);
        new Thread(mQueueWorkerThread).start();
    } else {
        mQueueWorkerThread.makeReady();
        mQueueWorkerThread.run(); // it will cause the exception
        // new Thread(mQueueWorkerThread).start(); should use this
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM