Basic ImageView breaks app in Android Studio - android

As soon as I add an ImageView to the layout, the app cannot run. When the code for the ImageView in activity_main.xml is removed, the app works. I've seen the app break in both Pixel 3a API 33, and my physical Pixel 5 device
Here are the main files:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:srcCompat="#drawable/ic_launcher_foreground" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_main.kt:
package com.example.test_custom_toast
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Toast
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.button).setOnClickListener {
val inflater = layoutInflater
val layout: View = inflater.inflate(
R.layout.custom_toast,
findViewById<View>(R.id.clToast) as ViewGroup
)
val toast = Toast(this)
toast.apply {
duration = Toast.LENGTH_LONG
setContentView(layout)
show()
}
}
}
}
I have another layout, but since I can't even get to it, I posting code seems irrelevant

Related

Duplicate and overlapping text in TextView when using LiveData or StateFlow

To be as clear as possible, I'm going to show the problem with a gif.
As you can see, the text is overlapping in my emulator and I don't know how to solve it, I don't know what I'm doing wrong.
It should be displayed correctly without overlapping. What I'm doing is subscribing to changes in both LiveData and StateFlow. When I press the button, I make it change the value, but instead of changing, it seems to return both values at once (Default and Hello). Could it be that the view is not refreshing? Or could it be a problem with my emulator?
Anyway, I'll leave all the code here in case you can figure it out.
FlowsFragment.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.View
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.rr.stateflow_livedata_flow_sharedflow.databinding.FragmentFlowsBinding
import kotlinx.coroutines.flow.collectLatest
class FlowsFragment : Fragment(R.layout.fragment_flows) {
private lateinit var binding: FragmentFlowsBinding
private val viewModel: FlowsViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentFlowsBinding.bind(view)
binding.btnLiveData.setOnClickListener {
viewModel.triggerLiveData()
}
binding.btnStateFlow.setOnClickListener {
viewModel.triggerStateFlow()
}
subscribeToObservables()
}
private fun subscribeToObservables() {
viewModel.liveData.observe(viewLifecycleOwner) {
binding.tvLiveData.text = it
}
lifecycleScope.launchWhenStarted {
viewModel.stateFlow.collectLatest {
binding.tvStateFlow.text = it
}
}
}
}
FlowsViewModel.kt
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.*
class FlowsViewModel : ViewModel() {
private val _liveData = MutableLiveData("Default LiveData")
val liveData: LiveData<String> = _liveData
private val _stateFlow = MutableStateFlow("Default StateFlow")
val stateFlow: StateFlow<String> = _stateFlow.asStateFlow()
fun triggerLiveData() {
_liveData.value = "Hello LiveData!"
}
fun triggerStateFlow() {
_stateFlow.value = "Hello StateFlow!"
}
}
fragment_flows.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FlowsFragment">
<TextView
android:id="#+id/tvLiveData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="sans-serif-condensed"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btnLiveData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="LIVEDATA"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvLiveData" />
<TextView
android:id="#+id/tvStateFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="sans-serif-condensed"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnLiveData" />
<Button
android:id="#+id/btnStateFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="STATEFLOW"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvStateFlow" />
<TextView
android:id="#+id/tvFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="sans-serif-condensed"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.504"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnStateFlow" />
<Button
android:id="#+id/btnFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="FLOW"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvFlow" />
<TextView
android:id="#+id/tvSharedFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="sans-serif-condensed"
android:text="Hello World!"
android:textColor="#color/black"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnFlow" />
<Button
android:id="#+id/btnSharedFlow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="SHAREDFLOW"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvSharedFlow" />
</androidx.constraintlayout.widget.ConstraintLayout>
I hope that the text doesn't overlap and returns the latest value of LiveData and StateFlow.
Edit with more info: The application displays the view directly from the fragment, MainActivity only has a fragment container that I show below.
MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.add
import androidx.fragment.app.commit
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportFragmentManager.commit {
setReorderingAllowed(true)
add<FlowsFragment>(R.id.mainActivityFragmentContainer)
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/mainActivityFragmentContainer"
android:name="com.rr.stateflow_livedata_flow_sharedflow.FlowsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="#layout/fragment_flows" />
</androidx.constraintlayout.widget.ConstraintLayout>
EDIT This is not the solution, it's a bad way to solve the problem.
I just have to add this line of code in fragment_flows.xml.
android:background="#color/white"
Just by setting the background of the fragment to white, the text is no longer duplicated and overlapping.
Does anyone know why this happens? Why does what is drawn on the screen stick to the background if there is no background in the fragment layout?

Image view in android studio is showing in xml layout but not showing in app

Image view in android studio is showing in xml layout but it is not showing in the app after run I tried every solution available but not got the solution to my problem.
I'm making a simple meme share app in which there will be two buttons share and next , after clicking next button another meme appears I used an random meme api I have not completed the app ( not added function for next button and share button ) just to check whether meme image is showing or not I ran my code successfully it was installed on my phone, buttons are showing but image is not showing only white background
MainActivity.kt
package com.example.memeshare
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import com.bumptech.glide.Glide
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadMeme()
}
private fun loadMeme(){
var memeImageview = findViewById<ImageView>(R.id.imageView)
// ...
// Instantiate the RequestQueue.
val queue = Volley.newRequestQueue(this)
val url = "https://i.redd.it/bi9tnlxmqlr71.jpg"
val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET, url,null,
{ response ->
val url = response.getString("url")
Glide.with(this).load(url).into(memeImageview)
},
{ },
)
// Add the request to the RequestQueue.
queue.add(jsonObjectRequest)
}
fun shareMeme(view: View) {
}
fun nextMeme(view: View) {
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:srcCompat="#tools:sample/avatars" />
<Button
android:id="#+id/shareButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/share"
android:padding="32dp"
app:layout_constraintRight_toRightOf="#id/guideline2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:onClick="shareMeme"/>
<Button
android:id="#+id/nextButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:width="0dp"
android:padding="32dp"
android:text="#string/next"
app:layout_constraintLeft_toLeftOf="#id/guideline2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:onClick="nextMeme"/>
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintGuide_percent="0.5"/>
</androidx.constraintlayout.widget.ConstraintLayout>
[It look like this in layout]
(https://i.stack.imgur.com/CarzW.jpg)
You need to set the
android:layout_width="wrap_content"
android:layout_height="wrap_content
And you need to add a source or background to the imageview.
android:background="#drawable/image"
android:src="#drawable/image"
Your mistake is to use tools:srcCompat.
So when you use tools, nothing will show in your app
You have to use
android:src="drawable/avatar"
😊Thanks to everyone who answered my question after a lot of struggle to find why my image view is not loading I got the mistake, actually what I did wrong was in
val url = "https://i.redd.it/bi9tnlxmqlr71.jpg"
I put the image link in val url instead of API link which is
"https://meme-api.herokuapp.com/gimme"
So the correct one is :
val url ="https://meme-api.herokuapp.com/gimme"
After this correction, my meme is loading.
Also, "tools:srcCompat="#tools:sample/avatars" is only used for debugging, it doesn't do anything when you run the app.
Correct code,
MainActivity.kt
package com.example.memeshare
import android.graphics.drawable.Drawable
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadMeme()
}
private fun loadMeme(){
var memeImageview = findViewById<ImageView>(R.id.imageView)
// ...
// Instantiate the RequestQueue.
val queue = Volley.newRequestQueue(this)
val url = "https://meme-api.herokuapp.com/gimme"
// Request a string response from the provided URL.
val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET, url,null,
{
response ->
val url = response.getString("url")
Glide.with(this).load(url).into(memeImageview)
},
{
Toast.makeText(this,"Something went wrong",Toast.LENGTH_LONG).show()
}
)
queue.add(jsonObjectRequest)
}
fun nextMeme(view: View) {
loadMeme()
}
fun shareMeme(view: View) {}
// Add the request to the RequestQueue.
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:srcCompat="#tools:sample/avatars"/>
<Button
android:id="#+id/shareButton"
android:layout_width="190dp"
android:layout_height="wrap_content"
android:text="#string/share"
android:padding="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:onClick="shareMeme"/>
<Button
android:id="#+id/nextButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:width="190dp"
android:padding="32dp"
android:text="#string/next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:onClick="nextMeme"/>
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintGuide_percent="0.5"/>
</androidx.constraintlayout.widget.ConstraintLayout>

