GeoNames 和 JDOM 在 shrinkResources 之后请求 java.rmi.RemoteException
GeoNames and JDOM request java.rmi.RemoteException after shrinkResources
我正在使用 GeoNames Java Client 在 Android 应用程序中自动完成地名:用户键入一些字符并显示建议列表。
还需要库 jdom-1.0.jar,以解析 GeoNames 获取的 XML 结果。
一切正常,除非我在 build.gradle.
中添加 shrinkResources true
此时一些关键的class迷路了,我不知道是哪个...我只知道WebService.search()
失败了,但我无法理解为什么 是否失败。事实上,这里请求 java.rmi.RemoteException
,但 Android 不支持 RMI 库,因此抛出 ClassNotFoundException
而不是异常堆栈跟踪。
PlaceFinder.java:
public class PlaceFinder extends AppCompatAutoCompleteTextView {
ToponymSearchCriteria searchCriteria;
public PlaceFinder( Context context, AttributeSet attributeSet ) {
super( context, attributeSet );
Adapter adapter = new Adapter(context, android.R.layout.simple_spinner_dropdown_item);
setAdapter(adapter);
WebService.setUserName("demo");
searchCriteria = new ToponymSearchCriteria();
searchCriteria.setMaxRows(3);
}
class Adapter extends ArrayAdapter<String> implements Filterable {
List<String> places;
Adapter( Context context, int layout ) {
super( context, layout );
places = new ArrayList<>();
}
@Override
public int getCount() {
return places.size();
}
@Override
public String getItem(int index) {
return places.get(index);
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering( CharSequence constraint ) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {
searchCriteria.setNameStartsWith(constraint.toString());
try {
ToponymSearchResult searchResult = WebService.search(searchCriteria); // search() fails
places.clear();
for( Toponym toponym : searchResult.getToponyms() ) {
places.add( toponym.getName() + ", " + toponym.getCountryName() );
}
filterResults.values = places;
filterResults.count = places.size();
} catch( Exception e ) {
e.printStackTrace(); // The class "java.rmi.RemoteException" is requested but missing
}
}
return filterResults;
}
@Override
protected void publishResults( CharSequence constraint, FilterResults results ) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
}
}
}
致命异常(回溯):
FATAL EXCEPTION: Filter
Process: com.example, PID: 32084
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/rmi/RemoteException;
at com.example.PlaceFinder$Adapter.performFiltering(:57)
at android.widget.Filter$RequestHandler.handleMessage(Filter.java:234)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
Caused by: java.lang.ClassNotFoundException: Didn't find class "java.rmi.RemoteException" on path: DexPathList[[zip file "/data/app/com.example-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at org.jdom.JDOMException.getNestedException(:294)
at org.jdom.JDOMException.getMessage(:144)
at java.lang.Throwable.getLocalizedMessage(Throwable.java:188)
at java.lang.Throwable.toString(Throwable.java:355)
at java.lang.Throwable.printStackTrace(Throwable.java:315)
at java.lang.Throwable.printStackTrace(Throwable.java:282)
at org.jdom.JDOMException.printStackTrace(:216)
at java.lang.Throwable.printStackTrace(Throwable.java:236)
at org.jdom.JDOMException.printStackTrace(:189)
at com.example.PlaceFinder$Adapter.performFiltering(:57)
at android.widget.Filter$RequestHandler.handleMessage(Filter.java:234)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
Suppressed: java.lang.ClassNotFoundException: java.rmi.RemoteException
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 15 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
如何解决这个双层问题?
我仍然不知道 shrinkResources
删除了哪个基本 class 或方法,但我尝试了几个小时后找到的解决方案只是添加到 proguard-rules.pro 规则:
-keep class org.jdom.input.* { *; }
就是这样。
同时我还发现可以将 JDOM 升级到更新的版本,它也与 GeoNames 兼容。不要使用 GeoNames 提供的 jdom-1.0.jar,而是添加到 build.gradle 依赖项:
implementation 'org.jdom:jdom:1.1.3'
此外,在这种情况下,需要上述 ProGuard 规则。
JDOM 2 似乎不再与 GeoNames 1.1.14 兼容。
我正在使用 GeoNames Java Client 在 Android 应用程序中自动完成地名:用户键入一些字符并显示建议列表。
还需要库 jdom-1.0.jar,以解析 GeoNames 获取的 XML 结果。
一切正常,除非我在 build.gradle.
中添加 shrinkResources true
此时一些关键的class迷路了,我不知道是哪个...我只知道WebService.search()
失败了,但我无法理解为什么 是否失败。事实上,这里请求 java.rmi.RemoteException
,但 Android 不支持 RMI 库,因此抛出 ClassNotFoundException
而不是异常堆栈跟踪。
PlaceFinder.java:
public class PlaceFinder extends AppCompatAutoCompleteTextView {
ToponymSearchCriteria searchCriteria;
public PlaceFinder( Context context, AttributeSet attributeSet ) {
super( context, attributeSet );
Adapter adapter = new Adapter(context, android.R.layout.simple_spinner_dropdown_item);
setAdapter(adapter);
WebService.setUserName("demo");
searchCriteria = new ToponymSearchCriteria();
searchCriteria.setMaxRows(3);
}
class Adapter extends ArrayAdapter<String> implements Filterable {
List<String> places;
Adapter( Context context, int layout ) {
super( context, layout );
places = new ArrayList<>();
}
@Override
public int getCount() {
return places.size();
}
@Override
public String getItem(int index) {
return places.get(index);
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering( CharSequence constraint ) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {
searchCriteria.setNameStartsWith(constraint.toString());
try {
ToponymSearchResult searchResult = WebService.search(searchCriteria); // search() fails
places.clear();
for( Toponym toponym : searchResult.getToponyms() ) {
places.add( toponym.getName() + ", " + toponym.getCountryName() );
}
filterResults.values = places;
filterResults.count = places.size();
} catch( Exception e ) {
e.printStackTrace(); // The class "java.rmi.RemoteException" is requested but missing
}
}
return filterResults;
}
@Override
protected void publishResults( CharSequence constraint, FilterResults results ) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
}
}
}
致命异常(回溯):
FATAL EXCEPTION: Filter
Process: com.example, PID: 32084
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/rmi/RemoteException;
at com.example.PlaceFinder$Adapter.performFiltering(:57)
at android.widget.Filter$RequestHandler.handleMessage(Filter.java:234)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
Caused by: java.lang.ClassNotFoundException: Didn't find class "java.rmi.RemoteException" on path: DexPathList[[zip file "/data/app/com.example-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at org.jdom.JDOMException.getNestedException(:294)
at org.jdom.JDOMException.getMessage(:144)
at java.lang.Throwable.getLocalizedMessage(Throwable.java:188)
at java.lang.Throwable.toString(Throwable.java:355)
at java.lang.Throwable.printStackTrace(Throwable.java:315)
at java.lang.Throwable.printStackTrace(Throwable.java:282)
at org.jdom.JDOMException.printStackTrace(:216)
at java.lang.Throwable.printStackTrace(Throwable.java:236)
at org.jdom.JDOMException.printStackTrace(:189)
at com.example.PlaceFinder$Adapter.performFiltering(:57)
at android.widget.Filter$RequestHandler.handleMessage(Filter.java:234)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
Suppressed: java.lang.ClassNotFoundException: java.rmi.RemoteException
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 15 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
如何解决这个双层问题?
我仍然不知道 shrinkResources
删除了哪个基本 class 或方法,但我尝试了几个小时后找到的解决方案只是添加到 proguard-rules.pro 规则:
-keep class org.jdom.input.* { *; }
就是这样。
同时我还发现可以将 JDOM 升级到更新的版本,它也与 GeoNames 兼容。不要使用 GeoNames 提供的 jdom-1.0.jar,而是添加到 build.gradle 依赖项:
implementation 'org.jdom:jdom:1.1.3'
此外,在这种情况下,需要上述 ProGuard 规则。
JDOM 2 似乎不再与 GeoNames 1.1.14 兼容。