
참고사이트: https://github.com/cepr/android-serialport-api
안녕하세요. 위와같이 a,b,c 등등[그외의 액티비티들도 있습니다.]
액티비티들을 구성해서 버튼을 누르면 다른 startActivity로 이동합니다.
현재 console,console2 액티비티 두개만 가지고 테스트를 하고 있는데요,
이 두 액티비티가 extends하고 있는 SerialPortActivity 구조가 궁금합니다;
설명하자면 아래와 같습니다.
1.console,console2 두 액티비티는 SerialPortActivity를 상속받는다.
2.두 액티비티는 공통적으로 onCreate에서 4byte의 값을 보낸다.[시리얼통신]
3.console하나만 놓고 말씀드리자면 콘솔액티비티가 시작할 때 시리얼포트액티비티가 시작되고
[onCreate], 종료될 때도 시리얼포트 액티비티가 같이 종료됩니다[onDestroy]
4.console onCreate에서 4byte를 보내고,console액티비티 안에 선언된 onDataReceived에서
onDataReceived
에서 값을 받았습니다. 그다음에 버튼을 눌러 console2 액티비티로 이동 후,
여기서도 onCreate에서 4byte를 보내는데
onDataReceived
,console액티비티 안에 선언된 onDataReceived와 console2에 선언된 onDataReceived에서 받은값이
섞여서 출력됩니다; 그리고 바로 시리얼포트액티비티가 닫히구요. 그뒤로 read/write먹통이 됩니다.
상위 액티비티라 앱자체가 종료되기 전까지 시리얼포트액티비티가 종료가 안될거라 생각했는데,
아래의 서브 액티비티들이 종료될 때마다 SeiralPortActivity도 종료가 됩니다.
그래서 console2 에서 시리얼통신을 하려고 할 때 포트가 닫혔다고 에러가 발생합니다.
에러내용 : java.io.IOException: write failed: EBADF (Bad file descriptor)
혹시 몰라서 소스도 같이 첨부합니다..콘솔,콘솔2 액티비티는 구조가 같아서 콘솔액티비티만 올립니다.
public class ConsoleActivity extends SerialPortActivity implements OnClickListener{
byte[] mBuffer;
Button btn_console;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.console);
btn_console = (Button)findViewById(R.id.btn_console);
btn_console.setOnClickListener(this);
mBuffer = new byte[4];
mBuffer[0] = (byte)0x02;
mBuffer[1] = (byte)0x30;
mBuffer[2] = (byte)0x32;
mBuffer[3] = (byte)0x0a;
if (mSerialPort != null)
{
try
{
Log.e("mBuffer size",""+mBuffer.length);
mOutputStream.write(mBuffer);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
@Override
protected void onDataReceived(final byte[] buffer, final int size) {
runOnUiThread(new Runnable() {
public void run()
{
String buffersArrayString = byteArrayToHex(buffer);
Log.e("값받음,콘솔액티비티 :",buffersArrayString+"");
}
});
}
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.btn_console:
Intent intent = new Intent(ConsoleActivity.this, ConsoleActivity2.class);
startActivity(intent);
finish();
break;
}
}
}
다음은 시리얼포트 액티비티입니다.
public abstract class SerialPortActivity extends Activity {
protected Application mApplication;
protected SerialPort mSerialPort;
protected OutputStream mOutputStream;
private InputStream mInputStream;
private ReadThread mReadThread;
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
while(!isInterrupted()) {
int size;
try {
byte[] buffer = new byte[1];
if (mInputStream == null) return;
size = mInputStream.read(buffer);
if (size > 0)
{
Log.e("data receive....","data receiver...");
onDataReceived(buffer, size);
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
private void DisplayError(int resourceId) {
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setTitle("Error");
b.setMessage(resourceId);
b.setPositiveButton("OK", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
SerialPortActivity.this.finish();
}
});
b.show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApplication = (Application) getApplication();
try {
Log.e("시리얼포트 액티비티 onCreate","시리얼포트 액티비티 onCreate");
mSerialPort = mApplication.getSerialPort();
mOutputStream = mSerialPort.getOutputStream();
mInputStream = mSerialPort.getInputStream();
/* Create a receiving thread */
mReadThread = new ReadThread();
mReadThread.start();
} catch (SecurityException e) {
DisplayError(R.string.error_security);
} catch (IOException e) {
DisplayError(R.string.error_unknown);
} catch (InvalidParameterException e) {
DisplayError(R.string.error_configuration);
}
}
protected abstract void onDataReceived(final byte[] buffer, final int size);
@Override
protected void onDestroy()
{
Log.e("시리얼포트 액티비티 destroy","시리얼포트 액티비티 destory");
if (mReadThread != null)
mReadThread.interrupt();
mApplication.closeSerialPort();
mSerialPort = null;
super.onDestroy();
}
}
다음은 어플리케이션 클래스 입니다.
public class Application extends android.app.Application
{
public SerialPortFinder mSerialPortFinder = new SerialPortFinder();
private SerialPort mSerialPort = null;
public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {
if (mSerialPort == null)
{
//직접지정
String path = "/dev/ttyS0";
int baudrate = 9600;
/* Check parameters */
if ( (path.length() == 0) || (baudrate == -1)) {
throw new InvalidParameterException();
}
/* Open the serial port */
mSerialPort = new SerialPort(new File(path), baudrate, 0);
}
return mSerialPort;
}
public void closeSerialPort() {
if (mSerialPort != null) {
mSerialPort.close();
mSerialPort = null;
}
}
}
아직 모르는 것이 많아..이런 앱 구조는 처음봅니다.
참고로 시리얼포트 액티비티에서 선언된 protected Application mApplication; 는
Application 클래스를 의미하는것 같습니다,.[누르니 이동]
public class Application extends android.app.Application {...중간생략
이런 구조이고, 매니페스트에서도 어플리케이션 속성에서
android:name="Application" 와 같이 지정합니다.
아직 소스를 제대로 파악못했지만, 제 생각엔 콘솔,콘솔2 같이 시리얼포트액티비티를 상속받은
하위 액티비티의 생명주기에 따라 시리얼통신이 연결/해제 되는것 같은데요..
어떻게 하면 각 액티비티가 아닌, 앱 자체가 켜지고-꺼지기 전까지 이 시리얼통신을 유지할 수 있을까요?
구조를 바꾸고 싶은데 어떤 부분을 고쳐야 할지 조언 좀 주시면 감사하겠습니다 ㅠ