When I try to use my layout id from my mainactivity in my secondactivity.kt page it returns as null and the app crashes

I'm trying to make a quiz app where on the homepage you click the + button and it takes you to a new page where you input the title of the quiz. Once you click the check button it takes you back to the homepage and the new quiz in the form of a button is created there. However, when I try to use the id for the layout from my mainactivity it returns as null and when the app crashes when I click the check button. Does anyone have any idea how I can fix this?
Second activity:
package com.example.k_ari
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Gravity
import android.widget.Button
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.Toast
import com.google.android.material.floatingactionbutton.FloatingActionButton
class Page2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_page2)
val button = Button(this#Page2)
button.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
val txtt = findViewById<EditText>(R.id.txt)
val textmessage: String = txtt.text.toString()
button.setText(textmessage)
val message = "New quiz created"
val toast1= Toast.makeText(applicationContext, message, Toast.LENGTH_LONG)
toast1.setGravity(Gravity.CENTER, 0,0)
val layout = findViewById<LinearLayout>(R.id.mainlayout)
val btn = findViewById<FloatingActionButton>(R.id.floatingActionButton2)
btn.setOnClickListener{
layout.addView(button)
toast1.show()
val intent = Intent(this#Page2, MainActivity::class.java)
startActivity(intent)
}
}
}
Second activity xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/secondlayout"
android:orientation="vertical"
tools:context=".Page2">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#99141414"
android:backgroundTint="#180030"
android:gravity="center_horizontal"
android:padding="20dp"
android:text="Enter the title:"
android:textAlignment="center"
android:textColor="#DADADA"
android:textSize="35sp"
android:textStyle="bold"
android:translationX="50dp"
android:translationY="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.433"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.112" />
<EditText
android:id="#+id/txt"
android:layout_width="361dp"
android:layout_height="67dp"
android:autofillHints="title"
android:background="#99141414"
android:backgroundTint="#180030"
android:hint="title"
android:inputType="text"
android:padding="10dp"
android:textColor="#DADADA"
android:textColorHint="#9ADCDCDC"
android:textSize="28sp"
android:translationX="25dp"
android:translationY="170dp"
app:layout_constraintBottom_toTopOf="#+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:contentDescription="#string/todo"
android:focusable="true"
android:translationX="300dp"
android:translationY="400dp"
app:backgroundTint="#180030"
app:layout_constraintBottom_toTopOf="#+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
Main activity:
package com.example.k_ari
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.google.android.material.floatingactionbutton.FloatingActionButton
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val floatingActionButton = findViewById<FloatingActionButton>(R.id.btn)
floatingActionButton.setOnClickListener{
val intent = Intent(this, Page2::class.java)
startActivity(intent)
}
}
}
Main activity xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/mainlayout"
android:orientation="vertical"
android:layout_gravity="center"
tools:context=".MainActivity">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:backgroundTint="#250A43"
android:backgroundTintMode="add"
android:clickable="true"
android:contentDescription="#string/todo"
android:tint="#250A43"
android:translationX="280dp"
android:translationY="580dp"
app:backgroundTint="#250A43"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.56"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:rippleColor="#FFFFFF"
app:srcCompat="#android:drawable/ic_input_add"
android:focusable="true" />
</LinearLayout>
Logcat:
2020-12-23 15:32:03.599 1474-1474/com.example.k_ari E/Toast: setGravity() shouldn't be called on text toasts, the values won't be used
2020-12-23 15:32:05.482 1474-1474/com.example.k_ari E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.k_ari, PID: 1474
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.LinearLayout.addView(android.view.View)' on a null object reference
at com.example.k_ari.Page2$onCreate$1.onClick(Page2.kt:35)
at android.view.View.performClick(View.java:8178)
at android.view.View.performClickInternal(View.java:8147)
at android.view.View.access$3700(View.java:888)
at android.view.View$PerformClick.run(View.java:30233)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8414)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:596)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
You cannot access a View from the Activity that does not hold it.
to handle data between activities like this, you should read about ViewModel and/or SharedPreferences
https://developer.android.com/topic/libraries/architecture/viewmodel
https://developer.android.com/reference/android/content/SharedPreferences

