【问题标题】:Android - dlopen failed: file offset for the libraryAndroid - dlopen 失败:库的文件偏移量
【发布时间】:2016-02-04 23:32:31
【问题描述】:

我正在为我的 arduino 汽车制作遥控应用程序。使用的代码首先在 Eclipse 中使用 Java 进行了测试,现在我正在尝试将相同的代码用于 Android 应用程序。

我使用了jSerialComm库,根据Android Studio,我的代码没有错误,但是当我运行它时,却找不到库?我收到以下错误:

致命异常:主要 进程:com.sahragard.avengrecontroller,PID:11728 java.lang.UnsatisfiedLinkError: dlopen failed: 文件偏移量 图书馆 "/data/user/0/com.sahragard.avengrecontroller/cache/1454627726168-libjSerialComm.so"

= 文件大小:0 >= 0 在 java.lang.Runtime.load(Runtime.java:332) 在 java.lang.System.load(System.java:1069) 在 com.fazecast.jSerialComm.SerialPort.(SerialPort.java:181) 在 com.sahragard.avengrecontroller.Conn.getPorts(Conn.java:19) 在 com.sahragard.avengrecontroller.MainActivity.onCreate(MainActivity.java:25) 在 android.app.Activity.performCreate(Activity.java:6237) 在 android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107) 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 在 android.app.ActivityThread.-wrap11(ActivityThread.java) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:148) 在 android.app.ActivityThread.main(ActivityThread.java:5417) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

我用谷歌搜索了好几个小时,并按照我找到的提示进行操作,但无论我做什么,总是出现同样的错误。我根据这篇文章添加了库: https://stackoverflow.com/a/16628496/4582696

感谢我能得到的任何帮助!提前致谢。

编辑:

MainActivity 类是对包含 Swing 接口的类的改编,其代码添加在此代码下方

public class MainActivity extends AppCompatActivity {



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Spinner conSpinner =(Spinner) findViewById(R.id.spinner);

        String[] a = new String[Conn.getPorts().length];
        for(int i=0; i<Conn.getPorts().length; i++){
            a[i] = Conn.getPorts()[i].getSystemPortName();
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item, a);
        conSpinner.setAdapter(adapter);


        final Button disconnectButton = (Button) findViewById(R.id.disconnect);
        disconnectButton.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                Conn.disconnect();
            }
        });


        final Button connectButton = (Button) findViewById(R.id.connect);
        connectButton.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                Conn.connect(conSpinner.getSelectedItemPosition());
                Runnable run = new Runnable() {
                    public void run() {
                        Conn.listen();
                    }
                };
                Conn.listen = new Thread(run);
                Conn.listen.start();
            }
        });



        final Button up = (Button) findViewById(R.id.upButton);
        up.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                Conn.sendMsg("w");
            }
        });

        final Button down = (Button) findViewById(R.id.downButton);
        down.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                Conn.sendMsg("s");
            }
        });

        final Button left = (Button) findViewById(R.id.leftButton);
        left.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                Conn.sendMsg("a");
            }
        });

        final Button right = (Button) findViewById(R.id.rightButton);
        right.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                Conn.sendMsg("d");
            }
        });




    }
}

原始 Remote_Interface 类

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import com.fazecast.jSerialComm.SerialPort;

