为什么我在单独的线程(实现 Runnable)上 运行 class 时得到 "android.os.NetworkOnMainThreadException"?
Why do I get "android.os.NetworkOnMainThreadException" when I run the class on a separate thread (implementing Runnable)?
在我的应用程序中,我有一个队列,其中包含应发送到服务器的数据库中的项目。由于我希望持续监视此队列并且此任务包括网络通信,因此我制作了一个 class 来实现我称之为 QueueWorkerThread 的 Runnable。但出于某种原因,我仍然得到“android.os.NetworkOnMainThreadException”,我不明白为什么?我已经尝试在 SO 上搜索类似的问题,但任何接近的问题都在使用 AsyncTask 并且因为 class 显然会在 API 级别 30 中被贬低我不想使用它(我想要这个应用程序可以工作很长时间)。我的 Runnable 是否以某种方式 运行 回到了主线程?这可能吗?
这是我的 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();
}
}
}
}
这是我启动线程的 MainActivity 中的代码:
private void startQueueWorkerThread(){
if (mQueueWorkerThread == null){
mQueueWorkerThread = new QueueWorkerThread(mContext,this, this);
new Thread(mQueueWorkerThread).start();
} else {
mQueueWorkerThread.makeReady();
mQueueWorkerThread.run();
}
}
这是我的 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;
这是堆栈跟踪:
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)
在 else
部分,您直接调用 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
}
}
在我的应用程序中,我有一个队列,其中包含应发送到服务器的数据库中的项目。由于我希望持续监视此队列并且此任务包括网络通信,因此我制作了一个 class 来实现我称之为 QueueWorkerThread 的 Runnable。但出于某种原因,我仍然得到“android.os.NetworkOnMainThreadException”,我不明白为什么?我已经尝试在 SO 上搜索类似的问题,但任何接近的问题都在使用 AsyncTask 并且因为 class 显然会在 API 级别 30 中被贬低我不想使用它(我想要这个应用程序可以工作很长时间)。我的 Runnable 是否以某种方式 运行 回到了主线程?这可能吗?
这是我的 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();
}
}
}
}
这是我启动线程的 MainActivity 中的代码:
private void startQueueWorkerThread(){
if (mQueueWorkerThread == null){
mQueueWorkerThread = new QueueWorkerThread(mContext,this, this);
new Thread(mQueueWorkerThread).start();
} else {
mQueueWorkerThread.makeReady();
mQueueWorkerThread.run();
}
}
这是我的 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;
这是堆栈跟踪:
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)
在 else
部分,您直接调用 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
}
}