How to save a screen as an image in the mobile device. I am using kotlin to make a meme creator app for android

I am making a meme creator app. I will load memes from firebase database and the user will select one of the meme templates and will start editting it. For entering text in the memes i am using the github library implementation 'com.github.hantrungkien:Awesome-Input-Layout:1.0.0'
It allows the user to rotate the textview, move it with finger and all. But the problem is i am very new to android dev. I dont know how to save the background meme image plus the text entered by user in the user's device or gallery. Please tell me detailed steps as i am pretty new. Every help is appreciated.
My Meme editting activity code
package com.example.memecreator
import android.app.Activity
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.RelativeLayout
import com.squareup.picasso.Picasso
import htkien.awesome_input.AwesomeInputLayout
import kotlinx.android.synthetic.main.activity_meme.*
class MemeActivity : AppCompatActivity() {
val TAG = MainActivity::class.java.simpleName
var mLayoutRoot: RelativeLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meme)
setSupportActionBar(meme_toolbar)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
meme_toolbar.setNavigationOnClickListener {
finish()
}
//I am passing intent from last activity and using picasso to load images. Its working fine.
val intent=intent
val memeImage=intent.getStringExtra("image")
Picasso.get().load(memeImage).into(meme_image)
mLayoutRoot=findViewById<RelativeLayout>(R.id.rl_meme)
val added=findViewById<Button>(R.id.btn_add_text)
added.setOnClickListener {
onClickBtnAddText()
}
}
override fun onBackPressed() {
if (!mLayoutRoot!!.isFocused) {
mLayoutRoot!!.requestFocus()
mLayoutRoot!!.requestFocusFromTouch()
} else {
super.onBackPressed()
}
}
private fun onClickBtnAddText() {
val awesomeLayout = LayoutInflater.from(this).inflate(
R.layout.layout_awesome_input,
mLayoutRoot,
false
) as AwesomeInputLayout
mLayoutRoot?.addView(awesomeLayout)
awesomeLayout.post {
val w = mLayoutRoot!!.width
val h = mLayoutRoot!!.height
awesomeLayout.x = w / 2 - awesomeLayout.width / 2.toFloat()
awesomeLayout.y = h / 2 - awesomeLayout.height / 2.toFloat()
awesomeLayout.requestLayout()
awesomeLayout.visibility = View.VISIBLE
showKeyboard(this#MemeActivity)
}
awesomeLayout.setDeleteViewListener { awesomeLayout ->
hideKeyboard(awesomeLayout)
mLayoutRoot!!.requestFocus()
mLayoutRoot!!.requestFocusFromTouch()
try {
mLayoutRoot!!.removeView(awesomeLayout)
} catch (e: IndexOutOfBoundsException) {
Log.e(TAG, "onDeleteView: ", e)
}
}
}
private fun hideKeyboard(view: View) {
val imm =
view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.toggleSoftInput(
InputMethodManager.HIDE_IMPLICIT_ONLY,
0
) // hide
}
private fun showKeyboard(activity: Activity) {
val imm = activity.getSystemService(
Activity.INPUT_METHOD_SERVICE
) as InputMethodManager
imm.toggleSoftInput(
0,
InputMethodManager.HIDE_IMPLICIT_ONLY
) // show
}
}
My Meme editting xml code
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rl_meme"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MemeActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar_layout_meme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
android:background="#android:color/white">
<androidx.appcompat.widget.Toolbar
android:id="#+id/meme_toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#color/colorDarkGrey">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Meme"
android:textSize="20sp"
android:maxLines="1"
android:textStyle="bold"
android:textColor="#android:color/white"
android:layout_centerVertical="true"/>
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/meme_image"
android:layout_width="match_parent"
android:layout_height="420dp"
android:layout_marginTop="152dp"
android:scaleType="fitXY"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_add_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#id/meme_image"
android:text="Add Text"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/meme_image" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
and finally the design of the edittext which i used from the github library
<?xml version="1.0" encoding="utf-8"?>
<htkien.awesome_input.AwesomeInputLayout
xmlns:autofit="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_marginTop="152dp"
android:background="#drawable/button_black_background"
android:orientation="vertical"
android:visibility="invisible">
<ImageButton
android:id="#+id/button_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#android:color/transparent"
android:scaleType="fitXY"
android:src="#drawable/ic_cross" />
<EditText
android:id="#+id/edit_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_margin="10dp"
android:hint="Type"
android:imeOptions="flagNoExtractUi"
android:textColor="#color/colorDark"
android:textColorHint="#color/colorDark"
android:textSize="16sp" />
</htkien.awesome_input.AwesomeInputLayout>
This is a screenshot image of my edit meme activity screen. I want to save this in the device
Let's modify the ConstraintLayout inside activity_meme layout a little bit,
...
...
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/meme_container"
android:layout_width="match_parent"
android:layout_height="420dp"
android:layout_marginTop="152dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/meme_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY" />
</FrameLayout>
<Button
android:id="#+id/btn_add_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#id/meme_container"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:text="Add Text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/meme_container" />
</androidx.constraintlayout.widget.ConstraintLayout>
...
...
Inside onCreate, replace
mLayoutRoot = findViewById<RelativeLayout>(R.id.rl_meme)
with
mLayoutRoot = findViewById<FrameLayout>(R.id.meme_container)
This layout will now contain the meme image with text. Hence we call drawToBitmap on mLayoutRoot and save the image.