import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JTextPane;
import java.awt.SystemColor;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Remote_Interface extends JFrame {

    private JPanel contentPane;
    private JTextField textField;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Remote_Interface frame = new Remote_Interface();
                    frame.setVisible(true);
//                  Conn.listen();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public Remote_Interface() {
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 270, 268);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        JComboBox<String> comboBox = new JComboBox<String> ();
        comboBox.setBounds(20, 46, 214, 20);
        for(int i=0; i<Conn.getPorts().length; i++){
            comboBox.addItem(Conn.getPorts()[i].getSystemPortName());
        }
        contentPane.add(comboBox);

        textField = new JTextField();
        textField.setBounds(20, 131, 214, 20);
        contentPane.add(textField);
        textField.setColumns(10);

        textField.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                Conn.sendMsg(e.getActionCommand());
                textField.setText("");
            }
        });

        JButton btnNewButton = new JButton("Send");
        btnNewButton.setBounds(20, 162, 89, 23);
        contentPane.add(btnNewButton);

        JTextPane txtpnPleaseSelectA = new JTextPane();
        txtpnPleaseSelectA.setBackground(SystemColor.control);
        txtpnPleaseSelectA.setText("Please select a port to connect");
        txtpnPleaseSelectA.setEditable(false);
        txtpnPleaseSelectA.setBounds(10, 11, 214, 20);
        contentPane.add(txtpnPleaseSelectA);

        btnNewButton.setEnabled(false);
        textField.setEnabled(false);

        JButton btnNewButton_1 = new JButton("Connect");
        btnNewButton_1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                Conn.connect(comboBox.getSelectedIndex());
                btnNewButton.setEnabled(true);
                textField.setEnabled(true);
                Runnable run = new Runnable(){
                    public void run(){
                        Conn.listen();
                    }
                };
                Conn.listen = new Thread(run);
                Conn.listen.start();
            }
        });
        btnNewButton_1.setBounds(143, 77, 89, 23);
        contentPane.add(btnNewButton_1);

        JButton btnD = new JButton("Disconnect");
        btnD.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                Conn.disconnect();
                btnNewButton.setEnabled(false);
                textField.setEnabled(false);
            }
        });
        btnD.setBounds(20, 77, 89, 23);
        contentPane.add(btnD);
    }
}

还有 Conn 类

import com.fazecast.jSerialComm.*;

import java.io.PrintWriter;
import java.util.Scanner;

public class Conn {

static  PrintWriter out;
static  SerialPort[] ports;
static  SerialPort port;
static  Scanner in;
static Thread listen;

public static SerialPort[] getPorts(){
    ports = SerialPort.getCommPorts();
    return ports;
}

public static void sendMsg(String s){
    out.println(s);
    out.flush();
}

public static void connect(int i){
    port = ports[i];
    port.openPort();
    port.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
    out = new PrintWriter(port.getOutputStream());
    in = new Scanner(port.getInputStream());
}

public static void disconnect(){
    port.closePort();

}

public static void listen(){// handle the input from the Arduino chip 
    while(in.hasNextLine()){
        System.out.println(in.nextLine());// just print it out to the console 
    }
}



}

【问题讨论】:

  • 你看过其他 SO 线程吗?这个 - stackoverflow.com/a/28152287/1091286 例如谈论芯片架构的差异,考虑到你正在为 arduino 开发一些东西,这可能是问题....
  • 感谢您的回答!我不太明白该问题上发布的答案。但我的问题是,当我在手机或虚拟手机上运行该应用程序时,它会立即崩溃。所以它还没有与 Arduino 芯片建立任何连接
  • at com.fazecast.jSerialComm.SerialPort 第 181 行。库,这意味着它加载
  • @cricket_007 但为什么它说“dlopen 失败:库的文件偏移量”?
  • 根据堆栈跟踪,无论您在第 19 行的 Conn.getPorts 处做什么,库都不喜欢那样。我还看到您正在使用模型对象作为静态实用程序类。那只是糟糕的代码......对不起

标签: java android


【解决方案1】:

我遇到了同样的问题,我能够解决的唯一方法是:

  1. 将文件从 https://github.com/Fazecast/jSerialComm/tree/master/src/main/java/com/fazecast/jSerialComm 复制到我的项目中,并保持与原始文件相同的包名。
  2. https://mvnrepository.com/artifact/com.fazecast/jSerialComm/1.3.11下载的jar 并提取它,复制 \jSerialComm-1.3.11\Android\ 中的所有文件夹
  3. 将所有文件夹粘贴到项目 src/main/jniLibs 中
  4. 调用 System.loadLibrary("jSerialComm");在进行任何方法调用之前。

之后

SerialPort myPort = SerialPort.getCommPort("/dev/ttyMT2");

给出了对应的对象,没有任何UnsatisfiedLinkError。

*另外一件事,如果您使用的是 /dev 文件夹,则可能需要构建一个 android 版本,其中 SeLinux 权限模式设置为 Disabled 或 Permissive。 https://www.centos.org/docs/5/html/5.1/Deployment_Guide/sec-sel-enable-disable.html

【讨论】:

  • 感谢您的回答,我继续前进并创建了自己的蓝牙功能。但我希望它能够很好地为将来遇到这个问题的人们提供解决方案。祝你好运
【解决方案2】:

假设这段代码在 Android 设备上运行良好,我真的不明白为什么会出现任何错误,因为很明显库正在加载到堆栈跟踪中,否则你会得到编译错误和类未找到异常。

