Странное исключение NetworkOnMainThreadException в правильно используемой AsyncTask

Я использую jtds 1.3.0 в AsyncTask для подключения к Microsoft SQL 2008. И мой метод doInBackground() возвращает объект ResultSet. Затем я читаю строки из метода ResultSet в onPostExecute(). Обычно мой запрос должен возвращать 4701 строку. Но я получаю NetworkOnMainThreadException около 58-60 строк, после чего соединение останавливается (я могу прочитать первые ~ 60 строк). Мой исходный запрос:

SELECT ID,TITLE,CODE FROM COMPANIES

Для экспериментов я пробовал:

SELECT TOP 50 ID,TITLE,CODE FROM COMPANIES --No problem.

SELECT TOP 100 ID,TITLE,CODE FROM COMPANIES --Throws exception.

Вывод логарифма:

android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1166)
        at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:163)
        at libcore.io.IoBridge.recvfrom(IoBridge.java:506)
        at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
        at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:46)
        at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:240)
        at libcore.io.Streams.readFully(Streams.java:81)
        at java.io.DataInputStream.readFully(DataInputStream.java:99)
        at java.io.DataInputStream.readFully(DataInputStream.java:95)
        at net.sourceforge.jtds.jdbc.SharedSocket.readPacket(SharedSocket.java:881)
        at net.sourceforge.jtds.jdbc.SharedSocket.getNetPacket(SharedSocket.java:762)
        at net.sourceforge.jtds.jdbc.ResponseStream.getPacket(ResponseStream.java:477)
        at net.sourceforge.jtds.jdbc.ResponseStream.read(ResponseStream.java:114)
        at net.sourceforge.jtds.jdbc.ResponseStream.readInt(ResponseStream.java:329)
        at net.sourceforge.jtds.jdbc.TdsData.readData(TdsData.java:728)
        at net.sourceforge.jtds.jdbc.TdsCore.tdsRowToken(TdsCore.java:3080)
        at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2347)
        at net.sourceforge.jtds.jdbc.TdsCore.getNextRow(TdsCore.java:772)
        at net.sourceforge.jtds.jdbc.JtdsResultSet.next(JtdsResultSet.java:611)
        at com.example.sql.FragmentMain$1.onPostExecute(FragmentMain.java:69)
        at com.example.sql.FragmentMain$1.onPostExecute(FragmentMain.java:52)
        at android.os.AsyncTask.finish(AsyncTask.java:632)
        at android.os.AsyncTask.access$600(AsyncTask.java:177)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:146)
        at android.app.ActivityThread.main(ActivityThread.java:5602)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
        at dalvik.system.NativeStart.main(Native Method)

Фрагмент кода, генерирующий ошибку:

new DatabaseTask(
            ((ActivityMain) getActivity()).getConnectionURL()
            , getString(R.string.query_all_companies))
    {
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
            if (D) Log.d(TAG, "Querying the companies..");
        }

        @Override
        protected void onPostExecute(ResultSet resultSet)
        {
            super.onPostExecute(resultSet);
            try
            {
                if (resultSet != null)
                {
                    int i = 0;
                    while (resultSet.next()) /*while loop causes error according to logcat.*/
                    {
                        if (D) Log.i(TAG,i++);
                    }

                }
            } catch (SQLException e)
            {
                e.printStackTrace();
            }
        }
    }.execute();

Наконец, мои настройки sdk в файлах gradle:

minSdkVersion 14
targetSdkVersion 22

и зависимости:

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile files('libs/jtds-1.3.0.jar')}

Я не включил свой класс AsyncTask для простоты. В основном я открываю соединение и звоню Connection.execute() в doInBackground(). Если кто-то хочет воспроизвести ошибку, я могу отредактировать свой пост.

Спасибо


Вот мой AsyncTask класс.

public class DatabaseTask extends AsyncTask<Object,String,ResultSet>
{
private final boolean D = true;
private final String TAG = "DatabaseTask";

private String url;
private String sqlStatement;



public DatabaseTask(String url, String sqlStatement)
{
    this.url = url;
    this.sqlStatement = sqlStatement;
}

private void addParams(PreparedStatement preparedStatement,Object... params) throws SQLException
{
    if (params != null && params.length > 0)
    {
        for (int i = 0; i < params.length; i++)
        {
            Object param = params[i];

            if (param instanceof String)
            {
                preparedStatement.setString(i+1, param.toString());
                if (D) Log.d(TAG, "String parameter \'" + param + "\' added.");
            } else if (param instanceof Integer)
            {
                preparedStatement.setInt(i+1, (Integer) param);
                if (D) Log.d(TAG, "Integer parameter \'" + param + "\' added.");
            } else if (param instanceof Double)
            {
                preparedStatement.setDouble(i+1, (Double) param);
                if (D) Log.d(TAG, "Double parameter \'" + param + "\' added.");
            } else if (param instanceof BigDecimal)
            {
                preparedStatement.setBigDecimal(i+1, (BigDecimal) param);
                if (D) Log.d(TAG, "BigDecimal parameter \'" + param + "\' added.");
            }
            else
                if (D) Log.e(TAG,"SQL parameter type is not supported.");
        }
    }
}

@Override
protected ResultSet doInBackground(Object... params)
{
    try
    {
        Class.forName("net.sourceforge.jtds.jdbc.Driver").newInstance();
        Connection connection;
        connection = DriverManager.getConnection(url,
                ActivityMain.DB_USER_NAME,
                ActivityMain.DB_PASSWORD);
        if (connection != null)
        {
            if (D) Log.d(TAG, "Connection successful.");
            connection.setAutoCommit(true);
            PreparedStatement preparedStatement = connection.prepareStatement(sqlStatement);
            addParams(preparedStatement, params);
            preparedStatement.execute();
            return preparedStatement.getResultSet();
        }
        else
        {
            if (D) Log.d(TAG, "Connection failed.");
        }
    } catch (ClassNotFoundException e)
    {
        e.printStackTrace();
    } catch (InstantiationException e)
    {
        e.printStackTrace();
    } catch (IllegalAccessException e)
    {
        e.printStackTrace();
    } catch (SQLException e)
    {
        if (D) Log.e(TAG,e.getMessage());
        e.printStackTrace();
    }
    return null;
}

}


person Taha    schedule 23.07.2015    source источник


Ответы (1)


Я наконец нашел решение. Из этой ссылки я увидел, что если размер выборки ResultSet превышен, он пытается подключиться к Интернету и получить следующую часть данных. Итак, либо использование ResultSet.setFetchSize(cacheSize), либо перемещение вызова метода ResultSet.next() в AsyncTask решает проблему.

person Taha    schedule 25.07.2015