0

From the Main Class below, I am trying to move as much code as possible into 2 new class files named "PhotoCapture.kt" and "PhotoUpload.kt" respectively. I don't find a way to make it work. It looks like I am confined to work only within the MainActivity. For example I can't find a way to move the method "onActivityResult" in a new class. What do I need to know more in order to understand how the whole thing works?

Thank you friends!

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)
//        }
//    }


}
Thanasis
  • 329
  • 4
  • 8

1 Answers1

1

You cannot move onActivityResult as it's tied with startActivityForResult. You are launching an intent to take a photo using the native camera and your activity is expecting a result. The result returns to the activity that launched the intent in the first place.

Generally, you can remove methods/functions from an activity, when their use can be applied in various other places. Your bitmapToString function, for example, can be easily put in a Utils class as it receives generic variables and has a body that is not dependant on any other part of your activity. With some alterations, other functions could be extracted as well. For example if you add a variable for the file name as a parameter to createImageFile(), you can use that in other activities that don't necessarily want to have the same format of filename as the one used here.

Nikos Hidalgo
  • 3,666
  • 9
  • 25
  • 39
  • Thank you for this. I guess my code will run in a fragment class. I mean classes extended from : AppCompatActivity() have the same methods as in classes extended from : Fragment() ? What is the difference? – Thanasis Dec 17 '19 at 14:45
  • 1
    @Thanasis An activity is one of the main Android components. A fragment is a representation of a specific behaviour. You can have activities without fragments, but not fragments without at least one activity. Even though they have a lot of common functions, there are many that can't be included in both. There are many discussions about when to use an activity vs a fragment ( https://stackoverflow.com/questions/20306091/dilemma-when-to-use-fragments-vs-activities ). Check the developer's guide though for more info: https://developer.android.com/guide/components/activities/intro-activities – Nikos Hidalgo Dec 17 '19 at 14:54
  • Despite reading and searching some issues are not cleaar to me. Thank you for your help. One last thing. Is it possible to redirect my above code to a new activity? But leave the setContentView(R.layout.activity_main) to the mainActivity and call another activity (class) from the mainActivity class. The new class / activity will not call a view.xml ( setContentView ) but will only accommodate my code. Is it possible. Ok I will try to read more, but I cant get the answers anywhere. Thank you. – Thanasis Dec 17 '19 at 15:05
  • 1
    @Thanasis activities tend to have their own UI as they're mainly responsible for what the user sees and interacts with. If you want to create some functionality or a feature within the same user interface (what you call view.xml) you can delegate your functions and organise them in classes and have your activity call them to get the results and then present them to the user. When a function is public in Kotlin you can call it from anywhere. In that sense, it's possible to have your main activity and call functions from other classes without setting a new content view. – Nikos Hidalgo Dec 17 '19 at 15:13
  • Nikos thanks. I will appreciate if you give me a vote to my question. Thanks again. – Thanasis Dec 19 '19 at 10:26
  • 1
    @Thanasis I upvoted your question but there's already a downvote from someone else, hence you're now on 0. – Nikos Hidalgo Dec 19 '19 at 10:51