尝试压缩位图时出现空指针异常,无法拍照并上传到服务器
当我尝试在相机应用程序上拍照并将其上传到服务器端时,我收到 NullPointerException
,但有些设备工作正常,有些设备却出现问题。我不知道是什么问题,在某些设备上它只能工作一次然后崩溃。
这些问题是通过使用 firebase CrashAnalytics
来识别的。
片段类。
class PhotoUploadFragment : BaseFragment() {
private lateinit var viewModel: SelectOptionViewModel
//define caseId type
private var caseId: String? = ""
//define caseNo type
private var caseNo: String? = ""
//define image clarity
private var imageClarity: String? = ""
//define image width
private var imageWidth: String? = ""
//define image height
private var imageHeight: String? = ""
//location
lateinit var mFusedLocationClient: FusedLocationProviderClient
//random id
val PERMISSION_ID = 42
//Initialize lat and long to get loc address
var longitude = 0.0
var latitude = 0.0
//Capture bitmap image
var capturedBitmap = BitmapFactory.decodeStream(null)
//Set timestamp when giving name while saving image
var addrTimeStamp = ""
//Initialize location address
var locationAddress = ""
companion object {
private var args: Bundle? = null
//pass the argument that needs to be displayed
fun newInstance(case_id: String, case_number: String): Fragment {
// fun newInstance(case_id: String, case_number: String): Fragment {
args = Bundle()
//pass the value caseId
args!!.putString(CASE_ID, case_id)
//pass the value caseNo
args!!.putString(CASE_NO, case_number)
val fragment = PhotoUploadFragment()
fragment.arguments = args
return fragment
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
//setup view model
viewModel = ViewModelProviders.of(this)[SelectOptionViewModel::class.java]
// homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]
val view: View = inflater.inflate(
layout.fragment_tab_photo_upload,
container,
false
)
//get caseId
caseId = arguments?.getString(CASE_ID)
//get caseNo
caseNo = arguments?.getString(CASE_NO)
if (caseNo == null || caseNo == "") {
caseNo = "Nil"
}
//get imageClarity
imageClarity = PrefsHelper().getPref<String>(Constants.IMAGE_CLARITY)
//get imageWidth
imageWidth = PrefsHelper().getPref<String>(Constants.IMAGE_WIDTH)
//get imageHeight
imageHeight = PrefsHelper().getPref<String>(Constants.IMAGE_HEIGHT)
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this.activity!!)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//to clear all the data inside the fragment to avoid multiple API calls
viewModel.imageUploadresponseLiveData.value = null
//to enable upload btn only after image is taken
photo_upload_button_upload.isEnabled = false
getLastLocation()
setUpListeners()
setupObservers()
}
private fun setupObservers() {
viewModel.imageUploadresponseLiveData.observe(this, androidx.lifecycle.Observer {
if (it != null) {
//photo upload success
if (it.success == 1 && it.result.success == 1) {
Toast.makeText(context, "Image uploaded successfully.", Toast.LENGTH_SHORT)
.show()
//delete file after upload
val root = Environment.getExternalStorageDirectory().toString()
val myDir = File(root + "/CV App/nomedia/images/")
myDir.deleteRecursively()
photo_upload_imageview_photo.setImageBitmap(null)
//to enable upload btn only after image is taken
photo_upload_button_upload.isEnabled = false
}
//photo upload fail
else {
Toast.makeText(
context,
"Failed to update image. Please try again.",
Toast.LENGTH_SHORT
).show()
}
}
})
//observe API call status
viewModel.imageUploadAPICallStatus.observe(this, androidx.lifecycle.Observer {
processStatus(it)
})
}
private fun setUpListeners() {
photo_upload_button_open.setOnClickListener {
//Check camera permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(
this.activity!!,
Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this.activity!!,
arrayOf(Manifest.permission.CAMERA),
1
)
}
}
//Check storage permission
if (ActivityCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this.activity!!,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_PERM_WRITE_STORAGE
)
}
//if permission is allowed,open camera
else {
startCamera()
}
photo_upload_button_upload.setOnClickListener {
showDialogUpload()
}
}
}
private fun startCamera() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { cameraIntent ->
// Ensure that there's a camera activity to handle the intent
cameraIntent.resolveActivity(context!!.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.activity!!,
"com.xyzshopapp.fileprovider",
it
)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
cameraIntent.putExtra("return-data", true)
this.startActivityForResult(cameraIntent, ACTION_IMAGE_CAPTURE)
}
}
}
}
/**
* Create external image file, this file will be passed to Camera for saving the captured image
*/
@Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
//Set timestamp to addrTimeStamp
addrTimeStamp = timeStamp
val root = Environment.getExternalStorageDirectory().toString()
val myDir = File("$root/CV App/nomedia/images")
myDir.mkdirs()
return File.createTempFile(
"JPG_${addrTimeStamp}_", /* prefix */
".jpg", /* suffix */
myDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
fileTemp = this
//Save the complete file path to string
imageFileName = this.toURI().path.toString()
}
}
//show thumbnail
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK ) {
when (requestCode) {
ACTION_IMAGE_CAPTURE -> {
val imageQuality = imageClarity
val byteArrayOutputStream = ByteArrayOutputStream()
//Decode file to bitmap
capturedBitmap = BitmapFactory.decodeFile(imageFileName)
val a = capturedBitmap
val destinationHeight = imageHeight
val destinationWidth = imageWidth
var imageToScale = capturedBitmap
//test
var uncompressed = capturedBitmap
if (destinationHeight != null) {
if (destinationWidth != null) {
if (destinationHeight.toInt() > 0 && destinationWidth.toInt() > 0 && imageToScale != null) {
val width = imageToScale.width
val height = imageToScale.height
//Calculate the max changing amount and decide which dimension to use
val widthRatio = destinationWidth.toFloat() / width.toFloat()
val heightRatio = destinationHeight.toFloat() / height.toFloat()
//Use the ratio that will fit the image into the desired sizes
var finalWidth = floor((width * widthRatio).toDouble()).toInt()
var finalHeight = floor((height * widthRatio).toDouble()).toInt()
if (finalWidth > destinationWidth.toInt() || finalHeight > destinationHeight.toInt()) {
finalWidth = floor((width * heightRatio).toDouble()).toInt()
finalHeight = floor((height * heightRatio).toDouble()).toInt()
}
//Scale given bitmap to fit into the desired area
imageToScale = Bitmap.createScaledBitmap(imageToScale, finalWidth, finalHeight, false)
//Created a bitmap with desired sizes
val scaledImage =
Bitmap.createBitmap(destinationWidth.toInt(), destinationHeight.toInt(), Bitmap.Config.ARGB_8888)
uncompressed = imageToScale
}
}
}
//compress by quality
if (imageQuality != null) {
uncompressed.compress(
Bitmap.CompressFormat.JPEG,
imageQuality.toInt(),
byteArrayOutputStream
)
/*try{
}catch (e:Exception)
{
println("this is exception $e")
}*/
}
val byteArray = byteArrayOutputStream.toByteArray()
//Encode bitmap to file
val compressedImageFile = FileOutputStream(imageFileName)
compressedImageFile.write(byteArray)
compressedImageFile.flush()
compressedImageFile.close()
//Set image in thumbnail
photo_upload_imageview_photo.setImageBitmap(a)
//to enable upload btn only after image is taken
photo_upload_button_upload.isEnabled = true
}
else -> {
Toast.makeText(context, "Unrecognized request code.", Toast.LENGTH_SHORT).show()
}
}
}
}
//popup box for uploading photo
fun showDialogUpload() {
val dialog = Dialog(context!!)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(true)
dialog.setContentView(layout.photo_upload)
val photo_upload_submit =
dialog.findViewById(com.xyz.shopapp.R.id.image_button_submit) as Button
val spinner =
dialog.findViewById(com.xyz.shopapp.R.id.photo_upload_spinner_image_name) as Spinner
//get array of image names
val imageName = (PrefsHelper().getPref<String>("ImageName"))
//convert array to string
val gson = Gson()
val imageNameList = gson.fromJson(imageName, Array<String>::class.java).asList()
//dropdown menu
if (spinner != null) {
val adapter =
ArrayAdapter<String>(context!!, android.R.layout.simple_spinner_item, imageNameList)
// Set layout to use when the list of choices appear
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Set Adapter to Spinner
spinner.adapter = adapter
//get image name
var itemSpinnerSelected = ""
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View,
position: Int,
id: Long
) {
// Get the selected item
itemSpinnerSelected = "${parent.getItemAtPosition(position)}"
}
override fun onNothingSelected(parent: AdapterView<*>) {
// Another interface callback
}
}
photo_upload_submit.setOnClickListener {
if (getAddress()) {
viewModel.submitImageData(
caseId, caseNo,
imageFileName, latitude, longitude, itemSpinnerSelected, locationAddress
)
// viewModel.submitImageData(
// caseId, caseNo,
// imageFileName, latitude, longitude, itemSpinnerSelected, locationAddress
// )
// viewModel.submitImageData(caseId,caseNo,rootDir + "/CV App/nomedia/images/avc6937492103605367617.jpg",latitude,longitude,itemSpinnerSelected, locationAddress)
// dismissDialog()
// val progressBar = findViewById(com.xyz.shopapp.R.id.progresbar) as ProgressBar
// progressBar.visibility = View.INVISIBLE
}
dialog.dismiss()
}
}
dialog.show()
}
//get location
//check whether location is enabled for application
@SuppressLint("MissingPermission")
private fun getLastLocation() {
// var latitude = 0.0
if (checkPermissions()) {
//if (isLocationEnabled()) {
mFusedLocationClient.lastLocation.addOnCompleteListener(this.activity!!) { task ->
val location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
latitude = location.latitude
longitude = location.longitude
getAddress()
}
}
/*mFusedLocationClient.lastLocation.addOnCompleteListener(this.activity!!) { task ->
var location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
latitude = location.latitude
longitude = location.longitude
getAddress()
}
}*/
// } else {
// Toast.makeText(context, "Turn on your location.", Toast.LENGTH_LONG).show()
// val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
// startActivity(intent)
// }
} else {
//requestPermissions()
//Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
//to get location in first try itself
val coraseLocationPermission = checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_COARSE_LOCATION
)
val accessFineLocation = checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
)
if (coraseLocationPermission != PackageManager.PERMISSION_GRANTED && accessFineLocation != PackageManager.PERMISSION_GRANTED) {
requestPermissions(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
),
PERMISSION_ID
)
}
}
}
@SuppressLint("MissingPermission")
private fun requestNewLocationData() {
val mLocationRequest = LocationRequest()
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest.interval = 0
mLocationRequest.fastestInterval = 0
mLocationRequest.numUpdates = 1
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this.activity!!)
mFusedLocationClient.requestLocationUpdates(
mLocationRequest, mLocationCallback,
Looper.myLooper()
)
}
private val mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val mLastLocation: Location = locationResult.lastLocation
latitude = mLastLocation.latitude
longitude = mLastLocation.longitude
}
}
// private fun isLocationEnabled(): Boolean {
// var locationManager: LocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
// return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
// LocationManager.NETWORK_PROVIDER
// )
// }
private fun checkPermissions(): Boolean {
if (ActivityCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
return true
}
return false
}
//check location permission
private fun requestPermissions() {
ActivityCompat.requestPermissions(
this.activity!!
,
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
),
PERMISSION_ID
)
}
//request location permission
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
if (requestCode == PERMISSION_ID) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
mFusedLocationClient.lastLocation.addOnCompleteListener(this.activity!!) { task ->
val location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
latitude = location.latitude
longitude = location.longitude
// Call API
}
}
requestNewLocationData()
} else {
getLastLocation()
}
}
}
//get address from location
var addresses: List<Address> = emptyList()
private fun getAddress(): Boolean {
// showDialog()
var flag = false
locationAddress = ""
try {
val geocoder = Geocoder(context, Locale.getDefault())
addresses = geocoder.getFromLocation(latitude,
longitude, 1
) // Here 1 represent max location result to returned, by documents it recommended 1 to 5
//null checking
val address_size = addresses.size
if (address_size > 0) {
locationAddress = addresses.get(0)
.getAddressLine(0) // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
flag = true
}
} catch (ioException: IOException) {
val errorMessage = getString(string.service_not_available)
Log.e(ContentValues.TAG, errorMessage + " saf not avail", ioException)
}
dismissDialog()
return flag
}
private fun processStatus(resource: ResourceStatus) {
when (resource.status) {
StatusType.SUCCESS -> {
dismissDialog()
// Toast.makeText(context, "Photo Uploaded Successfully.", Toast.LENGTH_SHORT).show()
}
StatusType.EMPTY_RESPONSE -> {
dismissDialog()
}
StatusType.PROGRESSING -> {
showDialog()
}
StatusType.SWIPE_RELOADING -> {
}
StatusType.ERROR -> {
// var fail_status = "Failed to update image. Please try again."
// Toast.makeText(context, fail_status, Toast.LENGTH_SHORT).show()
dismissDialog()
}
StatusType.LOADING_MORE -> {
// CommonUtils().showSnackbar(binding.root, "Loading more..")
}
StatusType.NO_NETWORK -> {
val internet_failure = "Please check your internet connection."
Toast.makeText(context, internet_failure, Toast.LENGTH_SHORT).show()
}
StatusType.SESSION_EXPIRED -> {
// var session_expired = "Invalid credentials. Login failed"
// Toast.makeText(this, session_expired, Toast.LENGTH_SHORT).show()
}
}
}
///
}
导致错误的行是
uncompressed.compress(Bitmap.CompressFormat.JPEG,imageQuality.toInt(),byteArrayOutputStream)
firebase crashAnalytics 控制台中显示的错误日志:
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
at com.axionz.shopapp.ui.tabfragment.PhotoUploadFragment.onActivityResult(PhotoUploadFragment.kt:353)
at androidx.fragment.app.FragmentActivity.onActivityResult(FragmentActivity.java:170)
at android.app.Activity.dispatchActivityResult(Activity.java:8464)
at android.app.ActivityThread.deliverResults(ActivityThread.java:5355)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4755)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4810)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:187)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:102)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:254)
at android.app.ActivityThread.main(ActivityThread.java:8243)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)
I am getting a NullPointerException
when trying to take a photo on camera application and upload it on to the server side, but some devices it works fine, and some getting issues. i don't know what is the issues, in some devices it works once and getting crashed.
the issues are identified by using firebase CrashAnalytics
.
the fragment class.
class PhotoUploadFragment : BaseFragment() {
private lateinit var viewModel: SelectOptionViewModel
//define caseId type
private var caseId: String? = ""
//define caseNo type
private var caseNo: String? = ""
//define image clarity
private var imageClarity: String? = ""
//define image width
private var imageWidth: String? = ""
//define image height
private var imageHeight: String? = ""
//location
lateinit var mFusedLocationClient: FusedLocationProviderClient
//random id
val PERMISSION_ID = 42
//Initialize lat and long to get loc address
var longitude = 0.0
var latitude = 0.0
//Capture bitmap image
var capturedBitmap = BitmapFactory.decodeStream(null)
//Set timestamp when giving name while saving image
var addrTimeStamp = ""
//Initialize location address
var locationAddress = ""
companion object {
private var args: Bundle? = null
//pass the argument that needs to be displayed
fun newInstance(case_id: String, case_number: String): Fragment {
// fun newInstance(case_id: String, case_number: String): Fragment {
args = Bundle()
//pass the value caseId
args!!.putString(CASE_ID, case_id)
//pass the value caseNo
args!!.putString(CASE_NO, case_number)
val fragment = PhotoUploadFragment()
fragment.arguments = args
return fragment
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
//setup view model
viewModel = ViewModelProviders.of(this)[SelectOptionViewModel::class.java]
// homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]
val view: View = inflater.inflate(
layout.fragment_tab_photo_upload,
container,
false
)
//get caseId
caseId = arguments?.getString(CASE_ID)
//get caseNo
caseNo = arguments?.getString(CASE_NO)
if (caseNo == null || caseNo == "") {
caseNo = "Nil"
}
//get imageClarity
imageClarity = PrefsHelper().getPref<String>(Constants.IMAGE_CLARITY)
//get imageWidth
imageWidth = PrefsHelper().getPref<String>(Constants.IMAGE_WIDTH)
//get imageHeight
imageHeight = PrefsHelper().getPref<String>(Constants.IMAGE_HEIGHT)
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this.activity!!)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//to clear all the data inside the fragment to avoid multiple API calls
viewModel.imageUploadresponseLiveData.value = null
//to enable upload btn only after image is taken
photo_upload_button_upload.isEnabled = false
getLastLocation()
setUpListeners()
setupObservers()
}
private fun setupObservers() {
viewModel.imageUploadresponseLiveData.observe(this, androidx.lifecycle.Observer {
if (it != null) {
//photo upload success
if (it.success == 1 && it.result.success == 1) {
Toast.makeText(context, "Image uploaded successfully.", Toast.LENGTH_SHORT)
.show()
//delete file after upload
val root = Environment.getExternalStorageDirectory().toString()
val myDir = File(root + "/CV App/nomedia/images/")
myDir.deleteRecursively()
photo_upload_imageview_photo.setImageBitmap(null)
//to enable upload btn only after image is taken
photo_upload_button_upload.isEnabled = false
}
//photo upload fail
else {
Toast.makeText(
context,
"Failed to update image. Please try again.",
Toast.LENGTH_SHORT
).show()
}
}
})
//observe API call status
viewModel.imageUploadAPICallStatus.observe(this, androidx.lifecycle.Observer {
processStatus(it)
})
}
private fun setUpListeners() {
photo_upload_button_open.setOnClickListener {
//Check camera permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(
this.activity!!,
Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this.activity!!,
arrayOf(Manifest.permission.CAMERA),
1
)
}
}
//Check storage permission
if (ActivityCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this.activity!!,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_PERM_WRITE_STORAGE
)
}
//if permission is allowed,open camera
else {
startCamera()
}
photo_upload_button_upload.setOnClickListener {
showDialogUpload()
}
}
}
private fun startCamera() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { cameraIntent ->
// Ensure that there's a camera activity to handle the intent
cameraIntent.resolveActivity(context!!.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.activity!!,
"com.xyzshopapp.fileprovider",
it
)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
cameraIntent.putExtra("return-data", true)
this.startActivityForResult(cameraIntent, ACTION_IMAGE_CAPTURE)
}
}
}
}
/**
* Create external image file, this file will be passed to Camera for saving the captured image
*/
@Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
//Set timestamp to addrTimeStamp
addrTimeStamp = timeStamp
val root = Environment.getExternalStorageDirectory().toString()
val myDir = File("$root/CV App/nomedia/images")
myDir.mkdirs()
return File.createTempFile(
"JPG_${addrTimeStamp}_", /* prefix */
".jpg", /* suffix */
myDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
fileTemp = this
//Save the complete file path to string
imageFileName = this.toURI().path.toString()
}
}
//show thumbnail
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK ) {
when (requestCode) {
ACTION_IMAGE_CAPTURE -> {
val imageQuality = imageClarity
val byteArrayOutputStream = ByteArrayOutputStream()
//Decode file to bitmap
capturedBitmap = BitmapFactory.decodeFile(imageFileName)
val a = capturedBitmap
val destinationHeight = imageHeight
val destinationWidth = imageWidth
var imageToScale = capturedBitmap
//test
var uncompressed = capturedBitmap
if (destinationHeight != null) {
if (destinationWidth != null) {
if (destinationHeight.toInt() > 0 && destinationWidth.toInt() > 0 && imageToScale != null) {
val width = imageToScale.width
val height = imageToScale.height
//Calculate the max changing amount and decide which dimension to use
val widthRatio = destinationWidth.toFloat() / width.toFloat()
val heightRatio = destinationHeight.toFloat() / height.toFloat()
//Use the ratio that will fit the image into the desired sizes
var finalWidth = floor((width * widthRatio).toDouble()).toInt()
var finalHeight = floor((height * widthRatio).toDouble()).toInt()
if (finalWidth > destinationWidth.toInt() || finalHeight > destinationHeight.toInt()) {
finalWidth = floor((width * heightRatio).toDouble()).toInt()
finalHeight = floor((height * heightRatio).toDouble()).toInt()
}
//Scale given bitmap to fit into the desired area
imageToScale = Bitmap.createScaledBitmap(imageToScale, finalWidth, finalHeight, false)
//Created a bitmap with desired sizes
val scaledImage =
Bitmap.createBitmap(destinationWidth.toInt(), destinationHeight.toInt(), Bitmap.Config.ARGB_8888)
uncompressed = imageToScale
}
}
}
//compress by quality
if (imageQuality != null) {
uncompressed.compress(
Bitmap.CompressFormat.JPEG,
imageQuality.toInt(),
byteArrayOutputStream
)
/*try{
}catch (e:Exception)
{
println("this is exception $e")
}*/
}
val byteArray = byteArrayOutputStream.toByteArray()
//Encode bitmap to file
val compressedImageFile = FileOutputStream(imageFileName)
compressedImageFile.write(byteArray)
compressedImageFile.flush()
compressedImageFile.close()
//Set image in thumbnail
photo_upload_imageview_photo.setImageBitmap(a)
//to enable upload btn only after image is taken
photo_upload_button_upload.isEnabled = true
}
else -> {
Toast.makeText(context, "Unrecognized request code.", Toast.LENGTH_SHORT).show()
}
}
}
}
//popup box for uploading photo
fun showDialogUpload() {
val dialog = Dialog(context!!)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(true)
dialog.setContentView(layout.photo_upload)
val photo_upload_submit =
dialog.findViewById(com.xyz.shopapp.R.id.image_button_submit) as Button
val spinner =
dialog.findViewById(com.xyz.shopapp.R.id.photo_upload_spinner_image_name) as Spinner
//get array of image names
val imageName = (PrefsHelper().getPref<String>("ImageName"))
//convert array to string
val gson = Gson()
val imageNameList = gson.fromJson(imageName, Array<String>::class.java).asList()
//dropdown menu
if (spinner != null) {
val adapter =
ArrayAdapter<String>(context!!, android.R.layout.simple_spinner_item, imageNameList)
// Set layout to use when the list of choices appear
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Set Adapter to Spinner
spinner.adapter = adapter
//get image name
var itemSpinnerSelected = ""
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View,
position: Int,
id: Long
) {
// Get the selected item
itemSpinnerSelected = "${parent.getItemAtPosition(position)}"
}
override fun onNothingSelected(parent: AdapterView<*>) {
// Another interface callback
}
}
photo_upload_submit.setOnClickListener {
if (getAddress()) {
viewModel.submitImageData(
caseId, caseNo,
imageFileName, latitude, longitude, itemSpinnerSelected, locationAddress
)
// viewModel.submitImageData(
// caseId, caseNo,
// imageFileName, latitude, longitude, itemSpinnerSelected, locationAddress
// )
// viewModel.submitImageData(caseId,caseNo,rootDir + "/CV App/nomedia/images/avc6937492103605367617.jpg",latitude,longitude,itemSpinnerSelected, locationAddress)
// dismissDialog()
// val progressBar = findViewById(com.xyz.shopapp.R.id.progresbar) as ProgressBar
// progressBar.visibility = View.INVISIBLE
}
dialog.dismiss()
}
}
dialog.show()
}
//get location
//check whether location is enabled for application
@SuppressLint("MissingPermission")
private fun getLastLocation() {
// var latitude = 0.0
if (checkPermissions()) {
//if (isLocationEnabled()) {
mFusedLocationClient.lastLocation.addOnCompleteListener(this.activity!!) { task ->
val location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
latitude = location.latitude
longitude = location.longitude
getAddress()
}
}
/*mFusedLocationClient.lastLocation.addOnCompleteListener(this.activity!!) { task ->
var location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
latitude = location.latitude
longitude = location.longitude
getAddress()
}
}*/
// } else {
// Toast.makeText(context, "Turn on your location.", Toast.LENGTH_LONG).show()
// val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
// startActivity(intent)
// }
} else {
//requestPermissions()
//Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
//to get location in first try itself
val coraseLocationPermission = checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_COARSE_LOCATION
)
val accessFineLocation = checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
)
if (coraseLocationPermission != PackageManager.PERMISSION_GRANTED && accessFineLocation != PackageManager.PERMISSION_GRANTED) {
requestPermissions(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
),
PERMISSION_ID
)
}
}
}
@SuppressLint("MissingPermission")
private fun requestNewLocationData() {
val mLocationRequest = LocationRequest()
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
mLocationRequest.interval = 0
mLocationRequest.fastestInterval = 0
mLocationRequest.numUpdates = 1
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this.activity!!)
mFusedLocationClient.requestLocationUpdates(
mLocationRequest, mLocationCallback,
Looper.myLooper()
)
}
private val mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val mLastLocation: Location = locationResult.lastLocation
latitude = mLastLocation.latitude
longitude = mLastLocation.longitude
}
}
// private fun isLocationEnabled(): Boolean {
// var locationManager: LocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
// return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
// LocationManager.NETWORK_PROVIDER
// )
// }
private fun checkPermissions(): Boolean {
if (ActivityCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(
this.activity!!,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
return true
}
return false
}
//check location permission
private fun requestPermissions() {
ActivityCompat.requestPermissions(
this.activity!!
,
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
),
PERMISSION_ID
)
}
//request location permission
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
if (requestCode == PERMISSION_ID) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
mFusedLocationClient.lastLocation.addOnCompleteListener(this.activity!!) { task ->
val location: Location? = task.result
if (location == null) {
requestNewLocationData()
} else {
latitude = location.latitude
longitude = location.longitude
// Call API
}
}
requestNewLocationData()
} else {
getLastLocation()
}
}
}
//get address from location
var addresses: List<Address> = emptyList()
private fun getAddress(): Boolean {
// showDialog()
var flag = false
locationAddress = ""
try {
val geocoder = Geocoder(context, Locale.getDefault())
addresses = geocoder.getFromLocation(latitude,
longitude, 1
) // Here 1 represent max location result to returned, by documents it recommended 1 to 5
//null checking
val address_size = addresses.size
if (address_size > 0) {
locationAddress = addresses.get(0)
.getAddressLine(0) // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
flag = true
}
} catch (ioException: IOException) {
val errorMessage = getString(string.service_not_available)
Log.e(ContentValues.TAG, errorMessage + " saf not avail", ioException)
}
dismissDialog()
return flag
}
private fun processStatus(resource: ResourceStatus) {
when (resource.status) {
StatusType.SUCCESS -> {
dismissDialog()
// Toast.makeText(context, "Photo Uploaded Successfully.", Toast.LENGTH_SHORT).show()
}
StatusType.EMPTY_RESPONSE -> {
dismissDialog()
}
StatusType.PROGRESSING -> {
showDialog()
}
StatusType.SWIPE_RELOADING -> {
}
StatusType.ERROR -> {
// var fail_status = "Failed to update image. Please try again."
// Toast.makeText(context, fail_status, Toast.LENGTH_SHORT).show()
dismissDialog()
}
StatusType.LOADING_MORE -> {
// CommonUtils().showSnackbar(binding.root, "Loading more..")
}
StatusType.NO_NETWORK -> {
val internet_failure = "Please check your internet connection."
Toast.makeText(context, internet_failure, Toast.LENGTH_SHORT).show()
}
StatusType.SESSION_EXPIRED -> {
// var session_expired = "Invalid credentials. Login failed"
// Toast.makeText(this, session_expired, Toast.LENGTH_SHORT).show()
}
}
}
///
}
The line which causes the error is
uncompressed.compress(Bitmap.CompressFormat.JPEG,imageQuality.toInt(),byteArrayOutputStream)
error log shown in firebase crashAnalytics console:
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
at com.axionz.shopapp.ui.tabfragment.PhotoUploadFragment.onActivityResult(PhotoUploadFragment.kt:353)
at androidx.fragment.app.FragmentActivity.onActivityResult(FragmentActivity.java:170)
at android.app.Activity.dispatchActivityResult(Activity.java:8464)
at android.app.ActivityThread.deliverResults(ActivityThread.java:5355)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4755)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4810)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:187)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:102)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:254)
at android.app.ActivityThread.main(ActivityThread.java:8243)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请在您现有的代码上尝试以下方法可能会对您有所帮助,可能会从 api 28 更新访问内部存储上的数据目录和 Android 11 中的存储更新,您会遇到问题,因为您说它在某些设备中工作,但在某些设备上不起作用设备,请转到 https://developer.android.com/about/versions/11/privacy/storage
有关存储更新的详细信息。
您可以在 Android 10 的清单中使用 android:requestLegacyExternalStorage="true" 的一种方法,但这不是 Android 10 以上版本的解决方案。
Android 清单中的权限和提供程序
provider_paths.xml
您的活动类代码
Please try the below way on your existing code may help you, May be update from api 28 Access to data directories on internal storage and Storage updates in Android 11 your are getting problem because you are saying it is working in some device and not in some device,Please go to https://developer.android.com/about/versions/11/privacy/storage
for detail about storage update.
one way you can use android:requestLegacyExternalStorage="true" in manifest for android 10, but it is not solution for above android 10.
Permission and provider in Android Manifest
provider_paths.xml
Your Activity Class Code
对象
capturedBitmap
为 null下面的代码可能对您有帮助
The object
capturedBitmap
is nullThe below code may help you