无论如何,这就是正在发生的事情......

final Spinner conSpinner =(Spinner) findViewById(R.id.spinner);

String[] a = new String[Conn.getPorts().length];
for(int i=0; i<Conn.getPorts().length; i++){
    a[i] = Conn.getPorts()[i].getSystemPortName();
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_spinner_item, a);
conSpinner.setAdapter(adapter);

以后再做

Conn.connect(conSpinner.getSelectedItemPosition());

...(大致)调用

public static void connect(int i){
    port = SerialPort.getCommPorts()[i];
    port.openPort();
    ...
}

我认为当您明确需要一个实例变量时,您不应该使用静态方法。

我知道这段代码并不“重要”,但我将您的类修改为适当的实例变量,这是保存Conn 变量状态的首选方法。

我会解释static 和非静态变量之间的区别,但这对于您显示的错误来说太宽泛了。


这是带有 cmets 的更新 Conn.java

注意我可能打错字或其他错误,我没有尝试编译这个

import com.fazecast.jSerialComm.*;

import java.io.PrintWriter;
import java.util.Scanner;

public class Conn {

    /* These are instance variables for *THIS* Conn object */
    private  PrintWriter out;
    // static  SerialPort[] ports; // unneccessary
    private  SerialPort port;
    private Scanner in;
    // static Thread listen; // unused

    // this acts like the connect method
    // it initializes all your stuff
    public Conn(int i) {
        this.port = SerialPort.getCommPorts()[i];
        // maybe you should check this to see it was opened
        boolean opened = port.openPort(); 
        if (!opened) {
            System.err.println("Oh no! The port wasn't opened");
        }
        this.port.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
        this.out = new PrintWriter(port.getOutputStream());
        this.in = new Scanner(port.getInputStream());
    }

    // not needed here, just call SerialPort.getCommPorts() in any other class
    /*
    public static SerialPort[] getPorts(){
        ports = SerialPort.getCommPorts();
        return ports;
    }
    */

    public void sendMsg(String s){
        this.out.println(s);
        this.out.flush();
    }

    // Maybe propogate whether you successfully closed the Connection
    public boolean disconnect(){
        return this.port.closePort();
    }

    // You probably want this on a separate thread since this will block the main thread
    // ... that's another topic though
    public void listen(){// handle the input from the Arduino chip 
        while(this.in.hasNextLine()){
            System.out.println(in.nextLine());// just print it out to the console 
        }
    }
} 

这是一个更新的 Activity,其中只有几个按钮侦听器供参考。请注意私有conn 字段和conn,在所有方法中使用小写c,在连接按钮中使用conn = new Conn(position)。你不需要一个静态类就是我想在这里展示的,真的......

import com.fazecast.jSerialComm.*;

public class MainActivity extends AppCompatActivity {

    private conn Conn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Spinner conSpinner =(Spinner) findViewById(R.id.spinner);

        SerialPort[] ports = SerialPort.getCommPorts()
        String[] a = new String[ports.length];
        for(int i=0; i<ports.length; i++){
            a[i] = ports[i].getSystemPortName();
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item, a);
        conSpinner.setAdapter(adapter);

        final Button connectButton = (Button) findViewById(R.id.connect);
        connectButton.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                conn = new Conn(conSpinner.getSelectedItemPosition());
                Runnable run = new Runnable() {
                    public void run() {
                        conn.listen();
                    }
                };
                new Thread(run).start();
            }
        });

        final Button disconnectButton = (Button) findViewById(R.id.disconnect);
        disconnectButton.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                if (conn != null) {
                    conn.disconnect();
                }
            }
        });

        final Button up = (Button) findViewById(R.id.upButton);
        up.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                if (conn != null) {
                    conn.sendMsg("w");
                }
            }
        });
    }
}

【讨论】:

  • 非常感谢您抽出宝贵的时间,我的朋友。看完你的代码后,我现在明白你的意思了。我对拼写错误等进行了一些更正以使其可运行,但我仍然收到相同的错误...
  • 是的,我自己也发现了几个错别字 :) 你说它在 Eclipse 中运行良好,但是?
  • 嗨@cricket_007 你能帮我解决我的问题吗stackoverflow.com/questions/35230272/…谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-20
  • 1970-01-01
  • 2017-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多