RecyclerView doesn't display all items with ScrollView and middle items are streched using NestedScrollView

I have a grid supported by recyclerview inside a ConstraintLayout inside a ScrollView.
Although 20 items are inserted in setList() (I debugged it), only 9 items are displayed when using ScrollView
When I switch to NestedScrollView all 20 items are displayed, but the items in the middle are streched. Not the images, but it seems that there is a background behind streched 3 times the actual size of the item/image.
I'm using androidx libraries.
Fragment layout
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimaryDark"
tools:context=".ui.details.DetailsFragment">
<ImageView
android:id="#+id/detail_backdrop"
android:layout_width="match_parent"
android:layout_height="220dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:scaleType="centerCrop"
android:src="#drawable/clapperboard"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/play_symbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#+id/detail_backdrop"
app:layout_constraintEnd_toEndOf="#+id/detail_backdrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/detail_backdrop"
app:srcCompat="#drawable/ic_play_circle_outline_white_96dp" />
<ProgressBar
android:id="#+id/details_progress_bar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Some other views...
<TextView
android:id="#+id/tv_my_list_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/my_list_at_details"
app:layout_constraintEnd_toEndOf="#+id/wish_list_btn"
app:layout_constraintStart_toStartOf="#+id/wish_list_btn"
app:layout_constraintTop_toBottomOf="#id/wish_list_btn" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_recommended"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_my_list_details"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
List item layout
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/movie_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="10dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/movie_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/iv_poster"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="#drawable/clapperboard" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
Adapter
package com.lacourt.myapplication.ui.details
import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Point
import android.graphics.drawable.Drawable
import android.util.DisplayMetrics
import android.util.Log
import android.view.Display
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.lacourt.myapplication.AppConstants
import com.lacourt.myapplication.R
import com.lacourt.myapplication.dto.DbMovieDTO
import com.lacourt.myapplication.ui.OnItemClick
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.movie_list_item.view.*
class RecommendedAdapter(
private val context: Context?,
private val onItemClick: OnItemClick,
private var list: ArrayList<DbMovieDTO>
) : RecyclerView.Adapter<RecommendedHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecommendedHolder {
val view =
LayoutInflater.from(context).inflate(R.layout.list_item_recommended, parent, false)
return RecommendedHolder(view)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: RecommendedHolder, position: Int) {
Log.d("grid-log", "onBindViewHolder() called, position = $position, list.size = ${list.size}")
// get device dimensions
val displayMetrics = DisplayMetrics()
(context as Activity).windowManager.defaultDisplay.getMetrics(displayMetrics)
val width = displayMetrics.widthPixels
val maxHeight= width.div(3) * 1.5
holder.poster.minimumHeight = maxHeight.toInt()
holder.apply {
Picasso.get()
.load("${AppConstants.TMDB_IMAGE_BASE_URL_W185}${list[position].poster_path}")
.placeholder(R.drawable.clapperboard)
.into(poster)
cardView.setOnClickListener {
val id = list[position].id
if (id != null)
onItemClick.onItemClick(id)
else
Toast.makeText(
context,
"Sorry. Can not load this movie. :/",
Toast.LENGTH_SHORT
).show()
}
}
}
fun setList(list: List<DbMovieDTO>) {
Log.d("grid-log", "setList() called")
this.list.clear()
this.list.addAll(list)
notifyDataSetChanged()
}
}
class RecommendedHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var poster = itemView.iv_poster
var cardView = itemView.movie_card_view
}
Any solutions for this strange behavior?
Since it may help someone in the future, I found a solution:
I just added holder.cardView.layoutParams.height = maxHeight.toInt() to onBindViewHolder of my adapter class and now every item layout is in the correct size.
Since you are using a constraint layout, you should let the constraints set the size, in general.
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_recommended"
android:layout_width="0dp"
android:layout_height="dp"
...
0dp in this case means let the constraints set the value.

Categories

Resources