如何通过在新 类 中移动代码来避免 Android 中的意大利面条代码 (Kotlin)
How to avoid spaghetti code in Android by Moving code in new Classes (Kotlin)
从下面的主要 Class 开始,我试图将尽可能多的代码移动到 2 个新的 class 文件中,分别命名为 "PhotoCapture.kt" 和 "PhotoUpload.kt"。我找不到让它工作的方法。看起来我只能在 MainActivity 中工作。例如,我找不到在新 class 中移动方法 "onActivityResult" 的方法。为了理解整个事情的运作方式,我需要了解更多什么?
谢谢各位朋友!
package com.tabapab.takepictureandsave
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.support.v4.content.FileProvider
import android.util.Log
import android.util.Base64
import android.widget.ImageView
import com.android.volley.AuthFailureError
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import kotlinx.android.synthetic.main.activity_main.*
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
class MainActivity : AppCompatActivity() {
var namaFile = ""
// var fileUri = Uri.parse("")
val RC_CAMERA = 100
val REQUEST_TAKE_PHOTO = 1001
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
capture_btn.setOnClickListener {
dispatchTakePictureIntent()
}
}
private fun dispatchTakePictureIntent() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
// Ensure that there's a camera activity to handle the intent
takePictureIntent.resolveActivity(packageManager)?.also {
// Create the File where the photo should go
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
// Error occurred while creating the File
null
}
// Continue only if the File was successfully created
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this,
"com.tabapab.takepictureandsave",
it
)
takePictureIntent.putExtra(MediaStore.ACTION_IMAGE_CAPTURE, photoURI)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO)
}
}
}
}
lateinit var currentPhotoPath: String
@Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("ddMMyyyy_HHmmss").format(Date())
val storageDir: File = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val filNam = File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = absolutePath
}
Log.d("myDebug", storageDir.toString())
return filNam
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
// val imageBitmap = data.extras.get("data") as Bitmap
// image_view.setImageBitmap(imageBitmap)
// galleryAddPic()
val f = File(currentPhotoPath)
Log.d("myDebug", currentPhotoPath)
// image_view.setImageURI(Uri.fromFile(f)) // this sets uncompressed,
val imgStr = getBitmapToString(image_view, Uri.fromFile(f))
volleyImg(imgStr)
}
}
fun bitmapToString(bmp: Bitmap): String {
val outputStream = ByteArrayOutputStream()
bmp.compress(Bitmap.CompressFormat.JPEG, 60, outputStream)
val byteArray = outputStream.toByteArray()
return Base64.encodeToString(byteArray, Base64.DEFAULT)
}
fun getBitmapToString(imV: ImageView, Fileuri: Uri): String {
var bmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
bmp = BitmapFactory.decodeFile(Fileuri.path)
Log.d("myDebug", Fileuri.path)
var dim = 720
Log.d("myDebug", "height:" + bmp.height + " _width:"+ bmp.width)
if (bmp.height > bmp.width) {
bmp = Bitmap.createScaledBitmap(bmp,
(bmp.width*dim).div(bmp.height), dim, true)
} else {
bmp = Bitmap.createScaledBitmap(bmp,
dim, (bmp.height*dim).div(bmp.width), true)
}
imV.setImageBitmap(bmp)
return bitmapToString(bmp)
return ""
}
private fun volleyImg(imgStr: String) {
msg_display.text = "Starting Volley Kick"
val url:String = "http://192.168.10.6/tabapad1/modules/android/classes/main.php?op=filestr"
// val rq:RequestQueue=Volley.newRequestQueue(this)
val stringRequest = object : StringRequest(Request.Method.POST, url,
Response.Listener<String> { response ->
// Process the json
try {
val obj = JSONObject(response)
msg_display.text = obj.getString("message")
} catch (e: Exception) {
msg_display.text = "Exception: $e"
}
}, Response.ErrorListener { error ->
msg_display.text = error.message
}) {
@Throws(AuthFailureError::class)
override fun getParams(): Map<String, String> {
val params = HashMap<String, String>()
params.put("filename", "Maria2.jpg")
params.put("imstr", imgStr)
msg_display.text = "Sets the Volley parameters"
return params
}
}
// Add the volley post request to the request queue
VolleySingleton.getInstance(this).addToRequestQueue(stringRequest)
// rq.add(request)
}
// private fun galleryAddPic() {
// // run this to add the photo to system's Media Provider's database
// // It will be available in the Android Gallery application and other Apps
// Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
// val f = File(currentPhotoPath)
// mediaScanIntent.data = Uri.fromFile(f)
// sendBroadcast(mediaScanIntent)
// }
// }
}
您不能将 onActivityResult
移动为 it's tied with startActivityForResult
。您正在启动使用本机相机拍摄照片的意图,并且您的 activity 正在等待结果。结果 returns 到首先启动意图的 activity。
通常,您可以从 activity 中删除 methods/functions,当它们的使用可以应用于其他各种地方时。例如,您的 bitmapToString 函数可以很容易地放在 Utils class 中,因为它接收通用变量并且具有不依赖于 activity 的任何其他部分的主体。通过一些改动,也可以提取其他功能。例如,如果您将文件名变量作为参数添加到 createImageFile()
,您可以在其他活动中使用该变量,这些活动不一定希望使用与此处使用的文件名格式相同的文件名。
从下面的主要 Class 开始,我试图将尽可能多的代码移动到 2 个新的 class 文件中,分别命名为 "PhotoCapture.kt" 和 "PhotoUpload.kt"。我找不到让它工作的方法。看起来我只能在 MainActivity 中工作。例如,我找不到在新 class 中移动方法 "onActivityResult" 的方法。为了理解整个事情的运作方式,我需要了解更多什么?
谢谢各位朋友!
package com.tabapab.takepictureandsave
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.support.v4.content.FileProvider
import android.util.Log
import android.util.Base64
import android.widget.ImageView
import com.android.volley.AuthFailureError
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.StringRequest
import kotlinx.android.synthetic.main.activity_main.*
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
class MainActivity : AppCompatActivity() {
var namaFile = ""
// var fileUri = Uri.parse("")
val RC_CAMERA = 100
val REQUEST_TAKE_PHOTO = 1001
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
capture_btn.setOnClickListener {
dispatchTakePictureIntent()
}
}
private fun dispatchTakePictureIntent() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
// Ensure that there's a camera activity to handle the intent
takePictureIntent.resolveActivity(packageManager)?.also {
// Create the File where the photo should go
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
// Error occurred while creating the File
null
}
// Continue only if the File was successfully created
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this,
"com.tabapab.takepictureandsave",
it
)
takePictureIntent.putExtra(MediaStore.ACTION_IMAGE_CAPTURE, photoURI)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO)
}
}
}
}
lateinit var currentPhotoPath: String
@Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("ddMMyyyy_HHmmss").format(Date())
val storageDir: File = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val filNam = File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = absolutePath
}
Log.d("myDebug", storageDir.toString())
return filNam
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
// val imageBitmap = data.extras.get("data") as Bitmap
// image_view.setImageBitmap(imageBitmap)
// galleryAddPic()
val f = File(currentPhotoPath)
Log.d("myDebug", currentPhotoPath)
// image_view.setImageURI(Uri.fromFile(f)) // this sets uncompressed,
val imgStr = getBitmapToString(image_view, Uri.fromFile(f))
volleyImg(imgStr)
}
}
fun bitmapToString(bmp: Bitmap): String {
val outputStream = ByteArrayOutputStream()
bmp.compress(Bitmap.CompressFormat.JPEG, 60, outputStream)
val byteArray = outputStream.toByteArray()
return Base64.encodeToString(byteArray, Base64.DEFAULT)
}
fun getBitmapToString(imV: ImageView, Fileuri: Uri): String {
var bmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
bmp = BitmapFactory.decodeFile(Fileuri.path)
Log.d("myDebug", Fileuri.path)
var dim = 720
Log.d("myDebug", "height:" + bmp.height + " _width:"+ bmp.width)
if (bmp.height > bmp.width) {
bmp = Bitmap.createScaledBitmap(bmp,
(bmp.width*dim).div(bmp.height), dim, true)
} else {
bmp = Bitmap.createScaledBitmap(bmp,
dim, (bmp.height*dim).div(bmp.width), true)
}
imV.setImageBitmap(bmp)
return bitmapToString(bmp)
return ""
}
private fun volleyImg(imgStr: String) {
msg_display.text = "Starting Volley Kick"
val url:String = "http://192.168.10.6/tabapad1/modules/android/classes/main.php?op=filestr"
// val rq:RequestQueue=Volley.newRequestQueue(this)
val stringRequest = object : StringRequest(Request.Method.POST, url,
Response.Listener<String> { response ->
// Process the json
try {
val obj = JSONObject(response)
msg_display.text = obj.getString("message")
} catch (e: Exception) {
msg_display.text = "Exception: $e"
}
}, Response.ErrorListener { error ->
msg_display.text = error.message
}) {
@Throws(AuthFailureError::class)
override fun getParams(): Map<String, String> {
val params = HashMap<String, String>()
params.put("filename", "Maria2.jpg")
params.put("imstr", imgStr)
msg_display.text = "Sets the Volley parameters"
return params
}
}
// Add the volley post request to the request queue
VolleySingleton.getInstance(this).addToRequestQueue(stringRequest)
// rq.add(request)
}
// private fun galleryAddPic() {
// // run this to add the photo to system's Media Provider's database
// // It will be available in the Android Gallery application and other Apps
// Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
// val f = File(currentPhotoPath)
// mediaScanIntent.data = Uri.fromFile(f)
// sendBroadcast(mediaScanIntent)
// }
// }
}
您不能将 onActivityResult
移动为 it's tied with startActivityForResult
。您正在启动使用本机相机拍摄照片的意图,并且您的 activity 正在等待结果。结果 returns 到首先启动意图的 activity。
通常,您可以从 activity 中删除 methods/functions,当它们的使用可以应用于其他各种地方时。例如,您的 bitmapToString 函数可以很容易地放在 Utils class 中,因为它接收通用变量并且具有不依赖于 activity 的任何其他部分的主体。通过一些改动,也可以提取其他功能。例如,如果您将文件名变量作为参数添加到 createImageFile()
,您可以在其他活动中使用该变量,这些活动不一定希望使用与此处使用的文件名格式相同的文件名。