如果我完成一个活动并再次调用它,它的属性值仍然保留在线程内(RunOnUiThread)

时间:2013-12-06 01:20:26

标签: android

在这种情况下,我有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”之外的变量的东西出现了。但我认为这不是问题,因为它是我第一次开始活动时的工作。

2 个答案:

答案 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作业一样:) 但我测试了它并且它正在工作。