onUpgrade
的SQLiteOpenHelper
方法是否曾被调用过?如果是这样,什么时候被召唤?如果它没有被开发人员调用,那为什么呢?这个功能到底发生了什么?我已经看到了删除所有表的示例,但随后评论说放弃所有表并不是你应该做的。有什么建议?
答案 0 :(得分:36)
对于那些想要了解调用onUpgrade()
的确切时刻的人,可能是在调用getReadableDatabase()
或getWriteableDatabase()
时。
对于那些不清楚如何确保它被触发的人,答案是:当提供给SqLiteOpenHelper
的构造函数的数据库版本更新时,会触发它。这是一个例子
public class dbSchemaHelper extends SQLiteOpenHelper {
private String sql;
private final String D_TAG = "FundExpense";
//update this to get onUpgrade() method of sqliteopenhelper class called
static final int DB_VERSION = 2;
static final String DB_NAME = "fundExpenseManager";
public dbSchemaHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
// TODO Auto-generated constructor stub
}
现在...... onUpgrade()
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
sql = "ALTER TABLE " + fundExpenseSchema.Expense.TABLE_NAME + " ADD COLUMN " + fundExpenseSchema.Expense.FUNDID + " INTEGER";
arg0.execSQL(sql);
}
答案 1 :(得分:28)
如果您正在使用SQLiteOpenHelper,则每当您更改数据库版本时都会调用onUpgrade。 还有一个额外的要求。数据库名称必须保持不变。
Old Version:
dbName = "mydb.db"
dbVersion = 1
New Version:
dbName = "mydb.db"
dbVersion = 2
在内容提供程序的onCreate中,您创建了一个采用这些参数的SQLiteOpenHelper实例。您的SQLiteOpenHelper实现如下所示:
public static final class MySQLiteOpenHelper extends SQLiteOpenHelper {
public MySQLiteOpenHelper(Context context, int dbVersion, String dbName) {
super(context, dbName, null, dbVersion);
}
@Override
public void onCreate(SQLiteDatabase db) {
//Code to create your db here
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Code to upgrade your db here
}
}
答案 2 :(得分:21)
在构造版本比打开的数据库版本更新的SQLiteOpenHelper时调用它。做什么取决于旧版本和新版本之间的数据库更改。如果不删除已更改的表,则唯一的情况是更改的位置超过添加的列。然后,您可以使用ALTER TABLE语句将新列添加到表签名。
答案 3 :(得分:4)
查看所有帖子并运行调试代码时,我仍然不清楚何时会看到onUpgrade被调用。我开始认为Android有一个严重的缺陷..
此页面上的信息让我得出了最终解决方案。非常感谢所有贡献者!
这为我解决了......
public class DatabaseHelper extends SQLiteOpenHelper {
public static String TAG = DatabaseHelper.class.getName();
private static final int DATABASE_VERSION = 42;
private static final String DATABASE_NAME = "app_database";
private static final String OLD_TABLE = "old_and_useless";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion ) {
if( newVersion > oldVersion) {
Log.d( TAG, "cool! you noticed." );
db.execSQL( "DROP TABLE IF EXISTS " + OLD_TABLE );
// other calls like onCreate if necessary
} else {
Log.d( TAG, "Hey! didn't you see me?" );
}
}
public void checkDatabaseVersion() {
SQLiteDatabase db = this.getWritableDatabase();
// if the DATABASE_VERSION is newer
// onUpgrade is called before this is reached
}
// other code removed for readability...
}
getWritableDatabase()和getReadableDatabase()确实会导致onUpgrade调用。我没有检查其他方法,因为这些符合我的需求。
继续阅读,踢球者即将到来......
当我终于意识到我的调试期间db版本正在更新时,我的初始Activity中的代码启发了我... ugh!
DatabaseHelper dbHelper = new DatabaseHelper( this );
dbHelper.checkDatabaseVersion();
注意:调用DatabaseHelper构造函数会更新db版本
在构造函数调用之后,db被标记为新版本。在调用getWritableDatabase()或getReadableDatabase()之前杀死应用程序并且您使用的是新版本。此后,新的执行永远不会调用onUpgrade方法,直到再次增加DATABASE_VERSION。 (叹息!现在看起来很荒谬:)
我的建议是在应用的早期阶段添加某种“checkDatabaseVersion()”。或者,如果您创建一个SQLiteOpenHelper对象,请确保在应用程序死亡之前调用其中一个方法(getWritableDatabase(),getReadableDatabase()等)。
我希望这可以节省其他人同样的头脑刮伤!...:p
答案 4 :(得分:2)
查看// don't forget to add a doctype. since you didn't i'm picking HTML5
<!DOCTYPE html>
<html>
<head>
// also add a character set
<meta charset='utf-8'>
<title>DeportesRulz.com</title>
<script>
function AJAX() {
try{
xmlHttp=new XMLHttpRequest(); // Firefox, Opera 8.0+, Safari
return xmlHttp;
}
catch (e) {
try{
xmlHttp=new ActiveXObject('Msxml2.XMLHTTP'); // Internet Explorer
return xmlHttp;
}
catch (e) {
try{
xmlHttp=new ActiveXObject('Microsoft.XMLHTTP');
return xmlHttp;
}
catch (e) {
alert('Your browser does not support AJAX.');
return false;
}
}
}
}
// Timestamp for preventing IE caching the GET request (common function)
function fetch_unix_timestamp() {
return parseInt(new Date().getTime().toString().substring(0, 10))
}
//takes a div element as a parameter. the data-rownum on that div will be used as the rownumber passed to file1.php
function refreshLiveStatus(targetDiv) {
// access the data-rownum attribute of the targetDiv
var rowNum = targetDiv.dataset['rownum'];
// if you don't need the square brackets, remove them
var url = './file1.php?row=[' + rowNum + ']';
var xmlHttp_three = AJAX();
// No cache
var timestamp = fetch_unix_timestamp();
// you had `url+'?t='+timestamp` here before. you can't have multiple '?' in a url like that. you need to use `&` as below
var nocacheurl = url+'&t='+timestamp;
// The code...
xmlHttp_three.onreadystatechange = function() {
if(xmlHttp_three.readyState==4) {
targetDiv.innerHTML=xmlHttp_three.responseText;
// start the next refresh
setTimeout(function() {
refreshLiveStatus(targetDiv);
},seconds);
}
}
xmlHttp_three.open('GET',nocacheurl,true);
xmlHttp_three.send(null);
}
var seconds = 5; // just set it here so you don't have to keep setting the variable (unless you want different refresh rates??)
seconds *= 1000; // if they're seconds make them seconds and save yourself the trouble of having to remember to do `* 1000` everywhere
// Start the refreshing process
// function to replace window.onload below. It's not necessary to replace window.onload but this will let you easily add more than one function to the window.onload
// console logs left in for science
function ready(fn) {
console.log('readying');
if (document.readyState != 'loading') {
console.log('loading...');
fn();
} else {
console.log('content not loaded');
document.addEventListener('DOMContentLoaded', fn);
}
}
ready(function() {
// querySelectorAll lets you use CSS selectors to select HTML elements. Note that the `liveStatus` class is added in the PHP code below.
var divs = document.querySelectorAll('div.liveStatus');
console.log(divs); // left here for you to what's selected
for(var i = 0, imax = divs.length; i < imax; i++) {
// the below is a closure. definitely read about these if you don't know what they are already
(function(liveDiv) {
refreshLiveStatus(liveDiv);
})(divs[i]);
}
});
// style the .liveStatus div. leave it out and see what happens
</script>
<style type='text/css'>
div.liveStatus {
display: inline-block;
}
</style>
</head>
<body>
<?php
//Obtener fecha
date_default_timezone_set('America/Caracas');
$fechaabrev = strftime("Sat, %b 17, %y");
//[Variables globales]
$xml = simplexml_load_file('./MLB.xml');
$juegos = count($xml->EventType->Date);
//Obtener todos los juegos
// you can use `$i<$juegos` instead of `$i<=$juegos-1` and save having to do that subtraction
for ($i=0;$i<$juegos;$i++) {
//Obtener solo juegos del dia
if ($xml->EventType->Date[$i]->attributes()->DTEXT == $fechaabrev) {
$juegosdeldia = count($xml->EventType->Date[$i]->Event);
//Bucle principal juegos del dia
for ($k=0;$k<$juegosdeldia;$k++) {
$juego_dia = $xml->EventType->Date[$i]->attributes()->DTEXT.' ';
$juego_horaf = $xml->EventType->Date[$i]->Event[$k]->Time->attributes()->TTEXT.' ';
$juego_horaf = explode(" ", $juego_horaf);
$juego_hora = $juego_horaf[0];
$juego_live = $xml->EventType->Date[$i]->Event[$k]->attributes()->LIVE_ENABLED.' ';
$juego_ligaf = $xml->EventType->Date[$i]->Event[$k]->NOTE.' ';
$juego_ligaf = explode(" ", $juego_ligaf);
if ($juego_ligaf[0] == 'AMERICAN') {
$juego_liga = 'American League';
} else if ($juego_ligaf[0] == 'NATIONAL') {
$juego_liga = 'National League';
}
$equipos = count($xml->EventType->Date[$i]->Event[$k]->Competitor);
//Bucle equipos
for ($j=0;$j<=$equipos-1;$j++) {
//Obtener equipo A
if ($xml->EventType->Date[$i]->Event[$k]->Competitor[$j]->attributes()->NUM == 2) {
$equipo_a = $xml->EventType->Date[$i]->Event[$k]->Competitor[$j]->attributes()->NAME;
}//--Fin Obtener equipo A--
//Obtener equipo B
if ($xml->EventType->Date[$i]->Event[$k]->Competitor[$j]->attributes()->NUM == 1) {
$equipo_b = $xml->EventType->Date[$i]->Event[$k]->Competitor[$j]->attributes()->NAME;
}//--Fin Obtener equipo B--
}//--Fin Bucle equipos--
//--------------------------------------------[Imprimiendo datos]---------------------------------------------------------//
// note how we add the rownumber with `...[" . ($k+1) . "]...`
// also see how we added the `liveStatus` class AND the data-rownum attribute to the "live" div
echo "
<table cellpadding='3' cellspacing='1' class='tablehead' style='background-color:white;'>
<tbody>
<tr class='stathead'>
<td colspan='5' style='background-color:#0B3861;color:white;'>
[" . ($k+1) . "] $equipo_a vs $equipo_b | [MLB] $juego_liga
<div class='liveStatus' name='live[$k]' data-rownum='$k' id='live[$k]'></div>
</td>
</tr>
<tr class='colhead' style='text-align:center;'>
<td>$juego_hora</td>
<td>A GANAR</td>
<td>ALTA/BAJA (6.5)</td>
<td>RUN LINE</td>
<td>
ALTA/BAJA (3.5 | 5to inning)
<div id='odds'></div>
</td>
</tr>
</tbody>
</table>";
//------------------------------------------[Fin Imprimiendo datos]---------------------------------------------------------//
}//--Fin Bucle principal juegos del dia--
}//--Fin Obtener solo juegos del dia--
}//--Fin Obtener todos los juegos--
?>
</body>
</html>
源代码,我们可以通过SqliteOpenHelper
或onCreate()
方法了解onUpgrade()
,onDowngrade
和getWritableDatabase()
。
getReadableDatabase()
答案 5 :(得分:1)
当您致电getReadableDatabase
或getWritableDatabase
时,实际上称为。
深度潜水:
您在SQLiteOpenHelper
的构造函数中传递版本号,该构造函数存储在名为mNewVersion
的变量中。而已。此时没有任何事情发生。
每次调用getReadableDatabase或getWritableDatabase时,它都会调用名为getDatabaseLocked
的方法。此方法将获取数据库的现有版本号,并将其与mNewVersion
进行比较。
onCreate
onUpgrade
。 我应该在onCreate和onUpgrade上写什么?
onCreate
应该包含第一次创建架构的代码。
您可以第一次将onUpgrade
留空,因为第一次不会调用它。如果您想在以后更改表结构,那么该代码应该放在这里。
SQLiteOpenHelper.java (源代码)
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
return getDatabaseLocked(false);
}
}
private SQLiteDatabase getDatabaseLocked(boolean writable) {
.
.
final int version = db.getVersion();
if (version != mNewVersion) {
if (db.isReadOnly()) {
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
db.beginTransaction();
try {
if (version == 0) {
onCreate(db);
} else {
if (version > mNewVersion) {
onDowngrade(db, version, mNewVersion);
} else {
onUpgrade(db, version, mNewVersion);
}
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
onOpen(db);
}