How to catch a NoClassDefFoundError?
NoClassDefFoundError is an Error not an Exception. if you really want to catch it, you need catch it as an Error
not an Exception
.
try {
Snackbar.make(v, snapbarString, Snackbar.LENGTH_LONG)
.setAction(snapbarTitle, new View.OnClickListener() {
@Override
public void onClick(View v) {
// no implementation required
}
}).show();
} catch (NoClassDefFoundError e) {
Toast.makeText(v.getContext(), snapbarString, Toast.LENGTH_LONG).show();
}
How to use an optional case if library is not present?
if you want use local toast as an optional one, the advantage of isSnackbarPresent
is that only checking the library whether present only once. for example:
private static final boolean isSnackbarPresent;
static{
isSnackbarPresent = classPresent("${package}.Snackbar");
}
private static boolean classPresent(String className) {
try {
ClassLoader.getSystemClassLoader().loadClass(className);
return true;
} catch (ClassNotFoundException ex) {
return false;
}
}
public static void show(View v
, CharSequence snapbarString
, CharSequence snapbarTitle) {
if(isSnackbarPresent){
Snackbar.make(v, snapbarString, Snackbar.LENGTH_LONG)
.setAction(snapbarTitle, new View.OnClickListener() {
@Override
public void onClick(View v) {
// no implementation required
}
}).show();
}else{
Toast.makeText(v.getContext(), snapbarString, Toast.LENGTH_LONG).show();
}
}
Advanced to use an optional case
if you don't want to checking isSnackbarPresent
every the show
method called you can do like this:
public static void show(View v
, CharSequence snapbarString
, CharSequence snapbarTitle) {
toaster.show(v, snapbarString, snapbarTitle);
}
private static final Toaster toaster = classPresent("${package}.Snackbar")
? snackbar()
: locally();
private static Toaster locally() {
return (view, message, title) -> Toast.makeText(view.getContext()
, message
, Toast.LENGTH_LONG).show();
}
private static Toaster snackbar() {
View.OnClickListener NOTHING = (view)->{};
return (view, message, title) -> {
Snackbar.make(view, message, Snackbar.LENGTH_LONG)
.setAction(title, NOTHING).show();
};
}
interface Toaster {
void show(View view, CharSequence message, CharSequence title);
}
private static boolean classPresent(String className) {
try {
ClassLoader.getSystemClassLoader().loadClass(className);
return true;
} catch (ClassNotFoundException ex) {
return false;
}
}
Enhancement
and this pattern is so flexible that can choosing one available Toaster
from all of Toasters, for examples:
interface ToasterProvider{
/**
* @see classPresent(String)
* @return return true if the library is presented in classpath
*/
boolean isPresent();
/**
* @throws NoSuchElementException thrown if toaster library is not present
*/
Toaster toaster() throws NoSuchElementException;
}
List<ToasterProvider> providers = ...;
Toaster toaster = providers.stream()
.filter(ToasterProvider::isPresent)
.findFirst().map(ToasterProvider::toaster)
.orElse(locally());