正确使用AsyncTask

时间:2015-07-23 12:28:24

标签: android sql-server android-asynctask networkonmainthread

我在AsyncTask中使用jtds 1.3.0进行Microsoft SQL 2008连接。我的doInBackground()方法返回一个ResultSet对象。然后我从ResultSet方法中的onPostExecute()读取行。通常我的查询应返回4701行。但是我得到第58至第60行的NetworkOnMainThreadException然后连接停止(我能够读取前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.

logcat输出:

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();

最后,我在gradle文件中的sdk设置:

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;
}

}

1 个答案:

答案 0 :(得分:0)

我终于找到了解决方案。从this链接我看到,如果超过ResultSet的提取大小,它会尝试连接到Internet并获取下一部分数据。因此,使用ResultSet.setFetchSize(cacheSize)或将ResultSet.next()方法调用移至AsyncTask可以解决问题。