android - AsyncTask 的 doInBackground 方法阻塞 UI 线程

标签 android multithreading android-asynctask

我正在 AsyncTask 中加载一些 JSON 数据,因为我想在 UI 中显示下载进度。下载工作正常,publishProgress 方法被定期调用(每 100 个 JSON 对象),但 onProgressUpdate 和 onPostExecute 不会实际执行,直到所有后台操作完成(即所有需要 doInBackground 结果的计算)。

日志大致如下:

AsyncTaskCaller.downloadWithAsyncTask: executing AsyncTask

MyAsyncTask.onPreExecute: AsyncTask started

MyAsyncTask.doInBackground: Download 0%
MyAsyncTask.doInBackground: Download 10%
...
MyAsyncTask.doInBackground: Download 90%
MyAsyncTask.doInBackground: Download 100%

AsyncTaskCaller.processResult: Results processed

// all background calculations finished

MyAsyncTask.onProgressUpdate: Download 0%
MyAsyncTask.onProgressUpdate: Download 10%
...
MyAsyncTask.onProgressUpdate: Download 90%
MyAsyncTask.onProgressUpdate: Download 100%

MyAsyncTask.onPostExecute: AsyncTask ended

MyActivity.updateUiAfterDownload

这就是我的代码调用数据的方式:

我的 Activity :

final Runnable mSynchroniseContacts = new Runnable() {
    public void run() {
        /** get oAuth tokens for synchronisation */
        MyApp app = (MyApp) getApplication();
        OpenAuthTokens myTokens = app.getAccessTokens();

        // mockup code to load contacts
        MyContact[] contacts = AsyncTaskCaller.loadContacts(myTokens, MyActivity.this);
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.synchronisation_activity);

    statusText = (TextView) findViewById(R.id.synchronisation_status_text);

    mSynchroniseContacts.run();
}

AsyncTaskCaller:

private static JSONArray records = null;

public static MyContact[] loadContacts(OpenAuthTokens myTokens, Context context) {
    MyAsyncTask contactDownloader = new MyAsyncTask(context, myTokens) {
        @Override
        protected void onPostExecute(JSONArray result) {
            super.onPostExecute(result);

            records = result; // assigning result to static class variable, to avoid calling contactDownloader.get(), which apparently blocks the UI thread according to http://stackoverflow.com/questions/5583137/asynctask-block-ui-threat-and-show-progressbar-with-delay
        }
    };

    contactDownloader.execute(url);

    // wait until contacts are downloaded
    while(!SforceContactDownloadTask2.isFinished()) {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            Log.e(TAG, e.getCause() + " - " + e.getMessage());
            e.printStackTrace();
        }
    }   

    // some code to convert JSONArray records into MyContact[] myContacts

    return myContacts;
}

MyAsyncTask(上面记录的代码未明确粘贴):

@Override
protected void onPreExecute() {
    finished = false;
}

@Override
protected void onPreExecute() {
    finished = false;
}

@Override
protected JSONArray doInBackground(String... url) {

    StringBuffer dataString = new StringBuffer();

    try {

        boolean isOnline = ConnectivtiyChecker.isInternetAvailable(context);

        if (isOnline) {

            /** send as http get request */
            URL urlObject = new URL(url[0]);
            HttpURLConnection conn = (HttpURLConnection) urlObject.openConnection();
            conn.addRequestProperty("Authorization", "OAuth " + myTokens.get_access_token());

            /** prepare response reader */
            JSONArray records = null;
            byte data[] = new byte[MAX_BUFFER_SIZE];
            int currentByteReadCount = 0;
            InputStream stream = null;
            BufferedInputStream input = null;

            try {
                /** get response input stream */
                stream = conn.getInputStream();
                input = new BufferedInputStream(stream);

                /** read response from input stream */
                while ((currentByteReadCount = input.read(data)) != -1) {
                    String readData = new String(data, 0, currentByteReadCount);
                    dataString.append(readData);

                    //code to figure progress out

                    // publishing the progress (every 5%)...
                    if (progress % (total / 20) == 0 ) {
                        publishProgress((int)(progress * 100 / total));
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, e.getCause() + " - " + e.getMessage());
                e.printStackTrace();
            } finally {
                // close streams
                if (input != null) {
                    input.close();
                }
                if (stream != null) {
                    stream.close();                     
                }
            }

            /** transform response into JSONArray */
            String result = dataString.toString();
            JSONObject object = (JSONObject) new JSONTokener(result).nextValue();
            records = object.getJSONArray("records");

            return records;
        } else {
            return null;
        }
    } catch (Exception e) {
        Log.e(TAG, e.getCause() + " - " + e.getMessage());
        e.printStackTrace();
        return null;
    }
}

@Override
protected void onProgressUpdate(Integer... changed) {
    Log.d(TAG, "Download " + changed[0] + "%");
}

@Override
protected void onPostExecute(JSONArray result) {
    finished = true;
}

public static boolean isFinished() {
    return finished;
}

有什么想法可以解除用户界面的阻塞吗?

最佳答案

您似乎正在主应用程序线程上调用Thread.sleep()。不要这样做。请将您的应用程序编写为正确的异步方式。

关于android - AsyncTask 的 doInBackground 方法阻塞 UI 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6755379/

相关文章:

Android-Room如何添加外键引用进行数据迁移

multithreading - 使用 `threadDelay` 时系统调用量过多

java - Android: finish() Activity 运行时异常

java - 是否可以在另一个方法 "AsyncTask"中运行 "AsyncTask"方法?

android - 扩展 LoaderManager - 如何实现 "publishProgress"?

android - 如何设置 View 的最小宽度以匹配父 View

Android:我可以更改标题栏位置吗?

java - 在java线程中,如何调用notify来进行特定的notify工作?

java - 如何等待任何工作线程完成?

java - Android 中的 Tabs+Swipe 适用于所有 API 级别