导入数据至数据库时如何实现进度条功能?
Got it, let's get that progress bar working for your file import. Since you already have the total line count, we can use that to calculate real-time progress and keep your users informed. Here's a step-by-step adjustment to your code:
1. Update Your Dialog Layout
First, add a horizontal progress bar and a progress text view to your import__dialog.xml to display progress:
<!-- Add these to your existing layout --> <ProgressBar android:id="@+id/progress_bar" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:max="100" android:visibility="gone"/> <TextView android:id="@+id/tv_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0%" android:layout_marginTop="8dp" android:visibility="gone"/>
2. Adjust Your Kotlin Code for Async Import & Progress Updates
We'll use Kotlin Coroutines to handle heavy file/database work off the main thread, while updating the UI safely on the main thread. Here's the revised code with progress tracking:
// Add these properties at the top of your Activity/Fragment private lateinit var progressBar: ProgressBar private lateinit var progressText: TextView private var totalLines = 0 private fun importDialog(type: Int, context: Context) { val builder = AlertDialog.Builder(this) val inflater = this.layoutInflater val view = inflater.inflate(R.layout.import__dialog, null) builder.setView(view) val dialog: AlertDialog = builder.create() dialog.window?.attributes?.windowAnimations = type dialog.setMessage(context.getString(R.string.open_master)) lbl = view.findViewById(R.id.edit_master) lbl.text = noti.toString() // Initialize progress components progressBar = view.findViewById(R.id.progress_bar) progressText = view.findViewById(R.id.tv_progress) btnimport = view.findViewById(R.id.img_import) btnimport.setOnClickListener { val fileintent = Intent(Intent.ACTION_GET_CONTENT) fileintent.type = "text/*" // Fixed MIME type for txt/csv try { startActivityForResult(fileintent, requestcode) dialog.show() } catch (e: ActivityNotFoundException) { lbl.text = "No activity can handle picking a file. Showing alternatives." } } scan = view.findViewById<Button>(R.id.btn_scan) scan.setOnClickListener { // First calculate total lines before starting import calculateTotalLines() // Then start import with progress importWithProgress(this) } dialog.show() } // Helper function to calculate total lines (extracted from your existing logic) private fun calculateTotalLines() { val cursor = contentResolver.openInputStream(android.net.Uri.parse(master_path)) ?: return try { val buffer = BufferedReader(InputStreamReader(cursor)) buffer.readLine() // Skip header line totalLines = 0 while (buffer.readLine() != null) { totalLines++ } } catch (e: IOException) { e.printStackTrace() val d = Dialog(this) d.setTitle("Failed to count lines: ${e.message}") d.show() } finally { cursor.close() } } // Updated import function with progress tracking private fun importWithProgress(context: Context) { // Show progress UI progressBar.visibility = View.VISIBLE progressText.visibility = View.VISIBLE // Launch coroutine for background work CoroutineScope(Dispatchers.IO).launch { val cursor = contentResolver.openInputStream(android.net.Uri.parse(master_path)) ?: return@launch val db = openOrCreateDatabase("database.db", Context.MODE_PRIVATE, null) val tableName = "Master" try { db.execSQL("delete from $tableName") val file = InputStreamReader(cursor) val buffer = BufferedReader(file) buffer.readLine() // Skip header val contentValues = ContentValues() db.beginTransaction() var currentLine = 0 while (true) { val line = buffer.readLine() ?: break currentLine++ // Your existing line parsing logic (kept as-is) val article_array = ArrayList<String>() var desc_array = ArrayList<String>() var price_array = ArrayList<String>() var isbn_array = ArrayList<String>() var total_array = ArrayList<String>() for(i in 0..12){ val article = line[i].toString().replace(" ","") article_array.add(article) } for(i in 13..62){ val desc = line[i].toString() desc_array.add(desc) } for(i in 63..70){ val price = line[i].toString().replace(" ","") price_array.add(price) } for(i in 71..line.length-1){ val isbn = line[i].toString().replace(" ","") isbn_array.add(isbn) } val article_list = article_array.toString().replace(", ","").replace("[","").replace("]","").replace("\n","") val desc_list = desc_array.toString().replace(", ","").replace("[","").replace("]","").replace("\n","") val price_list = price_array.toString().replace(", ","").replace("[","").replace("]","").replace("\n","") val isbn_list:String = isbn_array.toString().replace(", ","").replace("[","").replace("]","").replace("\n","") total_array.add(article_list) total_array.add(desc_list) total_array.add(price_list) total_array.add(isbn_list) val article=total_array[0].toString() val desc=total_array[1].toString() val price=total_array[2].toString() val isbn=total_array[3].toString() contentValues.put("article", article) contentValues.put("description", desc) contentValues.put("price", price) contentValues.put("isbn", isbn) db.insert(tableName, null, contentValues) // Calculate progress and update UI on main thread val progress = (currentLine.toFloat() / totalLines * 100).toInt() withContext(Dispatchers.Main) { progressBar.progress = progress progressText.text = "$progress%" } } db.setTransactionSuccessful() withContext(Dispatchers.Main) { // Hide progress and show success message progressBar.visibility = View.GONE progressText.visibility = View.GONE val d = Dialog(context) d.setTitle("Import completed successfully!") d.show() } } catch (e: IOException) { if (db.inTransaction()) db.endTransaction() withContext(Dispatchers.Main) { progressBar.visibility = View.GONE progressText.visibility = View.GONE val d = Dialog(context) d.setTitle("Import failed: ${e.message}") d.show() } } catch (ex: Exception) { if (db.inTransaction()) db.endTransaction() withContext(Dispatchers.Main) { progressBar.visibility = View.GONE progressText.visibility = View.GONE val d = Dialog(context) d.setTitle("Import failed: ${ex.message}") d.show() } } finally { db.close() cursor.close() } } } // Updated onActivityResult with better error handling @SuppressLint("MissingSuperCall") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (data == null) return if (requestCode == requestcode && resultCode == Activity.RESULT_OK) { val filepath = data.data ?: return master_path = filepath.toString() lbl.text = filepath.toString() } else { val d = Dialog(this) d.setTitle("Only CSV/TXT files allowed or operation cancelled") d.show() } }
Key Changes Made:
- Added progress UI components: A horizontal progress bar and text view to display real-time import percentage.
- Separated line counting: Extracted total line calculation into its own function to run before starting the import.
- Kotlin Coroutines: Moved file reading and database operations to a background thread (
Dispatchers.IO) to avoid blocking the main thread, and usedDispatchers.Mainto safely update the UI. - Real-time progress updates: Calculated progress percentage after each line is imported and refreshed the UI immediately.
- Resource cleanup: Added
close()calls for cursors and databases to prevent memory leaks.
A quick side note: Your current line parsing uses line[i] to split characters, which might not work well for standard CSV files (which use delimiters like commas). If you're working with proper CSV data, consider using a library like OpenCSV to handle parsing more reliably—but that's a separate improvement!
内容的提问来源于stack exchange,提问作者kinesis

