1

The consensus is that passing a Drawable from one activity to another using Intent is a very bad idea (maybe cause it's slow?). The general recommendation is to pass the Uri of an image instead of the image itself, however this method doesn't apply when your images are stored in an array or list. For example I have a list of Drawables that contains the icons of all the apps a user has. When I need to pass any of these icons to another activity there's no Uri available. So what I did was make the list available in an Application class, meaning I had a class that extended Application and which was called Notifications:

public class Notifications extends Application {

    private List<ResolveInfo> packages;

    public static final String CHANNEL_ID = "exampleServiceChannel";

    @Override
    public void onCreate() { //using onCreate will help you show notifications before any activity begins
        super.onCreate();

        createNotificationChannels();

    }

    public List<ResolveInfo> getPackages() {
        return packages;
    }

    public void setPackages(List<ResolveInfo> packages) {
        this.packages = packages;
    }

    private void createNotificationChannels() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //Check if device running Oreo or higher since notification channels only work Oreo or higher
            NotificationChannel serviceChannel = new NotificationChannel(CHANNEL_ID , getString(R.string.service_channel_name) , NotificationManager.IMPORTANCE_LOW);

            serviceChannel.setDescription(getString(R.string.service_channel_description)); // Can also change anything about channel, like its color

            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null)
            manager.createNotificationChannel(serviceChannel);

        }
    }

And then I filled this packages List inside the main activity like this:

final PackageManager pm = getPackageManager();
Intent main = new Intent(Intent.ACTION_MAIN, null);
main.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> packages = pm.queryIntentActivities(main, 0); //get a list of installed apps.
Notifications notifications = (Notifications) getApplicationContext();
notifications.setPackages(packages);

So then I can access this list from any other activity like so:

Notifications notifications = (Notifications) getApplicationContext();
List<ResolveInfo> packages = notifications.getPackages();
final PackageManager packageManager = getPackageManager();
final Drawable icon = packages.get(position).loadIcon(packageManager);

The problem is that there is a consensus that this is also a bad approach, that creating Application level Lists causes memory leaks. Is it a better or worse approach than using Intent? And what other method is there?

a_local_nobody
  • 7,947
  • 5
  • 29
  • 51
  • 1
    The best solution, most likely, is to get rid of the second activity. Android app development is moving strongly in the direction of having a single activity for the app, with fragments or composables handling individual screens. "Is it a better or worse approach that using Intent?" -- better, in that you are less likely to crash with a `TransactionTooLargeException`. A singleton repository is not a terrible solution here, though having it be a subclass of `Application` is not great. – CommonsWare Feb 22 '21 at 14:07
  • Is it possible to do it without extending the Application class? –  Feb 22 '21 at 14:14
  • 1
    If by "do it" you mean create a singleton repository, then yes. It would be easier if you were using a dependency inversion framework (Dagger/Hilt, Koin, etc.). Your singleton repository would *use* the `Application` singleton to get its drawables, without it *being* the `Application` singleton. – CommonsWare Feb 22 '21 at 14:16
  • What does it say singletons are bad https://programmerr47.medium.com/singletons-in-android-63ddf972a7e7 ? –  Feb 22 '21 at 14:24
  • This guy here said it's better to use application class than singleton: https://stackoverflow.com/a/3888560/14536109 –  Feb 22 '21 at 14:52
  • Just for the record I'm not pretending I know how any of this works under the hood, I just go by whatever experts like you make a consensus about :) –  Feb 22 '21 at 14:53
  • 1
    I do not know who the person is from your first link, and most of the concerns there would be addressed by the use of a dependency inversion framework. Your second link is from over a decade ago, and decade-old Stack Overflow answers are going to have issues. – CommonsWare Feb 22 '21 at 15:02
  • I've been reading around for a while and still have no idea what a dependency inversion framework is. I know I don't have the right to ask this but say I wanted to make the above code become a singleton that uses something like Dagger 2 how would I go about doing it? Examples are of course the best way to explain foreign concepts :) –  Feb 22 '21 at 15:34
  • 1
    "Examples are of course the best way to explain foreign concepts :)" -- I use Koin for dependency inversion in [this sample Kotlin project](https://gitlab.com/commonsguy/cw-jetpack-kotlin/-/tree/v2.0/DiceKoin). I have not covered Dagger in my books, though it is possible I will do a Dagger/Hilt + Java version of `DiceKoin` later this year. – CommonsWare Feb 22 '21 at 15:54
  • It's a bit overwhelming. Is there just an example of how to create and use a singleton using this dependency inversion, and in Java? –  Feb 22 '21 at 16:01
  • 1
    "It's a bit overwhelming" -- if you are referring to the example, that's why there is [a book for the examples in that repo](https://commonsware.com/Jetpack). "Is there just an example of how to create and use a singleton using this dependency inversion, and in Java?" -- Dagger is not especially simple. I'm sure there are tons of Dagger examples out there; I do not have links at my fingertips. On the whole, I recommend structured educational options (books, courses) for bigger topics. – CommonsWare Feb 22 '21 at 16:28
  • Okay say I want to keep it as in the original code, is it acceptable the way it is? Like in the `Notifications` class should I instantiate `packages` inside `onCreate()`? Should `packages` be filled in the `Notifications` class instead of filling it using `setPackages()` in the main activity? And finally does any method or variable in `Notifications` need to be static? `packages` should not change throughout the lifecycle of the activity. –  Feb 22 '21 at 16:54

1 Answers1

1

Not really sure if this is worth as an answer, but you say :

And then I filled this packages List inside the main activity

So, if you're able to fill this in one activity, why not just do it again in the second ? Wouldn't this be a better solution instead of setting things in Application ?


Alternatively, this sounds like the typical "I have data in A that I also need in B" problem, where you might have to consider using fragments and a shared activity

a_local_nobody
  • 7,947
  • 5
  • 29
  • 51
  • Well yes I could recreate the list each time, but I only want one of the drawables in the list to be available in the second activity (the position of that drawable is passed through an Intent). So I'd have to create the entire list again every time another activity is opened. –  Feb 22 '21 at 14:11
  • then you're probably going to want to make use of fragments, as you can set all the data you'd want in the activity – a_local_nobody Feb 22 '21 at 14:13