There's a certain number of classes which I always inject and never ask myself the question: the application context, shared preferences, DAOs, Retrofit, Json object. As you can see, these are usually related the third-party libraries or the Android framework.
Then there are classes which depend on those: the repository is a common example, but there are many more. For example you could have a preference manager which depends on shared preferences and context. Or you could have a class JsonExporter used to export user data which depends on DAOs and the Json mapper.
In turn, there are other classes which depend on those new classes: a view model/presenter in MVVM/MVP architecture could depend on both the repository and JsonExporter for example. At this point you have two choices:
- Instantiate the class yourself. But that means you need to have access to all of the class' dependencies, which are only available through dependency injection...
- so you might as well inject it. The cost of injection at this point is often very low, just adding
@Inject to the constructor. Only the base dependencies have to be provided in a module.
From a certain number of injected base classes, the decision to inject those more nested in the dependency graph really comes automatically.
There are also cases where you'll have a class that depends on nothing. Perhaps you decided to extract code from a big class into another one. Or perhaps the class just has no dependencies. I probably wouldn't inject such a class, there's no point.
Singletons are often handy to inject because the dependency injection framework (e.g. Dagger) can make sure there's always only one instance automatically.
One reason why we do dependency injection is so that classes depend on abstractions, not concretions (aka inversion of control). It's useful to have your class depend on a Repository interface, because you can decide to provide it with the implementation you want, for example RealRepository in the app, and MockRepository in tests. Another example is flavors or build variants: an injected FlavorBehavior interface could have different implementations in two different flavors. It's not the class' responsability to decide which to use.
Note that this is not a definitive answer, and I'm not an expert on the subject. It's an opinion-based subject too.