引起:android.database.sqlite.SQLiteException:没有这样的表:location(代码1):,同时编译:SELECT

时间:2016-10-14 11:08:50

标签: android sqlite

com.example.android.sunshine.app E / SQLiteLog:(1)没有这样的表:location`

我被困在这里已经有2天但是我找不到解决方案.. 请检查 wheatherDbHelper 类中的位置表,并将常量保存在 WeatherContract 中。

public class WeatherDbHelper extends SQLiteOpenHelper {

// If you change the database schema, you must increment the database version.
private static final int DATABASE_VERSION = 2;

static final String DATABASE_NAME = "weather.db";

public WeatherDbHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
    // Create a table to hold locations.  A location consists of the string supplied in the
    // location setting, the city name, and the latitude and longitude
    final String SQL_CREATE_LOCATION_TABLE = "CREATE TABLE " + LocationEntry.TABLE_NAME + " (" +
            LocationEntry._ID + " INTEGER PRIMARY KEY, " +
            LocationEntry.COLUMN_LOCATION_SETTING + " TEXT UNIQUE NOT NULL, " +
            LocationEntry.COLUMN_CITY_NAME + " TEXT NOT NULL, " +
            LocationEntry.COLUMN_COORD_LAT + " REAL NOT NULL, " +
            LocationEntry.COLUMN_COORD_LONG + " REAL NOT NULL " +
            " );";
    sqLiteDatabase.execSQL(SQL_CREATE_LOCATION_TABLE);

    final String SQL_CREATE_WEATHER_TABLE = "CREATE TABLE " + WeatherEntry.TABLE_NAME + " (" +
            // Why AutoIncrement here, and not above?
            // Unique keys will be auto-generated in either case.  But for weather
            // forecasting, it's reasonable to assume the user will want information
            // for a certain date and all dates *following*, so the forecast data
            // should be sorted accordingly.
            WeatherEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +

            // the ID of the location entry associated with this weather data
            WeatherEntry.COLUMN_LOC_KEY + " INTEGER NOT NULL, " +
            WeatherEntry.COLUMN_DATE + " INTEGER NOT NULL, " +
            WeatherEntry.COLUMN_SHORT_DESC + " TEXT NOT NULL, " +
            WeatherEntry.COLUMN_WEATHER_ID + " INTEGER NOT NULL," +

            WeatherEntry.COLUMN_MIN_TEMP + " REAL NOT NULL, " +
            WeatherEntry.COLUMN_MAX_TEMP + " REAL NOT NULL, " +

            WeatherEntry.COLUMN_HUMIDITY + " REAL NOT NULL, " +
            WeatherEntry.COLUMN_PRESSURE + " REAL NOT NULL, " +
            WeatherEntry.COLUMN_WIND_SPEED + " REAL NOT NULL, " +
            WeatherEntry.COLUMN_DEGREES + " REAL NOT NULL, " +

            // Set up the location column as a foreign key to location table.
            " FOREIGN KEY (" + WeatherEntry.COLUMN_LOC_KEY + ") REFERENCES " +
            LocationEntry.TABLE_NAME + " (" + LocationEntry._ID + "), " +

            // To assure the application have just one weather entry per day
            // per location, it's created a UNIQUE constraint with REPLACE strategy
            " UNIQUE (" + WeatherEntry.COLUMN_DATE + ", " +
            WeatherEntry.COLUMN_LOC_KEY + ") ON CONFLICT REPLACE);";


    sqLiteDatabase.execSQL(SQL_CREATE_WEATHER_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
    // This database is only a cache for online data, so its upgrade policy is
    // to simply to discard the data and start over
    // Note that this only fires if you change the version number for your database.
    // It does NOT depend on the version number for your application.
    // If you want to update the schema without wiping data, commenting out the next 2 lines
    // should be your top priority before modifying this method.
    sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + LocationEntry.TABLE_NAME);
    sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + WeatherEntry.TABLE_NAME);
    onCreate(sqLiteDatabase);
}

}

public class WeatherContract {

// The "Content authority" is a name for the entire content provider, similar to the
// relationship between a domain name and its website.  A convenient string to use for the
// content authority is the package name for the app, which is guaranteed to be unique on the
// device.
public static final String CONTENT_AUTHORITY = "com.example.android.sunshine.app";

// Use CONTENT_AUTHORITY to create the base of all URI's which apps will use to contact
// the content provider.
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);

// Possible paths (appended to base content URI for possible URI's)
// For instance, content://com.example.android.sunshine.app/weather/ is a valid path for
// looking at weather data. content://com.example.android.sunshine.app/givemeroot/ will fail,
// as the ContentProvider hasn't been given any information on what to do with "givemeroot".
// At least, let's hope not.  Don't be that dev, reader.  Don't be that dev.
public static final String PATH_WEATHER = "weather";
public static final String PATH_LOCATION = "location";

// To make it easy to query for the exact date, we normalize all dates that go into
// the database to the start of the the Julian day at UTC.
public static long normalizeDate(long startDate) {
    // normalize the start date to the beginning of the (UTC) day
    Time time = new Time();
    time.set(startDate);
    int julianDay = Time.getJulianDay(startDate, time.gmtoff);
    return time.setJulianDay(julianDay);
}

/* Inner class that defines the table contents of the location table */
public static final class LocationEntry implements BaseColumns {

    public static final Uri CONTENT_URI =
            BASE_CONTENT_URI.buildUpon().appendPath(PATH_LOCATION).build();

    public static final String CONTENT_TYPE =
            ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_LOCATION;
    public static final String CONTENT_ITEM_TYPE =
            ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_LOCATION;

    // Table name
    public static final String TABLE_NAME = "location";

    // The location setting string is what will be sent to openweathermap
    // as the location query.
    public static final String COLUMN_LOCATION_SETTING = "location_setting";

    // Human readable location string, provided by the API.  Because for styling,
    // "Mountain View" is more recognizable than 94043.
    public static final String COLUMN_CITY_NAME = "city_name";

    // In order to uniquely pinpoint the location on the map when we launch the
    // map intent, we store the latitude and longitude as returned by openweathermap.
    public static final String COLUMN_COORD_LAT = "coord_lat";
    public static final String COLUMN_COORD_LONG = "coord_long";

    public static Uri buildLocationUri(long id) {
        return ContentUris.withAppendedId(CONTENT_URI, id);
    }
}

/* Inner class that defines the table contents of the weather table */
public static final class WeatherEntry implements BaseColumns {

    public static final Uri CONTENT_URI =
            BASE_CONTENT_URI.buildUpon().appendPath(PATH_WEATHER).build();

    public static final String CONTENT_TYPE =
            ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_WEATHER;
    public static final String CONTENT_ITEM_TYPE =
            ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_WEATHER;

    public static final String TABLE_NAME = "weather";

    // Column with the foreign key into the location table.
    public static final String COLUMN_LOC_KEY = "location_id";
    // Date, stored as long in milliseconds since the epoch
    public static final String COLUMN_DATE = "date";
    // Weather id as returned by API, to identify the icon to be used
    public static final String COLUMN_WEATHER_ID = "weather_id";

    // Short description and long description of the weather, as provided by API.
    // e.g "clear" vs "sky is clear".
    public static final String COLUMN_SHORT_DESC = "short_desc";

    // Min and max temperatures for the day (stored as floats)
    public static final String COLUMN_MIN_TEMP = "min";
    public static final String COLUMN_MAX_TEMP = "max";

    // Humidity is stored as a float representing percentage
    public static final String COLUMN_HUMIDITY = "humidity";

    // Humidity is stored as a float representing percentage
    public static final String COLUMN_PRESSURE = "pressure";

    // Windspeed is stored as a float representing windspeed  mph
    public static final String COLUMN_WIND_SPEED = "wind";

    // Degrees are meteorological degrees (e.g, 0 is north, 180 is south).  Stored as floats.
    public static final String COLUMN_DEGREES = "degrees";

    public static Uri buildWeatherUri(long id) {
        return ContentUris.withAppendedId(CONTENT_URI, id);
    }

    /*
        Student: This is the buildWeatherLocation function you filled in.
     */
    public static Uri buildWeatherLocation(String locationSetting) {
        return CONTENT_URI.buildUpon().appendPath(locationSetting).build();
    }

    public static Uri buildWeatherLocationWithStartDate(
            String locationSetting, long startDate) {
        long normalizedDate = normalizeDate(startDate);
        return CONTENT_URI.buildUpon().appendPath(locationSetting)
                .appendQueryParameter(COLUMN_DATE, Long.toString(normalizedDate)).build();
    }

    public static Uri buildWeatherLocationWithDate(String locationSetting, long date) {
        return CONTENT_URI.buildUpon().appendPath(locationSetting)
                .appendPath(Long.toString(normalizeDate(date))).build();
    }

    public static String getLocationSettingFromUri(Uri uri) {
        return uri.getPathSegments().get(1);
    }

    public static long getDateFromUri(Uri uri) {
        return Long.parseLong(uri.getPathSegments().get(2));
    }

    public static long getStartDateFromUri(Uri uri) {
        String dateString = uri.getQueryParameter(COLUMN_DATE);
        if (null != dateString && dateString.length() > 0)
            return Long.parseLong(dateString);
        else
            return 0;
    }
}

}

public class FetchWeatherTask extends AsyncTask<String, Void, Void> {

private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();

private final Context mContext;

public FetchWeatherTask(Context context) {
    mContext = context;
}

private boolean DEBUG = true;

/**
 * Helper method to handle insertion of a new location in the weather database.
 *
 * @param locationSetting The location string used to request updates from the server.
 * @param cityName A human-readable city name, e.g "Mountain View"
 * @param lat the latitude of the city
 * @param lon the longitude of the city
 * @return the row ID of the added location.
 */
long addLocation(String locationSetting, String cityName, double lat, double lon) {
    long locationId;

    // First, check if the location with this city name exists in the db
    Cursor locationCursor = mContext.getContentResolver().query(
            WeatherContract.LocationEntry.CONTENT_URI,
            new String[]{WeatherContract.LocationEntry._ID},
            WeatherContract.LocationEntry.COLUMN_LOCATION_SETTING + " = ?",
            new String[]{locationSetting},
            null);

    if (locationCursor.moveToFirst()) {
        int locationIdIndex = locationCursor.getColumnIndex(WeatherContract.LocationEntry._ID);
        locationId = locationCursor.getLong(locationIdIndex);
    } else {
        // Now that the content provider is set up, inserting rows of data is pretty simple.
        // First create a ContentValues object to hold the data you want to insert.
        ContentValues locationValues = new ContentValues();

        // Then add the data, along with the corresponding name of the data type,
        // so the content provider knows what kind of value is being inserted.
        locationValues.put(WeatherContract.LocationEntry.COLUMN_CITY_NAME, cityName);
        locationValues.put(WeatherContract.LocationEntry.COLUMN_LOCATION_SETTING, locationSetting);
        locationValues.put(WeatherContract.LocationEntry.COLUMN_COORD_LAT, lat);
        locationValues.put(WeatherContract.LocationEntry.COLUMN_COORD_LONG, lon);

        // Finally, insert location data into the database.
        Uri insertedUri = mContext.getContentResolver().insert(
                WeatherContract.LocationEntry.CONTENT_URI,
                locationValues
        );

        // The resulting URI contains the ID for the row.  Extract the locationId from the Uri.
        locationId = ContentUris.parseId(insertedUri);
    }

    locationCursor.close();
    // Wait, that worked?  Yes!
    return locationId;
}

/**
 * Take the String representing the complete forecast in JSON Format and
 * pull out the data we need to construct the Strings needed for the wireframes.
 *
 * Fortunately parsing is easy:  constructor takes the JSON string and converts it
 * into an Object hierarchy for us.
 */
private void getWeatherDataFromJson(String forecastJsonStr,
                                    String locationSetting)
        throws JSONException {

    // Now we have a String representing the complete forecast in JSON Format.
    // Fortunately parsing is easy:  constructor takes the JSON string and converts it
    // into an Object hierarchy for us.

    // These are the names of the JSON objects that need to be extracted.

    // Location information
    final String OWM_CITY = "city";
    final String OWM_CITY_NAME = "name";
    final String OWM_COORD = "coord";

    // Location coordinate
    final String OWM_LATITUDE = "lat";
    final String OWM_LONGITUDE = "lon";

    // Weather information.  Each day's forecast info is an element of the "list" array.
    final String OWM_LIST = "list";

    final String OWM_PRESSURE = "pressure";
    final String OWM_HUMIDITY = "humidity";
    final String OWM_WINDSPEED = "speed";
    final String OWM_WIND_DIRECTION = "deg";

    // All temperatures are children of the "temp" object.
    final String OWM_TEMPERATURE = "temp";
    final String OWM_MAX = "max";
    final String OWM_MIN = "min";

    final String OWM_WEATHER = "weather";
    final String OWM_DESCRIPTION = "main";
    final String OWM_WEATHER_ID = "id";

    try {
        JSONObject forecastJson = new JSONObject(forecastJsonStr);
        JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);

        JSONObject cityJson = forecastJson.getJSONObject(OWM_CITY);
        String cityName = cityJson.getString(OWM_CITY_NAME);

        JSONObject cityCoord = cityJson.getJSONObject(OWM_COORD);
        double cityLatitude = cityCoord.getDouble(OWM_LATITUDE);
        double cityLongitude = cityCoord.getDouble(OWM_LONGITUDE);

        long locationId = addLocation(locationSetting, cityName, cityLatitude, cityLongitude);

        // Insert the new weather information into the database
        Vector<ContentValues> cVVector = new Vector<ContentValues>(weatherArray.length());

        // OWM returns daily forecasts based upon the local time of the city that is being
        // asked for, which means that we need to know the GMT offset to translate this data
        // properly.

        // Since this data is also sent in-order and the first day is always the
        // current day, we're going to take advantage of that to get a nice
        // normalized UTC date for all of our weather.

        Time dayTime = new Time();
        dayTime.setToNow();

        // we start at the day returned by local time. Otherwise this is a mess.
        int julianStartDay = Time.getJulianDay(System.currentTimeMillis(), dayTime.gmtoff);

        // now we work exclusively in UTC
        dayTime = new Time();

        for(int i = 0; i < weatherArray.length(); i++) {
            // These are the values that will be collected.
            long dateTime;
            double pressure;
            int humidity;
            double windSpeed;
            double windDirection;

            double high;
            double low;

            String description;
            int weatherId;

            // Get the JSON object representing the day
            JSONObject dayForecast = weatherArray.getJSONObject(i);

            // Cheating to convert this to UTC time, which is what we want anyhow
            dateTime = dayTime.setJulianDay(julianStartDay+i);

            pressure = dayForecast.getDouble(OWM_PRESSURE);
            humidity = dayForecast.getInt(OWM_HUMIDITY);
            windSpeed = dayForecast.getDouble(OWM_WINDSPEED);
            windDirection = dayForecast.getDouble(OWM_WIND_DIRECTION);

            // Description is in a child array called "weather", which is 1 element long.
            // That element also contains a weather code.
            JSONObject weatherObject =
                    dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
            description = weatherObject.getString(OWM_DESCRIPTION);
            weatherId = weatherObject.getInt(OWM_WEATHER_ID);

            // Temperatures are in a child object called "temp".  Try not to name variables
            // "temp" when working with temperature.  It confuses everybody.
            JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
            high = temperatureObject.getDouble(OWM_MAX);
            low = temperatureObject.getDouble(OWM_MIN);

            ContentValues weatherValues = new ContentValues();

            weatherValues.put(WeatherEntry.COLUMN_LOC_KEY, locationId);
            weatherValues.put(WeatherEntry.COLUMN_DATE, dateTime);
            weatherValues.put(WeatherEntry.COLUMN_HUMIDITY, humidity);
            weatherValues.put(WeatherEntry.COLUMN_PRESSURE, pressure);
            weatherValues.put(WeatherEntry.COLUMN_WIND_SPEED, windSpeed);
            weatherValues.put(WeatherEntry.COLUMN_DEGREES, windDirection);
            weatherValues.put(WeatherEntry.COLUMN_MAX_TEMP, high);
            weatherValues.put(WeatherEntry.COLUMN_MIN_TEMP, low);
            weatherValues.put(WeatherEntry.COLUMN_SHORT_DESC, description);
            weatherValues.put(WeatherEntry.COLUMN_WEATHER_ID, weatherId);

            cVVector.add(weatherValues);
        }

        int inserted = 0;
        // add to database
        if ( cVVector.size() > 0 ) {
            ContentValues[] cvArray = new ContentValues[cVVector.size()];
            cVVector.toArray(cvArray);
            inserted = mContext.getContentResolver().bulkInsert(WeatherEntry.CONTENT_URI, cvArray);
        }

        Log.d(LOG_TAG, "FetchWeatherTask Complete. " + inserted + " Inserted");

    } catch (JSONException e) {
        Log.e(LOG_TAG, e.getMessage(), e);
        e.printStackTrace();
    }
}

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

    // If there's no zip code, there's nothing to look up.  Verify size of params.
    if (params.length == 0) {
        return null;
    }
    String locationQuery = params[0];

    // These two need to be declared outside the try/catch
    // so that they can be closed in the finally block.
    HttpURLConnection urlConnection = null;
    BufferedReader reader = null;

    // Will contain the raw JSON response as a string.
    String forecastJsonStr = null;

    String format = "json";
    String units = "metric";
    int numDays = 14;

    try {
        // Construct the URL for the OpenWeatherMap query
        // Possible parameters are avaiable at OWM's forecast API page, at
        // http://openweathermap.org/API#forecast
        final String FORECAST_BASE_URL =
                "http://api.openweathermap.org/data/2.5/forecast/daily?";
        final String QUERY_PARAM = "q";
        final String FORMAT_PARAM = "mode";
        final String UNITS_PARAM = "units";
        final String DAYS_PARAM = "cnt";
        final String APPID_PARAM = "APPID";

        Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
                .appendQueryParameter(QUERY_PARAM, params[0])
                .appendQueryParameter(FORMAT_PARAM, format)
                .appendQueryParameter(UNITS_PARAM, units)
                .appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
                .appendQueryParameter(APPID_PARAM, BuildConfig.OPEN_WEATHER_MAP_API_KEY)
                .build();

        URL url = new URL(builtUri.toString());

        // Create the request to OpenWeatherMap, and open the connection
        urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("GET");
        urlConnection.connect();

        // Read the input stream into a String
        InputStream inputStream = urlConnection.getInputStream();
        StringBuffer buffer = new StringBuffer();
        if (inputStream == null) {
            // Nothing to do.
            return null;
        }
        reader = new BufferedReader(new InputStreamReader(inputStream));

        String line;
        while ((line = reader.readLine()) != null) {
            // Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
            // But it does make debugging a *lot* easier if you print out the completed
            // buffer for debugging.
            buffer.append(line + "\n");
        }

        if (buffer.length() == 0) {
            // Stream was empty.  No point in parsing.
            return null;
        }
        forecastJsonStr = buffer.toString();
        getWeatherDataFromJson(forecastJsonStr, locationQuery);
    } catch (IOException e) {
        Log.e(LOG_TAG, "Error ", e);
        // If the code didn't successfully get the weather data, there's no point in attempting
        // to parse it.
    } catch (JSONException e) {
        Log.e(LOG_TAG, e.getMessage(), e);
        e.printStackTrace();
    } finally {
        if (urlConnection != null) {
            urlConnection.disconnect();
        }
        if (reader != null) {
            try {
                reader.close();
            } catch (final IOException e) {
                Log.e(LOG_TAG, "Error closing stream", e);
            }
        }
    }
    return null;
}

}

这是log ...

enter code here--------- beginning of crash
10-14 16:05:06.291 2443-2498/com.example.android.sunshine.app E/AndroidRuntime: FATAL EXCEPTION: ModernAsyncTask #1
                                                                                Process: com.example.android.sunshine.app, PID: 2443
                                                                                java.lang.RuntimeException: An error occured while executing doInBackground()
                                                                                    at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:137)
                                                                                    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
                                                                                    at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
                                                                                    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
                                                                                    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                                                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                                                    at java.lang.Thread.run(Thread.java:818)
                                                                                 Caused by: android.database.sqlite.SQLiteException: no such table: location (code 1): , while compiling: SELECT * FROM weather INNER JOIN location ON weather.location_id = location._id WHERE (location.location_setting = ? AND date >= ? ) ORDER BY date ASC
                                                                                    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)

0 个答案:

没有答案