کپی و آپدیت دیتابیس ( آموزش کامل )
تا به امروز، من توی برنامه هام دیتابیس رو کپی میکردم و ازش استفاده میکردم، در آپدیت ها دیتابیس قبلی رو پاک میکردم و دیتابیس جدید رو جایگزین میکردم. اما این روش همیشه جواب نمید!
1 : زمانی که حجم دیتابیس بالا باشه
2 : توی بعضی از گوشی ها دیتابیس قبلی پاک نمیشه، در نتیجه آپدیت دیتابیس با مشکل روبه رو میشه
.
روشی که من پیدا کردم استفاده از SQLiteAssetHelper هست که یک Library کامل برای کپی، آپدیت و ... دیتابیس هست.
در دیتابیس هایی که حجم بالایی دارن یک راه اینه که به فایل های کوچکتر تقسیم بشن که این راه حل من نیست پس این Library میتونه گزینه خوبی باشه
لینک GitHub : لینک
طریقه استفاده : sqliteassethelper-2.0.1.jar رو در فولدر libs کپی میکنیم
برای استفاده در API پایین تر از 10 ( طبق مستندات ) باید دیتابیس رو به صورت فایل زیپ قرار بدیم مانند : database.sqlite.zip
بعد کلاس زیر رو میسازیم
public class DataBaseConnection extends SQLiteAssetHelper { private static final String DATABASE_NAME = "database.sqlite.zip"; private static final int DATABASE_VERSION = 1; public DataBaseConnection(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } }
خوب تا اینجاشو بلد بودم، ولی دیتابیسم یا خالی کپی میشه یا اصلا کپی نمیشه
ممنون میشم اگر از این Library استفاده کردید یا علامند هستید، این روش رو تست کنید و آموزش رو کامل کنید
اگر هم راه حل دیگه ای با توجه به شرایط میدونید در پاسخ درج کنید
اینم برای ارتباط با دیتابیس
private DataBaseConnection db = new DataBaseConnection(this);
آپدیت کردن هم مانند دیتابیس با حجم بالا تست شد و درست کار میکنه.
از اول کامل توضیح میدم.( به دلیل تغییرات جزئی توی کانستراکتور کلاس )
1 : کلاس sqliteassethelper-2.0.1.jar رو به پروژه اضافه کنید.
2 : یک کلاس به نام DataBaseConnection که Extends شده از SQLiteAssetHelper هست رو بسازید و داخلش کدهای زیر رو قرار بدید
public class DataBaseConnection extends SQLiteAssetHelper { public DataBaseConnection(Context context, String name, int version) { super(context, name, null, version); setForcedUpgrade(version); } public SQLiteDatabase database() { SQLiteDatabase database = null; return database; } }
3 : در کلاس ActivityMain یا هر کلاسی که میخواید از دیتابیس استفاده کنید کافیه کد زیر رو استفاده کنید
DataBaseConnection db = new DataBaseConnection(this, "database", 5); final SQLiteDatabase database = db.getReadableDatabase(); Cursor cursor = database.rawQuery("SELECT * FROM test ", null); while (cursor.moveToNext()) { try { Log.i("LOG", cursor.getString(cursor.getColumnIndex("id"))); } catch (Exception e) { } } cursor.close(); database.close();
خوب اول بگم این کدی که نوشتم چیکار میکنه، این کد میره از Assets از پوشه databases ، دیتابیسی با نام database که پسوند زیپ داره رو باز میکنه، اگر به نسخه 5 آپدیت نبود اونو آپدیت میکنه و بعد از Table ی به نام test تمام id ها رو لاگ میکنه.
تغییراتی که من دادم اینه که setForcedUpgrade(version); رو به ورژن اضافه کرد، که باعث میشه آپدیت فورس بشه، و version رو به پارامتر های ورودی کانستراکتور اضافه کردم که به راحتی بتونیم ازش استفاده کنید.(در کارهای بزرگتر میتونید به عنوان فیلد تعریفش کنید)
فقط یک نکته وجود داره که اونم اینه که نام دیتابیس و فایل زیپ باید یکی باشن یعنی نام اگر database.sqlite هست، فایل زیپ باید database.zip باشه.
روش های دیگری هم برای آپدیت توی مستندات لینکی که در سوال گذاشتم هست، ولی من چون میخواستم دیتابیس پاک بشه و بعد دوباره کپی بشه این روش برام کارایی داشت، اگر روشی که میخواید این نیست، میتونید به مستندات مراجعه کنید.
این کد من برای کپی دیتا بیسم تو کارت حافظه ویا حافظه گوشیه این کد شما رو کجا استفاده کنم ممنون میشم کمکم کنید خیلی کارم گیره وقتم کوتاه خواهشا کمکم کنید کل انجمنو گشتم ظاهرا فقط شما اطلاعات کافی دارین در این مورد پیشاپیش ممنون
public class G extends Application {
public static Context context;
public static LayoutInflater inflater;
public static Handler HANDLER = new Handler();
public static Activity currentActivity;
public static SQLiteDatabase database;
public static StructApplication selectedApplication;
public static StructApplicationFav selectedApplicationFav;
public static final String DIR_SDCARD = Environment.getExternalStorageDirectory().getAbsolutePath();
public static String DIR_APP = DIR_SDCARD + "/my_database";
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
new File(DIR_APP).mkdirs();
prepareDB();
}
private boolean prepareDB() {
try {
String state = Environment.getExternalStorageState();
InputStream is = context.getAssets().open("norooz.sqlite");
if (state.equals(Environment.MEDIA_MOUNTED))
{
File DB_PATH = new File(DIR_APP + "/norooz.sqlite");
Log.i("DB_PATHDB_PATHDB_PATHDB_PATHDB_PATHDB_PATH", "DB_PATH=" + DB_PATH);
if (DB_PATH.exists()) {
database = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
Log.i("databasedatabasedatabasedatabasedatabasedatabase", "database=" + database);
return true;
}
else {
if (copy(new FileOutputStream(DB_PATH), is)) {
database = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
return true;
}
else {
return false;
}
}
}
else {
Log.i("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", "state=" + state);
DIR_APP = getFilesDir().toString();
File dbFile = new File(getFilesDir().toString() + "/" + "/norooz.sqlite");
if (dbFile.exists()) {
database = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
return true;
}
else {
FileOutputStream os = openFileOutput("norooz.sqlite", context.MODE_PRIVATE);
if (copy(os, is)) {
database = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
return true;
}
else {
return false;
}
}
}
}
catch (Exception e) {
e.printStackTrace();
return false;
}
}
private boolean copy(OutputStream os, InputStream is) {
try {
int readed = 0;
byte[] buffer = new byte[8 * 1024];
while ((readed = is.read(buffer)) > 0) {
os.write(buffer, 0, readed);
}
try {
is.close();
}
catch (Exception e) {
e.printStackTrace();
}
try {
os.flush();
}
catch (Exception e) {
e.printStackTrace();
}
try {
os.close();
}
catch (Exception e) {
e.printStackTrace();
}
return true;
}
catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
ممنون از معرفی این کتابخونه ، من استفاده کردم مشکلم حل شد
الان یه مشکل کوچیک دارم
تا این دیتابیس کپی بشه روی گوشی کاربر تصویر صفحه سیاه باقی میمونه.
چطوری می تونم یک progress هنگام کپی نمایش بدم ؟
کد های فراخوانی دیتابیس رو داخل کلاس G قرار دادم و در تمام کلاس ها فقط فراخوانی کردم
من نمیتونم استفاده کنم تماما مراحل رو هم درست میرم از این خط خطا میگیره
final SQLiteDatabase database = db.getReadableDatabase();
"CREATE TABLE IF NOT EXISTS news (" + "news_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , " + "news_title TEXT, " + "news_desc TEXT, " + "news_date INTEGER " + ")");
چرا من نمیتونم از این لایبری استفاده کنم.هر کاری میکنم خطا میده؟؟؟؟؟؟؟؟؟
کدها رو دقیقا کپی میکنم.یه دیتابیس هم ساختم که یک جدول به اسم table داره که داخلش فقط یک سطر به اسم id هست و اونو زیپ کردم داخل assets قرار دادم.
public class DbActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); DataBaseConnection db = new DataBaseConnection(this, "database", 5); final SQLiteDatabase database = db.getReadableDatabase(); Cursor cursor = database.rawQuery("SELECT * FROM table", null); while (cursor.moveToNext()) { try { Log.i("LOG", cursor.getString(cursor.getColumnIndex("id"))); } catch (Exception e) { } } cursor.close(); database.close(); }
خط 20 که خطا گرفته این هست:
Cursor cursor = database.rawQuery("SELECT * FROM table", null);
public void insert(Long id,String title,String desc,String date){
ContentValues cv=new ContentValues();
cv.put("news_id", id);
cv.put("news_title", title);
cv.put("news_desc", desc);
cv.put("news_date", date);
}
public class NewsFragment extends Fragment {
private ArrayAdapter adapter;
public NewsFragment(){}
ProgressDialog mProgressDialog;
ListView lstContent;
ConnectionDetector cd;
DataBaseConnection db;
private ArrayList<StructNews> News = new ArrayList<StructNews>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_news, container, false);
lstContent = (ListView) rootView.findViewById(R.id.lstContent);
new TestAsync().execute();
cd = new ConnectionDetector(getActivity());
db = new DataBaseConnection(getActivity(), "database", 5);
return rootView;
}
class TestAsync extends AsyncTask<String, Void, String>
{
@Override
protected String doInBackground(String... params) {
if (!cd.isConnectingToInternet()){
final SQLiteDatabase database = db.getReadableDatabase();
Cursor cursor = database.rawQuery("SELECT * FROM news ", null);
StructNews task = new StructNews();
while (cursor.moveToNext()) {
task.id = cursor.getLong(cursor.getColumnIndex("news_id"));
task.title = cursor.getString(cursor.getColumnIndex("news_title"));
task.desc = cursor.getString(cursor.getColumnIndex("news_desc"));
task.date = cursor.getString(cursor.getColumnIndex("news_date"));
News.add(task);
}
cursor.close();
}else{
}
NewsRead();
return null;
}
protected void onPreExecute () {
mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.setMessage("لطفا صبر کنید...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
super.onPreExecute();
}
protected void onPostExecute(String result){
mProgressDialog.dismiss();
// if (!cd.isConnectingToInternet()){
// Toast.makeText(getActivity().getApplicationContext(), "خطا در برقراری ارتباط.", Toast.LENGTH_SHORT).show();
// }else{
adapter = new AdapterNews(News);
lstContent.setAdapter(adapter);
// }
}
public void onResume() {
adapter.notifyDataSetChanged();
}
}
public void NewsRead() {
String result = Webservice.readUrl("http://192.168.1.1/android/note_server/news.php?action=read", null);
if (result != null) {
try {
News.clear();
JSONArray tasks = new JSONArray(result);
for (int i = 0; i < tasks.length(); i++) {
JSONObject object = tasks.getJSONObject(i);
StructNews task = new StructNews();
task.id = object.getLong("news_id");
task.title = object.getString("news_title");
task.desc = object.getString("news_desc");
task.date = object.getString("news_date") ;
News.add(task);
}
}
برای insert توی دیتابیس از کد زیر استفاده کنید
DataBaseConnection db = new DataBaseConnection(getActivity(), "db_name", App.databaseVersion); final SQLiteDatabase database = db.getWritableDatabase(); database.execSQL(" insert into ... ");
database.close();
برای select کردن هم از کدی که بالا قرار دادم استفاده کنید.
اینکه شما json رو چجوری parse میکنید، ربطی به دیتابیس نداره، شما اطلاعات رو از وب میگیرید، حالا به هر روشی، بعد داخل دیتابیس insert میکنید، سری بعدی اگر آفلاین بود مستقیم از دیتابیس میخونید.
کد هاتون رو یک نگاهی کردم، توی نامگذاری یکم مشکل دارید، هیچ وقت نام متد یا آرایه رو با حرف بزرگ شروع نکنید، و اگر نیازی به Constructor ندارید، ازش استفاده نکنید. کلا تمیز نوشتن خیلی بهتون کمک میکنه، و اگر فقط قسمتی که مشکل دارید رو تو پاسخ درج کنید خیلی بهتره، چون دوستان سریع میبینن و جوابو پیدا میکنن، ولی کد کامل کلاستون رو که میذارید، باید بشینیم از بالا بخونیم که ببینیم چه کارهایی انجام دادید.
********** آپدیت:
database.execSQL("INSERT INTO student (student_id,student_name_student_age) VALUES ('" + student.id + "','"+student.name+"','" + student.age + "' )"
همین کد ها، اطلاعات student رو توی دیتابیس ذخیره میکنه، اگر شما یک آرایه از student ها دارید، خوب فقط کافیه این خط کد رو توی یک حلقه for قرار بدید و تعداد تکرار رو به اندازه array.size قرار بدید. اون 2 خط بالا رو هم باید قبل از for و 1 خط اخر رو باید بعد از for بنویسید
***** آپدیت 2 *******
دستور گرفتن آخرین آیدی
select student_id from student where student_id = (select MAX(student_id) from student)
این کد سمت php درسته حاج حسین؟ یکی از بچه های PHP گفت به این شکل میشه :گفتم شما هم یه نگاه بندازید ببینید با این کد آیدی که در آخر نوشتید می خوره یا نه.
$result = mysqli_query($connection,"SELECT * FROM news WHERE (`id` > '{$id}')");
public void newsRead(){ String url = "http://192.168.1.1/android/note_server/news.php"; ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("action", "read")); params.add(new BasicNameValuePair("news_id", url)); String result = Webservice.readUrl(url, params); if (result != null) { try { JSONArray tasks = new JSONArray(result); DataBaseConnection db = new DataBaseConnection(this, "database", 5); final SQLiteDatabase database = db.getWritableDatabase(); for (int i = 0; i < tasks.length(); i++) { JSONObject object = tasks.getJSONObject(i); StructTask task = new StructTask(); task.id = object.getLong("news_id"); task.title = object.getString("news_title"); task.desc = object.getString("news_desc"); task.date = object.getString("news_date") ; database.execSQL("INSERT INTO news (news_title,news_desc,news_date) VALUES ('" + task.title + "','" + task.desc + "','" + task.date + "')"); Cursor cursor = database.rawQuery("select news_id from news where news_id = (select MAX(news_id) from news)", null); while (cursor.moveToNext()) { StructTask localTask = new StructTask(); localTask.id = cursor.getLong(cursor.getColumnIndex("news_id")); } cursor.close(); G.tasks.add(task); } database.close(); } catch (JSONException e) { e.printStackTrace(); } }
دوباره سلام حسینی جان : من یه هفته ای نبودم الان اومدم و فقط سر همین یه تیکه کد مشکل دارم تا کامل حل بشه. این news_id داخلش مقدار آخرین آیدی رو ذخیره می کنه داخل خودش حالا چطوری برسه سمت php . نمی دونم واقعا چکارش کنم. و این موضوع باید حل بشه واسم والا دست بردارش نیستم!
String url ="http://192.168.0.0/android/note_server/news.php";
ArrayListparams=newArrayList();
params.add(newBasicNameValuePair("action","read"));
params.add(newBasicNameValuePair( url , news_id )); ====>> اینجا
/////////////////////////////////////////////////////////
php
function read(){ $connection = connectToDatabase(); $result = mysqli_query($connection,"SELECT * FROM news WHERE ('news_id' > '{$news_id}')"); $output = array();while($row = mysqli_fetch_array($result)){ $record = array(); $record['news_id']= $row['news_id']; $record['news_title']= $row['news_title']; $record['news_desc']= $row['news_desc']; $record['news_date']= $row['news_date']; $output[]= $record;} echo json_encode($output); mysqli_close($connection);}
عاقا من از این روش استفاده کردم از کد زیر مشکل میگیره
final SQLiteDatabase database = db.getReadableDatabase();
به کد زیر هم تغیر دادم بازم فایده نداشت
final SQLiteDatabase database = db.getWritableDatabase()
دیتابیسمم رو هم توی پوشه ی assets داخل database.zip قرار دادم که اسم فایلم هم database.sqllite هست
ممنون میشم کمک کنید .... :(
من هر کاری میکنم جواب نمیگیرم دوستان کسی میتونه کمک کنه اینم کدش:
private void populatedFromDatabase() {
sections.clear();
try {
DataBaseConnection db = new DataBaseConnection(ActivityMain.this, "Scamper", 5);
final SQLiteDatabase database = db.getReadableDatabase();
Cursor cursor = database.rawQuery("SELECT * FROM Scamper_Section", null);
while (cursor.moveToNext()) {
section = new StructSection();
section.setSectionId(cursor.getInt(cursor.getColumnIndex("section_id")));
section.setSctionEn(cursor.getString(cursor.getColumnIndex("section_en")));
section.setSectionFa(cursor.getString(cursor.getColumnIndex("section_fa")));
Log.i("LOG", "Section ID = " + section.getSectionId());
sections.add(section);
}
cursor.close();
database.close();
} catch (Exception e) {
Toast.makeText(ActivityMain.this, "Error Database", Toast.LENGTH_SHORT).show();
}
}
سلام من طبق توضیحات پیش رفتم اینم کدم
DataBaseConnection db = new DataBaseConnection(SMS_Test2Activity.this, "SmsPost.sqlite", 5);
final SQLiteDatabase database = db.getWritableDatabase();
database.execSQL("INSERT INTO deliver (deliver_sms,tell_sms,message_sms) VALUES (2,'s','s') ");
database.close();
سلام دوستان
من با این لایبراری کار کردم و مشکلی هم نداره ولی من توی اندوروید استدیو به دیتابیس چندتا رکورد اضافه کردم و log هم گرفتم و درست بود ولی بعدش فایل دیتا بیس رو برداشتم کپی کردم توی یه برنامه databse manager ولی رکورد هایی که از داخل اندروید استدیو اضافه کرده بودم وجود نداشت ؟!
دلیلش چیه ؟
اینم کد های من ، با این کد های من باید دوتا رکورد به دیتابیسم اصافه بشه که hasan , farid هستن و وقتی هم لاگ میگیرم اضافه میشن ، ولی وقتی دیتابیس رو با یک نفرم افزار دیتا بیس منیجر باز می کنم خبری از این رکوردهای جدید نیست ؟!
DataBaseConnection db = new DataBaseConnection(MainActivity.this, "database", 5); final SQLiteDatabase database = db.getWritableDatabase(); database.execSQL("INSERT INTO test (name) VALUES ('hasan')"); database.execSQL("INSERT INTO test (name) VALUES ('farid')"); Cursor cursor = database.rawQuery("SELECT * FROM test " , null); while(cursor.moveToNext()){ try{ Log.i("MINELOG" , cursor.getString(cursor.getColumnIndex("id"))); Log.i("MINELOG" , cursor.getString(cursor.getColumnIndex("name"))); }catch (Exception e){ } } cursor.close(); database.close();
اینطوری خوبه؟ اسم دیتابیس رو هم با آندرلاین عوض کردم ولی باز هم خطا گرفت!
من این کارهایی که گفتین انجام دادم اما با اررور زیر مواجه شدم
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
که از خط زیر گرفته میشد :
final SQLiteDatabase database = db.getReadableDatabase();
آیا به جز کارهایی گفتین کار دیگه ای باید انجام بشه؟ مثل تعریف کردن کلاس G یا .... چون به چیز دیگه ای اشاره نفرمودین
دوستان بنده همه کارهایی گفتید رو انجام دادم، اما این ارور رو میده. من داخل همین پوشه databases گذاشتم. هم زیپ کردم نشد، و هم بدون زیپ گذاشتم و بازم نشد. هم اسمشو با پسوند گذاشتم (یعنی databa.db) نشد و هم بدون پسوند که بازم نشد. اینم خطاش. اسم دیتابیس رو گذاشتم tasnim2:
01-31 21:09:33.877 9928-9928/rasadev.ir.tasnim E/SQLiteLog: (14) cannot open file at line 30052 of [b3bb660af9]
01-31 21:09:33.877 9928-9928/rasadev.ir.tasnim E/SQLiteLog: (14) os_unix.c:30052: (2) open(/data/data/rasadev.ir.tasnim/databases/tasnim2) -
01-31 21:09:33.879 9928-9928/rasadev.ir.tasnim E/SQLiteLog: (14) cannot open file at line 30052 of [b3bb660af9]
01-31 21:09:33.879 9928-9928/rasadev.ir.tasnim E/SQLiteLog: (14) os_unix.c:30052: (2) open(/data/data/rasadev.ir.tasnim/databases/tasnim2)
پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .