I have an android homescreen widget created with the new Glance
api which contains a lazy column. Each row in the column displays an image with ImageProvider(contentUri)
.
The image has been retrieved from a URL with Glide
and saved to internal storage file with FileOutputStream(filename)
. see MainActivity
below.
When attempting to retrieve and show the image with getUriForFile()
my widget just shows a message "Loading..." and never displays the image. No crash occurs. It just never loads the image.
How can I pull the image from internal storage and display it in LazyColumnRow()
?
Note that I am only showing one bitmap in this example as proof of concept, but intend to eventually show 10+ bitmaps. I am following the recommendation in below post, which suggests using URI for multiple images.
Crash in glance app widget image when trying to display bitmap
Note that when I pull the same URI in MainActivity()
it works and displays the image in ImageView.
Composable defined in
GlanceAppWidget
Content()
@Composable
fun LazyColumnRow(
/*LazyColumnRow is called from a LazyColumn, with each filename passed in here*/
) {
val context = LocalContext.current
val filepath = File(context.getFilesDir(), "my_images")
val filename = File(filepath, "default_image.png") /*each LazyColumn item will have different filename in PROD*/
val contentUri: Uri = FileProvider.getUriForFile(context,"${context.packageName}.fileprovider", filename)
Row(modifier = GlanceModifier) {
Image(
modifier = GlanceModifier.size(28.dp),
provider = ImageProvider(contentUri), /*this is not working*/
contentDescription = "Image"
)
}
}
MainActivity
class which downloads and stores Bitmap. It can also succesfully retrieve URI and display in imageView.
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@OptIn(ExperimentalAnimationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = inflate(layoutInflater)
setContentView(binding.root)
//Download image from url
var bitmap: Bitmap? = null
CoroutineScope(Dispatchers.IO).launch {
bitmap = Glide.with(baseContext)
.asBitmap()
.load("https://picsum.photos/id/237/200")
.submit()
.get()
}
//store image in internal storage file
val filepath = File(baseContext.getFilesDir(), "my_images")
if (!filepath.exists()) {
filepath.mkdirs()
}
val filename = File(filepath, "default_image.png")
try {
FileOutputStream(filename).use { out ->
bitmap?.compress(Bitmap.CompressFormat.PNG, 100, out)
}
} catch (e: IOException) {
e.printStackTrace()
}
//retrieve image from internal storage file
val contentUri: Uri = getUriForFile(
baseContext,
"$packageName.fileprovider",
filename)
//display in imageView. This code works.
val imageView = findViewById<ImageView>(R.id.myImage)
imageView.setImageURI(contentUri)
}
}
Content Provider declared in Manifest for
FileProvider
URI
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
xml/file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="/" />
<files-path name="my_docs" path="docs/" />
</paths>
You need to explicitly grant read permission to the Home activities, for example with: