마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

여러 액티비티에서 시리얼 통신,유지를 하려고 합니다.

0 추천

 

 

참고사이트: 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 같이 시리얼포트액티비티를 상속받은

하위 액티비티의 생명주기에 따라 시리얼통신이 연결/해제 되는것 같은데요..

어떻게 하면 각 액티비티가 아닌, 앱 자체가 켜지고-꺼지기 전까지 이 시리얼통신을 유지할 수 있을까요?

구조를 바꾸고 싶은데 어떤 부분을 고쳐야 할지 조언 좀 주시면 감사하겠습니다 ㅠ

 

 

질문 님이 2018년 1월 10일 질문
2018년 1월 10일 수정

1개의 답변

0 추천

android-serialport-api 코드를 보니...

1. SerialPort instance는 Application class instance에 기반하여 singleton으로 하나만 존재하기
   때문에 SerialPortActivity를 상속하여 여러개의 Activity를 구동하면 당연히 정상 동작할 수가
   없습니다.

2. 가장 쉬운 접근 방법은 SerialPortActivity를 하나만 사용하여 구현하는 것이고,
   꼭 Activity간 이동이 필요하다면, SerialPort관련 로직은 Service 컴포넌트로 옮겨
   수행하는 것이 맞습니다.

디자이너정 (42,810 포인트) 님이 2018년 1월 10일 답변
디자이너정님이 2018년 1월 10일 수정
디자이너 정님, 답변 감사드립니다.
activity간의 이동을 구현한 이유는 아래와 같습니다.
1.각 activity마다 출력하는 ui가 다릅니다.
2.activity 마다 보내는 커맨드값이 다르고, 받는값에 따라 레이아웃을 변화시키는등 처리할 사항이 다릅니다.
말씀해주신대로 최상위 액티비티 A 하나만 SerialPortActivity를 extends하고,
나머지 B,C,D등이 A를 extends 상속하려고 합니다. 이런식으로 처리해도 될련지요? 명령값을 받을 때도 A의 onDataReceived를 통해 서브 액티비티 BCD등으로 보내서 처리한다던지요..[프래그먼트 형식도 생각해봤습니다..] 서비스컴포넌트로도 구현히 가능하다면 공부해서 해볼텐데 지금 시간이 촉박한지라 전자의 방식을 사용할까 생각중입니다.
...