Mọi người ơi em bị lỗi này mà không biết làm sao để tìm ra cái database đã tồn tại để xoá đi, mọi ngừoi cho em lời khuyên với ạ:
Caused by: android.database.sqlite.SQLiteException: table weather already exists (code 1): , while compiling: CREATE TABLE weather (_id INTEGER PRIMARY KEY AUTOINCREMENT,location_id INTEGER NOT NULL, date INTEGER NOT NULL, short_desc TEXT NOT NULL, weather_id INTEGER NOT NULL,min REAL NOT NULL, max REAL NOT NULL, humidity REAL NOT NULL, pressure REAL NOT NULL, wind REAL NOT NULL, degrees REAL NOT NULL, FOREIGN KEY (location_id) REFERENCES location (_id), UNIQUE (date, location_id) ON CONFLICT REPLACE);
Code
Weather provider:
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.sunshine.app.data;
import android.annotation.TargetApi;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
public class WeatherProvider extends ContentProvider {
// The URI Matcher used by this content provider.
private static final UriMatcher sUriMatcher = buildUriMatcher();
private WeatherDbHelper mOpenHelper;
static final int WEATHER = 100;
static final int WEATHER_WITH_LOCATION = 101;
static final int WEATHER_WITH_LOCATION_AND_DATE = 102;
static final int LOCATION = 300;
private static final SQLiteQueryBuilder sWeatherByLocationSettingQueryBuilder;
static{
sWeatherByLocationSettingQueryBuilder = new SQLiteQueryBuilder();
//This is an inner join which looks like
//weather INNER JOIN location ON weather.location_id = location._id
sWeatherByLocationSettingQueryBuilder.setTables(
WeatherContract.WeatherEntry.TABLE_NAME + " INNER JOIN " +
WeatherContract.LocationEntry.TABLE_NAME +
" ON " + WeatherContract.WeatherEntry.TABLE_NAME +
"." + WeatherContract.WeatherEntry.COLUMN_LOC_KEY +
" = " + WeatherContract.LocationEntry.TABLE_NAME +
"." + WeatherContract.LocationEntry._ID);
}
//location.location_setting = ?
private static final String sLocationSettingSelection =
WeatherContract.LocationEntry.TABLE_NAME+
"." + WeatherContract.LocationEntry.COLUMN_LOCATION_SETTING + " = ? ";
//location.location_setting = ? AND date >= ?
private static final String sLocationSettingWithStartDateSelection =
WeatherContract.LocationEntry.TABLE_NAME+
"." + WeatherContract.LocationEntry.COLUMN_LOCATION_SETTING + " = ? AND " +
WeatherContract.WeatherEntry.COLUMN_DATE + " >= ? ";
//location.location_setting = ? AND date = ?
private static final String sLocationSettingAndDaySelection =
WeatherContract.LocationEntry.TABLE_NAME +
"." + WeatherContract.LocationEntry.COLUMN_LOCATION_SETTING + " = ? AND " +
WeatherContract.WeatherEntry.COLUMN_DATE + " = ? ";
private Cursor getWeatherByLocationSetting(Uri uri, String[] projection, String sortOrder) {
String locationSetting = WeatherContract.WeatherEntry.getLocationSettingFromUri(uri);
long startDate = WeatherContract.WeatherEntry.getStartDateFromUri(uri);
String[] selectionArgs;
String selection;
if (startDate == 0) {
selection = sLocationSettingSelection;
selectionArgs = new String[]{locationSetting};
} else {
selectionArgs = new String[]{locationSetting, Long.toString(startDate)};
selection = sLocationSettingWithStartDateSelection;
}
return sWeatherByLocationSettingQueryBuilder.query(mOpenHelper.getReadableDatabase(),
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
}
private Cursor getWeatherByLocationSettingAndDate(
Uri uri, String[] projection, String sortOrder) {
String locationSetting = WeatherContract.WeatherEntry.getLocationSettingFromUri(uri);
long date = WeatherContract.WeatherEntry.getDateFromUri(uri);
return sWeatherByLocationSettingQueryBuilder.query(mOpenHelper.getReadableDatabase(),
projection,
sLocationSettingAndDaySelection,
new String[]{locationSetting, Long.toString(date)},
null,
null,
sortOrder
);
}
/*
Students: Here is where you need to create the UriMatcher. This UriMatcher will
match each URI to the WEATHER, WEATHER_WITH_LOCATION, WEATHER_WITH_LOCATION_AND_DATE,
and LOCATION integer constants defined above. You can test this by uncommenting the
testUriMatcher test within TestUriMatcher.
*/
static UriMatcher buildUriMatcher() {
// 1) The code passed into the constructor represents the code to return for the root
// URI. It's common to use NO_MATCH as the code for this case. Add the constructor below.
// 2) Use the addURI function to match each of the types. Use the constants from
// WeatherContract to help define the types to the UriMatcher.
// 3) Return the new matcher!
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = WeatherContract.CONTENT_AUTHORITY;
// For each type of URI you want to add, create a corresponding code.
matcher.addURI(authority, WeatherContract.PATH_WEATHER, WEATHER);
matcher.addURI(authority, WeatherContract.PATH_WEATHER + "/*", WEATHER_WITH_LOCATION);
matcher.addURI(authority, WeatherContract.PATH_WEATHER + "/*/#", WEATHER_WITH_LOCATION_AND_DATE);
matcher.addURI(authority, WeatherContract.PATH_LOCATION, LOCATION);
return matcher;
}
/*
Students: We've coded this for you. We just create a new WeatherDbHelper for later use
here.
*/
@Override
public boolean onCreate() {
mOpenHelper = new WeatherDbHelper(getContext());
return true;
}
/*
Students: Here's where you'll code the getType function that uses the UriMatcher. You can
test this by uncommenting testGetType in TestProvider.
*/
@Override
public String getType(Uri uri) {
// Use the Uri Matcher to determine what kind of URI this is.
final int match = sUriMatcher.match(uri);
switch (match) {
// Student: Uncomment and fill out these two cases
// case WEATHER_WITH_LOCATION_AND_DATE:
// case WEATHER_WITH_LOCATION:
case WEATHER_WITH_LOCATION_AND_DATE:
return WeatherContract.WeatherEntry.CONTENT_ITEM_TYPE;
case WEATHER_WITH_LOCATION:
return WeatherContract.WeatherEntry.CONTENT_TYPE;
case WEATHER:
return WeatherContract.WeatherEntry.CONTENT_TYPE;
case LOCATION:
return WeatherContract.LocationEntry.CONTENT_TYPE;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// Here's the switch statement that, given a URI, will determine what kind of request it is,
// and query the database accordingly.
Cursor retCursor;
switch (sUriMatcher.match(uri)) {
// "weather/*/*"
case WEATHER_WITH_LOCATION_AND_DATE:
{
retCursor = getWeatherByLocationSettingAndDate(uri, projection, sortOrder);
break;
}
// "weather/*"
case WEATHER_WITH_LOCATION: {
retCursor = getWeatherByLocationSetting(uri, projection, sortOrder);
break;
}
// "weather"
case WEATHER: {
retCursor = mOpenHelper.getReadableDatabase().query(
WeatherContract.WeatherEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
break;
}
// "location"
case LOCATION: {
retCursor = mOpenHelper.getReadableDatabase().query(
WeatherContract.LocationEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
break;
}
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}
/*
Student: Add the ability to insert Locations to the implementation of this function.
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
Uri returnUri;
switch (match) {
case WEATHER: {
normalizeDate(values);
long _id = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, values);
if ( _id > 0 )
returnUri = WeatherContract.WeatherEntry.buildWeatherUri(_id);
else
throw new android.database.SQLException("Failed to insert row into " + uri);
break;
}
case LOCATION: {
long _id = db.insert(WeatherContract.LocationEntry.TABLE_NAME, null, values);
if ( _id > 0 )
returnUri = WeatherContract.LocationEntry.buildLocationUri(_id);
else
throw new android.database.SQLException("Failed to insert row into " + uri);
break;
}
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return returnUri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Stfinal SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
int rowsDeleted;
// this makes delete all rows return the number of rows deleted
if ( null == selection ) selection = "1";
switch (match) {
case WEATHER:
rowsDeleted = db.delete(
WeatherContract.WeatherEntry.TABLE_NAME, selection, selectionArgs);
break;
case LOCATION:
rowsDeleted = db.delete(
WeatherContract.LocationEntry.TABLE_NAME, selection, selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Because a null deletes all rows
if (rowsDeleted != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsDeleted;
//udent: Start by getting a writable database
// Student: Use the uriMatcher to match the WEATHER and LOCATION URI's we are going to
// handle. If it doesn't match these, throw an UnsupportedOperationException.
// Student: A null value deletes all rows. In my implementation of this, I only notified
// the uri listeners (using the content resolver) if the rowsDeleted != 0 or the selection
// is null.
// Oh, and you should notify the listeners here.
}
private void normalizeDate(ContentValues values) {
// normalize the date value
if (values.containsKey(WeatherContract.WeatherEntry.COLUMN_DATE)) {
long dateValue = values.getAsLong(WeatherContract.WeatherEntry.COLUMN_DATE);
values.put(WeatherContract.WeatherEntry.COLUMN_DATE, WeatherContract.normalizeDate(dateValue));
}
}
@Override
public int update(
Uri uri, ContentValues values, String selection, String[] selectionArgs) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
int rowsUpdated;
switch (match) {
case WEATHER:
normalizeDate(values);
rowsUpdated = db.update(WeatherContract.WeatherEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
case LOCATION:
rowsUpdated = db.update(WeatherContract.LocationEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if (rowsUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsUpdated;
}
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
switch (match) {
case WEATHER:
db.beginTransaction();
int returnCount = 0;
try {
for (ContentValues value : values) {
normalizeDate(value);
long _id = db.insert(WeatherContract.WeatherEntry.TABLE_NAME, null, value);
if (_id != -1) {
returnCount++;
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
getContext().getContentResolver().notifyChange(uri, null);
return returnCount;
default:
return super.bulkInsert(uri, values);
}
}
@Override
@TargetApi(11)
public void shutdown() {
mOpenHelper.close();
super.shutdown();
}
}
weatherdbhelper
package com.example.android.sunshine.app.data;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.example.android.sunshine.app.data.WeatherContract.LocationEntry;
import com.example.android.sunshine.app.data.WeatherContract.WeatherEntry;
/**
* Manages a local database for weather data.
*/
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) {
final String SQL_CREATE_LOCATION_TABLE = "CREATE TABLE " + WeatherEntry.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 " +
" );";
// 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.
final String SQL_CREATE_WEATHER_TABLE = "CREATE TABLE " + WeatherEntry.TABLE_NAME + " (" +
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_LOCATION_TABLE);
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);
}
}
weather contract
package com.example.android.sunshine.app.data;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.net.Uri;
import android.provider.BaseColumns;
import android.text.format.Time;
/**
* Defines table and column names for the weather database.
*/
public class WeatherContract {
// 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.
// 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";
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
Students: This is where you will add the strings. (Similar to what has been
done for WeatherEntry)
*/
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;
}
}
}