在这种情况下,我有2个活动。我正在使用活动1并转到活动2.应用程序按预期工作。
当我回到活动1并再次启动活动2时,问题就开始了。
见下面的代码:
public class ScreenWActivity extends SerialComActivity {
private static final String tag = "ScreenWActivity";
private TextView mReception, m_tvDate, mtvPesoPercent, mtvState;
public String mCommand = null;
public int mActualProcess, mNextProcess;
private Commands mLastCommand;
public SettingsGlobal mSettings;
public int mAttempts = 0;
public long mStartTime, mTimeout;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_W);
this.mSettings = new SettingsGlobal(this); // get global settings
this.mtvState = (TextView) findViewById(R.id.tv_state); // label to update the current state
startSerialConnection(); // open serial port and start connection. inherited from SerialComActivity (the upper class)
this.mTimeout = 10; // timeout for commands response in seconds
this.mNextProcess = 1; // the next step in the process, its updated in the stepN() methods
this.mActualProcess = 1; // current step in the processo
this.mLastCommand = Commands.OPEN_DOOR; // the last command I've sent, to know what to expect in return
this.executeWorkflow(mNextProcess); // starts the workflow
}
private void step1(){
this.mtvState.setText("Closing door."); // update status
this.writeSerial(Commands.OPEN_DOOR.command("080").getBytes()); // sends the command to the outputstream, the external device reads the command, execute it and respond back
this.mNextProcess = 2; // the next step in the process is 2
this.mActualProcess = 1; // just tracking
this.mLastCommand = Commands.OPEN_DOOR;
startCounting(); // starts the timout, I've sent the command, now I wait for an answer
}
private void step2(){
this.mtvState.setText("Testando peso das balanças 1.");
this.writeSerial(Commands.GET_W.command().getBytes()); // get weight from weighing-machine
mLastCommand = Commands.GET_W; // the last command i sent i requested the weight - now I know what to expect
mNextProcess = 3; // next step in the sequence in case everything goes according to plan
this.mActualProcess = 2; // tracking
startCounting(); // starting timeout to get an answer
}
private void step3(){...}
private void step4(){...}
private void step5(){...}
private void step6(){...}
@Override
protected void writeSerial(byte[] buffer){...}
public void startCounting(){
mStartTime = System.currentTimeMillis();
timerHandler.postDelayed(timerRunnable, 0);
}
public void stopCounting(){
timerHandler.removeCallbacks(timerRunnable);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
stopCounting();
timerRunnable = null;
if(this.mSerialPort != null)
this.mSerialPort.close();
this.mSerialPort = null;
if(AppConfig.DEBUG) Log.i(tag, "finishing!");
finish();
super.onDestroy();
}
public void executeWorkflow(int step) {
switch(step){
case 1:
step1();
break;
case 2:
step2();
break;
case 3:
step3();
break;
case 4:
step4();
break;
case 5:
step5();
break;
case 6:
step6();
break;
}
}
protected boolean validateReturn(String resposta) {
/// we check the command we've sent and the response we're given. if it matches, then we return true, else false
}
// overrided from SerialComActivity, called when the external equipment sends a message to us
// ITS CALLED WHEN THERE IS INPUT FROM THE EXTERNAL EQUIPMENT
@Override
protected void onDataReceived(final byte[] buffer, final int size) {
runOnUiThread(new Runnable() {
public void run() {
stopCounting(); // we remove the callbacks from the timeout thread
if( validateReturn(new String(buffer, 0, size).trim()) ){ // we check if the response is good
executeWorkflow(mNextProcess); // if its good, we move to the next step
}else{
mtvState.setText("invalid return"); // if not we message the user
executeWorkflow(mActualProcess); // we try again
}
}
});
}
// RESPONSIBLE FOR THE TIMEOUT
// the code below was created intending to implement a timeout timer for waiting a response from the external device
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
@Override
public void run() {
long millis = System.currentTimeMillis() - mStartTime;
long seconds = (millis / 1000);
timerHandler.postDelayed(this, 500);
if(mTimeout - seconds == 0 ){
mAttempts += 1;
if(mAttempts == 3){ // we make 3 attempts to get a response, if it is the third, we quit trying and give error
mAttempts = 0;
mtvState.setText("Could not communicate.");
stopCounting(); // we end the timer
}else{
executeWorkflow(mActualProcess); // if we can still try, we send the command again
}
}
}
};
}
在方法onDataReceived()
内部,每当我从外部设备得到响应时调用,我使用属性mLastCommand
(表示我发送的最后一个命令),所以这样我知道如何验证我得到的反应。
当我回到活动2时,在类范围中,属性的值与我在onCreate()
方法中定义的值相同。在LogCat中,我看到属性值已正确定义,如OnCreate中所述。
但是,当调用方法onDataReceived
(它在SerialComActivity
类中的一个线程内)时(当我从外部获取数据时调用它),该相同属性的值{{1}与我第一次启动活动时相同,不管我为它定义的值。好像第一次进入活动时mLastCommand
内的runnable仍然保持旧值,并且在其外部,类具有我定义的值。
这就像在RunOnUiThread
中有两个具有相同名称的不同属性。
我尝试将ScreenWActivity
方法中的属性归零,但无济于事。
以下是onDestroy()
类的代码:
SerialComActivity
我还在学习Java和Android编程,所以如果我做错了,请原谅我。我抬头看了看,你不能在RunOnUiThred中使用除“final”之外的变量的东西出现了。但我认为这不是问题,因为它是我第一次开始活动时的工作。
答案 0 :(得分:0)
尝试在onPause()
而不是onDestroy()
进行清理,onDestroy()
可能不会立即调用,这意味着SerialPort
上可能存在读取冲突。此外,如果您已经在onDestroy()
,则调用finish()
并没有真正做任何事情。
最后,对于像SerialPort
连接这样的有限资源,最好将它放在Service
中。
答案 1 :(得分:0)
我是Java的新手,但我想我发现了发生了什么。问题是我提出了错误的问题。
问题出在mInputStream.read()
。正如我所知,这是一个阻止操作。我正在创建一个在read()
方法中保持阻塞的线程。完成Activity
后,(返回第一个),线程继续运行。我知道,因为当通过串行接口发送一些信息时,该线程会响应。
所以我做了什么,并且它对我有用,尽管很多人都说这种方法不建议使用mInputStream.available()
:
try {
if (mInputStream == null){ Log.i(tag,"returning"); return null ;}
Log.i(tag,"reading");
mEmptyStream = true;
while(mEmptyStream && !mFinish){
Log.i(tag,"input while");
/// checking if there is info, so we don't block the thread
if(mInputStream.available() > 0){
Log.i(tag,"input avail : " + InputStream.available());
//stream not empty
mEmptyStream = false;
size = mInputStream.read(buffer); //
}
}
if (size > 0) {
Log.i(tag,"size > 0 = " + new String(buffer, 0, size));
return new String(buffer,0,size);
}else{
Log.i(tag,"size <= 0");
}
}
基本上我使用available()
循环。当我完成活动时,在onPause()
方法中,我将字段mFinish
设置为true,这样线程就会发现它已经不再执行,并且可以正常结束。这是我发现的方式,到目前为止它的工作方式。我在原始帖子之后显着改进了代码,就像在RunOnUiThread中没有运行非UI作业一样:)
但我测试了它并且它正在工作。