java - 由于 ProgressDialog,尝试规避 AsyncTask 上的 NetworkOnMainThreadException

标签 java android android-asynctask progressdialog

我遇到以下问题。我正在使用 DropBox SDK 将文件上传到 dropbox,效果很好。当文件上传时(在 AsyncTask 内),将显示带有取消按钮的 ProgressDialog,在这里仍然可以。工作不正常的是,当按下取消按钮时,会引发 NetworkOnMainThreadException 。我是 Android 编程新手,但我怀疑它与构造函数中的 ProgressDialog 有关。因为它不在“doInBackground”部分中。

尝试通过实现 OnDismissListener 并在 onDismiss 上进行中止来修复它,但仍然没有成功。调用“mRequest.abort()”时出现错误。 预先感谢您的任何答复!

这是我的代码

public class DropBoxUpload extends AsyncTask<Void, Long, Boolean> implements OnDismissListener {

    private DropboxAPI<?> mApi;
    private String mPath;
    private File mFile;

    private long mFileLen;
    private UploadRequest mRequest;
    private Context mContext;
    private final ProgressDialog mDialog;

    private String mErrorMsg;


    public DropBoxUpload(Context context, DropboxAPI<?> api, String dropboxPath, File file) {

        // We set the context this way so we don't accidentally leak activities
        mContext = context.getApplicationContext();

        mFileLen = file.length();
        mApi = api;
        mPath = dropboxPath;
        mFile = file;

        mDialog = new ProgressDialog(context);
        mDialog.setMax(100);
        mDialog.setMessage("Uploading " + file.getName());
        mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mDialog.setProgress(0);
        mDialog.setButton("Cancel", new OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                // This will cancel the putFile operation
                mDialog.dismiss();

            }
        });
        mDialog.setCancelable(true);
        mDialog.setOnDismissListener(this);

        mDialog.show();         
    }

    @Override
    protected Boolean doInBackground(Void... params) {

        try {
            // By creating a request, we get a handle to the putFile operation,
            // so we can cancel it later if we want to
            FileInputStream fis = new FileInputStream(mFile);
            String path = mPath + mFile.getName();
            mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(),
                    new ProgressListener() {
                @Override
                public long progressInterval() {
                    // Update the progress bar every half-second or so
                    return 500;
                }

                @Override
                public void onProgress(long bytes, long total) {
                    publishProgress(bytes);
                }
            });

            if (mRequest != null) {
                mRequest.upload();
                return true;
            }

        } catch (DropboxUnlinkedException e) {
            // This session wasn't authenticated properly or user unlinked
            mErrorMsg = "This app wasn't authenticated properly.";
        } catch (DropboxFileSizeException e) {
            // File size too big to upload via the API
            mErrorMsg = "This file is too big to upload";
        } catch (DropboxPartialFileException e) {
            // We canceled the operation
            mErrorMsg = "Upload canceled";
        } catch (DropboxServerException e) {
            // Server-side exception.  These are examples of what could happen,
            // but we don't do anything special with them here.
            if (e.error == DropboxServerException._401_UNAUTHORIZED) {
                // Unauthorized, so we should unlink them.  You may want to
                // automatically log the user out in this case.
            } else if (e.error == DropboxServerException._403_FORBIDDEN) {
                // Not allowed to access this
            } else if (e.error == DropboxServerException._404_NOT_FOUND) {
                // path not found (or if it was the thumbnail, can't be
                // thumbnailed)
            } else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
                // user is over quota
            } else {
                // Something else
            }
            // This gets the Dropbox error, translated into the user's language
            mErrorMsg = e.body.userError;
            if (mErrorMsg == null) {
                mErrorMsg = e.body.error;
            }
        } catch (DropboxIOException e) {
            // Happens all the time, probably want to retry automatically.
            mErrorMsg = "Network error.  Try again.";
        } catch (DropboxParseException e) {
            // Probably due to Dropbox server restarting, should retry
            mErrorMsg = "Dropbox error.  Try again.";
        } catch (DropboxException e) {
            // Unknown error
            mErrorMsg = "Unknown error.  Try again.";
        } catch (FileNotFoundException e) {
        } 

        return false;
    }

    @Override
    protected void onProgressUpdate(Long... progress) {
        int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
        mDialog.setProgress(percent);
    }

    @Override
    protected void onPostExecute(Boolean result) {
        mDialog.dismiss();          
    }

    @Override
    public void onDismiss(DialogInterface arg0) {
        // TODO Auto-generated method stub
        mRequest.abort();
    }
}

最佳答案

您无法从主 UI 线程访问 mRequest 对象,因为它负责网络操作。这就是为什么当您调用 mRequest.abort() 时会收到 NetworkOnMainThreadException 的原因。

您应该修改您的代码,以便使用 AsyncTask.cancel对话框关闭时,定期在 doInBackground 中检查 isCancelled,并在任务取消时调用 mRequest.abort()

关于java - 由于 ProgressDialog,尝试规避 AsyncTask 上的 NetworkOnMainThreadException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10755322/

相关文章:

java - 如何访问 setOnItemClickListener 方法中的接口(interface)?

android - 如何在取消 Activity 时退出所有异步任务?

java - 是否可以从 gc 的角度将 java 对象标记为不可回收以节省 gc-sweep 时间?

java - 最佳实践 : custom jsp tag or include tag?

android - 如何阻止 "Go"按钮被替换为 "Next"- Chrome Android 浏览器应用程序

android - 在 React-Native 中激活调试时卡在黑屏上

java - 过时的 Maven Artifact 的安全性

java - ServiceConfigurationError:无法实例化SPI类:org.apache.lucene.codecs.compressing.FastCompressingCodec

android - 如何在 Linux 中更改 AVD 管理器的默认列表路径?

java - Android 应用程序随机崩溃(java.lang.NoClassDefFoundError)