I am developing an android based app which process speech. My app references a .jar dependency and I have successfully added that jar as a library in my project but as I run the project it gives me java.lang.NoClassDefFoundError: for an class file which is there in jar file
Basically the class file which throwing the above error imports javax.sound.sampled packages in the code.
I am working on this part since last couple of months now but didn't found any way out of this.
I have tried copying the source code of jar library into android studio and then referencing javax.sound.sampled jar to it even tried copying javax.sound.sampled source code into android and then attaching them as per flow but still no luck.
It would be nice if I get alternatives for below imports, as it will solve the issue
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFileFormat.Type;
import javax.sound.sampled.AudioFormat.Encoding;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
Edit:
I am facing problem here
String strFullName = "com/example/packagename/AudioFileReader.class";
Enumeration<?> configs = null;
try {
configs = Service.class.getClassLoader().getSystemResources("strFullName");
} catch (Throwable e) {
}
if (configs != null) {
while (configs.hasMoreElements()) {
URL configFileUrl = (URL) configs.nextElement();
InputStream input = null;
try {
input = configFileUrl.openStream();
} catch (Throwable e2) {
}
if (input != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
try {
for (String strLine = reader.readLine(); strLine != null; strLine = reader.readLine()) {
strLine = strLine.trim();
int nPos = strLine.indexOf(35);
if (nPos >= 0) {
strLine = strLine.substring(0, nPos);
}
if (strLine.length() > 0) {
providers.add(strLine);
}
}
} catch (Throwable e22) {
}
}
}
}
Iterator<String> iterator = providers.iterator();
return iterator;
}
It gives me TwoEnumerationsInOne and configs.hasMoreElements() gives false so not able to go into while loop.
AudioFileReader.java is included in the package
Thanks in advance.
Related
in the app when receiving an intent which was created from other app and has a file path, it can access the file's content using the file path.
the question is if that path (call it as 'link-path') is a 'hard link' to the original file, is it possible to find the original file through this 'link-path'?
Searched and find some post like:
https://unix.stackexchange.com/questions/122333/how-to-tell-which-file-is-original-if-hard-link-is-created
they show some unix shell command. Not sure if there is some android file system support for this, anyone having suggestion?
You can use this code I made, based on this post. It will return the target path of any path. If path is not a symbolic link, it will return itself. If path doesn't exist it returns null.
public static String findLinkTarget(String path) {
try {
Process findTarget = Runtime.getRuntime().exec("readlink -f " + path);
BufferedReader br = new BufferedReader(new InputStreamReader(findTarget.getInputStream()));
return br.readLine();
} catch (IOException e) {
Log.w(TAG, "Couldn't find target file for link: " + path, e);
}
}
The code wasn't tested, but I tested the command on Termux and it worked.
EDIT: Try calling getCanonicalPath() on your file, I think it resolves the symlink.
find a way by comparing the inode, in api >21 android has Os to get it, otherwise using the command "ls -i" to get the inode. One issue though, tested on api<=18 the "ls -i" does not return any thing (tested on emulator), in that case maybe fallback to compare the file's size and timestamp.
static String getFileInode(File file) {
String inode = "-1";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
StructStat st = null;
try {
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file,
ParcelFileDescriptor.parseMode("r"));
st = Os.fstat (pfd.getFileDescriptor());
if (st != null) {
inode = ""+st.st_ino;
}
} catch (Exception e) {
Log.e(TAG, "fstat() failed”+ e.getMessage());
}
} else {
BufferedReader reader = null;
try {
Process process = Runtime.getRuntime().exec(("ls -il " + path));
reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
process.waitFor();
String ret = output.toString();
if (!TextUtils.isEmpty(ret)) {
ret = ret.trim();
String[] splitArr = ret.split("\\s+");
if (splitArr.length>0) {
inode = splitArr[0];
}
}
} catch(Exception e) {
Log.e(TAG, "!!! Runtime.getRuntime().exec() exception, cmd:”+cmd);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {}
}
}
}
return inode;
}
I'm a newbie in Android Development. I want to get metadata from Shoutcast Server, and found streamscraper to be the easiest one to use. But my problem is, I don't know how to use it. The homepage itself only showing something like in how to use it:
import java.net.URI;
import java.util.List;
import net.moraleboost.streamscraper.Stream;
import net.moraleboost.streamscraper.Scraper;
import net.moraleboost.streamscraper.scraper.IceCastScraper;
public class Harvester {
public static void main(String[] args) throws Exception {
Scraper scraper = new IceCastScraper();
List streams = scraper.scrape(new URI("http://host:port/"));
for (Stream stream: streams) {
System.out.println("Song Title: " + stream.getCurrentSong());
System.out.println("URI: " + stream.getUri());
}
}
}
Searched anywhere and found no project sample of how to use this. I hope one of you can post the code of how to use it, or make a tutorial for it.
No need to use external libraries. The following pages give you:
Current song: http://yourstream:port/currentsong?sid=#
Last 20 songs: http://yourstream:port/played.html?sid#
Next songs: http://yourstream:port/nextsongs?sid=#
An Android java class which prints the current song:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
public class NowPlaying {
public void CurrentSong() {
try
{
URL url = new URL("http://www.mofosounds.com:8000/currentsong?sid=#");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
catch(Exception e)
{
System.out.println(e.toString());
}
}
}
Note: the nextsongs?sid=#feature must be supported by the player of the stream.
I was wondering if it is possible to find all the libraries that are included in the Android project programmatically. I am writing a library which would need info about other libraries included in the project. Any help much appreciated.
i have made a simple function, just make a call to this function when you want to have the details.
public static void checkLibrary(){
try {
Log.e(" i am in","checklibrary");
Set<String> libs = new HashSet<String>();
String mapsFile = "/proc/" + android.os.Process.myPid() + "/maps";
BufferedReader reader = new BufferedReader(new FileReader(mapsFile));
String line;
while ((line = reader.readLine()) != null) {
if (line.endsWith(".so")) {
int n = line.lastIndexOf(" ");
libs.add(line.substring(n + 1));
}
}
Log.e("Ldd", libs.size() + " libraries:");
for (String lib : libs) {
Log.e("Ldd", lib);
}
} catch (FileNotFoundException e) {
// Do some error handling...
} catch (IOException e) {
// Do some error handling...
}
}
For future readers.
You may use Mike Penz's AboutLibraries library
Benefits
Allow to list external, internal libraries used in your project
Out of box activity or fragment with list of libraries used in your project.
I need unzip a .zip file of 2.5mb(1087 files - *.html, *.css and *.db) in android, i have used java.util.zip, it works fine, but i need improve the performance, the unzip process last 1.10 minutes, i need reduce this time.
I have followed some recomendations for improve the performance, for example :
Use BufferedInputStream, FileOutputStream and BufferedOutputStream.
Read the zip in blocks :
byte data[] = new byte[2048];
while ((counter = bisMediaFile.read(data, 0, 2048)) != -1)
{
bosMediaFile.write(data, 0, counter);
}
Is there any way to improve my code?. I was searching third party zip programs to use programatically, for example i tried the 7ZipJBinding, but it looks like android doesn't support this, because i referenced the sevenzipjbinding.jar and sevenzipjbinding-AllPlatforms.jar but i get an error : "Native Libraries Detected in sevenzipjbinding-AllPlatforms". At 7zip homepage there are versions for MAC, Windows, Linux, but i didn't see anything about android.
Could you please recommend any other library to unzip files in android?
This is my all code :
public static void processZipFile(String strBinaryPath,String strExtractPath, String strDestinationDBPath) throws Exception
{
ZipFile zipInFile = null;
try
{
if (strExtractPath != null)
{
zipInFile = new ZipFile(strBinaryPath);
for (Enumeration<? extends ZipEntry> entries = zipInFile.entries(); entries.hasMoreElements();)
{
ZipEntry zipMediaEntry = entries.nextElement();
if (zipMediaEntry.isDirectory())
{
File mediaDir = new File(String.format("%s\\%s", strExtractPath, zipMediaEntry.getName()));
mediaDir.mkdirs();
}
else
{
BufferedInputStream bisMediaFile = null;
FileOutputStream fosMediaFile = null;
BufferedOutputStream bosMediaFile = null;
try
{
String strFileName = String.format("%s\\%s", strExtractPath, zipMediaEntry.getName());
File uncompressDir = new File(strFileName).getParentFile();
uncompressDir.mkdirs();
//if is a database file, extract to other path : android.movinginteractive.com/databases
if(strFileName.contains(".db"))
strFileName = String.format("%s\\%s", strDestinationDBPath, ExtractDBName(zipMediaEntry.getName()));
bisMediaFile = new BufferedInputStream(zipInFile.getInputStream(zipMediaEntry));
fosMediaFile = new FileOutputStream(strFileName);
bosMediaFile = new BufferedOutputStream(fosMediaFile);
int counter;
byte data[] = new byte[2048];
while ((counter = bisMediaFile.read(data, 0, 2048)) != -1)
{
bosMediaFile.write(data, 0, counter);
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (bosMediaFile != null)
{
bosMediaFile.flush();
bosMediaFile.close();
}
if (bisMediaFile != null)
bisMediaFile.close();
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (zipInFile != null)
zipInFile.close();
File flZipToDelete = new File(strBinaryPath);
if(flZipToDelete.exists())
flZipToDelete.delete();
}
}
I'm sure you could find a C or C++ code snippet for unzipping files and run it through the Android NDK. That said, I'm not sure what performance gains you might get.
I am attempting to load a set of JAR files that go together to make up an API. For some reason I can only load classes not dependent on definitions in other JARs. I am beginning to suspect that the Android classloaders simply do not handle implementing an interface from one JAR file in another. For this reason I've also unpacked the classes into a common dir however this doesn't work either.
Please see the following code. Apologies for any anomalies, but I've tried to ensure it will compile straight up if pasted into an ADT project called MyProj.
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import dalvik.system.PathClassLoader;
import android.content.Context;
// IPluginSource simply defines the method here at the top.
public class AndroidPluginSource implements IPluginSource
{
#Override
public void doSearching(ArrayList<ClassLoader> classLoaders, ArrayList<String> classNames)
{
String jarPaths = "";
// For each of the raw resources, JARs compiled into the 'res/raw' dir...
for (Field str : R.raw.class.getFields())
{
String resName = str.getName();
Logger.log(Level.FINE, "Resource: " + str);
try
{
// Copy the JAR file to the local FS.
InputStream is = MyProj.self.getResources().openRawResource(str.getInt(this));
OutputStream os = MyProj.self.openFileOutput(resName + ".jar", Context.MODE_PRIVATE);
copyData(is, os);
is.close();
os.close();
// Get JAR location.
String jarLoc = MyProj.self.getFilesDir() + File.separator + resName + ".jar";
// First attempt is just single classloaders, so we aren't suprised this won't work.
classLoaders.add(new PathClassLoader(jarLoc, MyProj.self.getClassLoader()));
//Logger.log(Level.FINE, " LOC: " + jarLoc);
// Keep running list of JAR paths, will that work?
if (jarPaths.length() > 0) jarPaths += File.pathSeparator;
jarPaths += jarLoc;
// We have to go through the JARs to get class names...
JarFile jar = new JarFile(jarLoc);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements())
{
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
if (entryName.endsWith(".class"))
{
classNames.add(toClassName(entryName));
Logger.log(Level.FINE, " ENT: " + entryName);
// ...while we're here lets get the class out as a file.
String classLoc = MyProj.self.getFilesDir() + File.separator + entryName;
Logger.log(Level.FINER, " CLS: " + classLoc);
File classFile = new File(classLoc);
classFile.delete();
classFile.getParentFile().mkdirs();
InputStream jis = jar.getInputStream(entry);
//OutputStream jos = MyProj.self.openFileOutput(classLoc, Context.MODE_PRIVATE);
OutputStream jos = new FileOutputStream(classFile);
copyData(jis, jos);
jos.close();
jis.close();
}
}
}
catch (Exception ex)
{
Logger.log(Level.SEVERE, "Failed plugin search", ex);
}
}
File f = MyProj.self.getFilesDir();
recursiveList(f, 0);
// So we have a class loader loading classes...
PathClassLoader cl = new PathClassLoader(VermilionAndroid.self.getFilesDir().getAbsolutePath(), ClassLoader.getSystemClassLoader());
classLoaders.add(cl);
// A JAR loader loading all the JARs...
PathClassLoader jl = new PathClassLoader(jarPaths, ClassLoader.getSystemClassLoader());
classLoaders.add(jl);
// And if edited as below we also have a DexLoader and URLClassLoader.
}
// This is just so we can check the classes were all unpacked together.
private void recursiveList(File f, int indent)
{
StringBuilder sb = new StringBuilder();
for (int x = 0; x < indent; x++) sb.append(" ");
sb.append(f.toString());
Logger.log(Level.INFO, sb.toString());
File[] subs = f.listFiles();
if (subs != null)
{
for (File g : subs) recursiveList(g, indent+4);
}
}
// Android helper copy file function.
private void copyData(InputStream is, OutputStream os)
{
try
{
int bytesRead = 1;
byte[] buffer = new byte[4096];
while (bytesRead > 0)
{
bytesRead = is.read(buffer);
if (bytesRead > 0) os.write(buffer, 0, bytesRead);
}
}
catch (Exception ex) {}
}
// Goes from a file name or JAR entry name to a full classname.
private static String toClassName(String fileName)
{
// The JAR entry always has the directories as "/".
String className = fileName.replace(".class", "").replace(File.separatorChar, '.').replace('/', '.');
return className;
}
}
The following code is where this is called from.
public void enumeratePlugins(IPluginSource source)
{
ArrayList<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
ArrayList<String> classNames = new ArrayList<String>();
source.doSearching(classLoaders, classNames);
logger.log(Level.FINE, "Trying discovered classes");
logger.log(Level.INFO, "Listing plugins...");
StringBuilder sb = new StringBuilder();
// Try to load the classes we found.
for (String className : classNames)
{
//boolean loadedOK = false;
Throwable lastEx = null;
for (int x = 0; x < classLoaders.size(); x++)
{
ClassLoader classLoader = classLoaders.get(x);
try
{
Class dynamic = classLoader.loadClass(className);
if(PluginClassBase.class.isAssignableFrom(dynamic) &&
!dynamic.isInterface() && !Modifier.isAbstract(dynamic.getModifiers()))
{
PluginClassBase obj = (PluginClassBase) dynamic.newInstance();
String classType = obj.getType();
String typeName = obj.getName();
classes.put(typeName, new PluginClassDef(typeName, classType, dynamic));
logger.log(Level.FINE, "Loaded plugin: {0}, classType: {1}", new Object[] {typeName, classType});
sb.append(typeName).append(" [").append(classType).append("], ");
if (sb.length() > 70)
{
logger.log(Level.INFO, sb.toString());
sb.setLength(0);
}
}
lastEx = null;
break;
}
catch (Throwable ex)
{
lastEx = ex;
}
}
if (lastEx != null)
{
logger.log(Level.INFO, "Plugin instantiation exception", lastEx);
}
}
if (sb.length() > 0)
{
logger.log(Level.INFO, sb.substring(0, sb.length()-2));
sb.setLength(0);
}
logger.log(Level.FINE, "Finished examining classes");
}
Thanks for your help.
EDIT: I have also tried adding
URLClassLoader ul = null;
try
{
URL[] contents = new URL[jarURLs.size()];
ul = new URLClassLoader(jarURLs.toArray(contents), ClassLoader.getSystemClassLoader());
}
catch (Exception e) {}
classLoaders.add(ul);
...which gives rise to a new exception - UnsupportedOperationException: Can't load this type of class file.
AND:
DexClassLoader dl = new DexClassLoader(jarPaths, "/tmp", null, getClass().getClassLoader());
classLoaders.add(dl);
Also didn't work correctly, but thanks for the suggestion Peter Knego
I should clarify that in the JAR files I have:
JAR1:
public interface IThing
public class ThingA implements IThing
JAR2:
public class ThingB implements IThing
I'm not entirely sure what you're trying to do, but I suspect what you want isn't supported by the Java language's definition of a class loader.
Class loaders are arranged in a hierarchy. If you ask class loader CL1 for a copy of class Foo, it will ask its parent if it knows what Foo is. That goes up the chain to the bootstrap loader, and as things fail it comes back down, until eventually CL1 gets a chance to go out and find a copy. (It doesn't have to work this way, and there's a test case that deliberately does it "wrong", but it's almost always done like this.)
Suppose CL1 does define Foo. Foo implements IBar, so when preparing that class the VM will ask CL1 to find IBar. The usual search is done.
If IBar is defined in CL2, and CL2 is not a parent of CL1, then nothing in CL1 will be able to see IBar.
So if you're creating a bunch of "peer" class loaders for various jar files, you can't directly reference classes between them.
This is not unique to Android.
If you create a single class loader and put the whole set of jars in the path, you can mix and match however you want.
There was no solution to this problem, I have so-far worked around it.