2012-12-20 38 views
1

我想連接到一個終端模擬器使用android的庫,這將連接到串行設備,並應顯示我發送/接收的數據。我應該能夠通過終端下方的文本框發送數據,或者在兩種情況下輸入終端本身並敲擊鍵盤上的回車。Android屏幕沒有更新沒有用戶操作

當我將數據發送到我的命令答覆回來到一個方法從庫onDataReceived(int id, byte[] data)。每次收到數據時都會自動運行。我可以看到數據到達日誌。

我的問題是,每當數據來自串行設備背面的屏幕不更新,直到我要麼把文本框對焦,或按下鍵盤上的回車鍵。如何在收到任何內容時更新屏幕。我知道它正在接收數據,當我按下文本框或輸入按鈕時,將顯示接收到的所有數據。

這是當我收到的數據叫什麼,一個ByteArrayInputStream與新數據更新。 appendToEmulator直接寫入終端模擬器。 notifyUpdate讓仿真器知道屏幕已經改變。

public void onDataReceived(int id, byte[] data) 
{ 
    String str = new String(data); 
    Log.d(TAG, "in data received " + str); 
    ((MyBAIsWrapper)bis).renew(data); 

    mSession.appendToEmulator(data, 0, data.length); 
    mSession.notifyUpdate(); 
} 

這裏就是我送東西:

mEntry = (EditText) findViewById(R.id.term_entry); 
mEntry.setOnEditorActionListener(new TextView.OnEditorActionListener() { 

     @Override 
     public boolean onEditorAction(TextView v, int actionId, 
       KeyEvent event) { 

      /* Ignore enter-key-up events. */ 
      if (event != null && event.getAction() == KeyEvent.ACTION_UP) { 

       return false; 
      } 


      /* Don't try to send something if we are not connected yet. */ 
      TermSession session = mSession; 

      if (mSession == null) { 
      Log.d(TAG, "null session "); 
      return true; 

      } 

      Log.d(TAG, "in click event "); 
      Editable e = (Editable) v.getText(); 

      // call original sendData to send data over serial 
      String data = e.toString() + "\r\n"; 
      Log.d(TAG, "edittext data is " + data); 
      //overridden sendData 
      sendData(data.getBytes()); 

      // send data over serial using original sendData() method 
      mSelectedAdapter.sendData(data.getBytes()); 
      TextKeyListener.clear(e); 
      return true; 
     } 
    }); 

我能做些什麼,使實時畫面更新,而不僅僅是用戶操作更新?

編輯:我認爲無效()是我需要的,但它不工作。我在emulatorView上調用它。一個emulatorView顯示終端模擬器的屏幕,是從視圖繼承http://pastebin.com/MNJ0Zf8P

編輯庫類:所以整個視圖無效什麼也不做,但我注意到,當我無效mEmulatorView屏幕更新,當我打開它。也是第一次更新後,我可以點擊終端本身,它會更新。進一步的抽頭什麼都不做。非常奇怪,所以很明顯,它改變了行爲,但在我調用它時沒有自動執行任何操作。

編輯:處理程序如何工作並調用它沒有?

編輯,我的全部活動:

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.InputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.net.Socket; 
import java.util.ArrayList; 
import java.util.Arrays; 

import slickdevlabs.apps.usb2seriallib.AdapterConnectionListener; 
import slickdevlabs.apps.usb2seriallib.SlickUSB2Serial; 
import slickdevlabs.apps.usb2seriallib.USB2SerialAdapter; 
import slickdevlabs.apps.usb2seriallib.SlickUSB2Serial.BaudRate; 
import slickdevlabs.apps.usb2seriallib.SlickUSB2Serial.DataBits; 
import slickdevlabs.apps.usb2seriallib.SlickUSB2Serial.ParityOption; 
import slickdevlabs.apps.usb2seriallib.SlickUSB2Serial.StopBits; 
import slickdevlabs.apps.usb2seriallib.USB2SerialAdapter.DataListener; 

import android.app.Activity; 
import android.app.AlertDialog; 
import android.content.DialogInterface; 
import android.content.Intent; 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Message; 
import android.text.Editable; 
import android.text.method.TextKeyListener; 
import android.util.DisplayMetrics; 
import android.util.Log; 
import android.view.KeyEvent; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.Window; 
import android.widget.AdapterView; 
import android.widget.AdapterView.OnItemSelectedListener; 
import android.widget.ArrayAdapter; 
import android.widget.Button; 
import android.widget.EditText; 
import android.widget.Spinner; 
import android.widget.TextView; 
import android.widget.Toast; 

import jackpal.androidterm.emulatorview.EmulatorView; 
import jackpal.androidterm.emulatorview.TermSession; 

public class SerialTerminalActivity extends Activity implements 
    OnClickListener, OnItemSelectedListener, AdapterConnectionListener, 
    DataListener { 

private static final String TAG = "SerialTerminalActivity"; 
private EditText mEntry; 
private EmulatorView mEmulatorView; 
private TermSession mSession; 
private OutputStream bos; 
private InputStream bis; 
private InputStream in; 
private OutputStream out; 
private Spinner mBaudSpinner; 
private Spinner mDataSpinner; 
private Spinner mParitySpinner; 
private Spinner mStopSpinner; 
private Spinner mDeviceSpinner; 
private Button mConnect; 
private ArrayList<String> mDeviceOutputs; 
private ArrayList<USB2SerialAdapter> mDeviceAdapters; 
private ArrayAdapter<CharSequence> mDeviceSpinnerAdapter; 
private USB2SerialAdapter mSelectedAdapter; 
private TextView mCurrentSettings; 
boolean attached = false; 

private Button mUpdateSettings; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    setContentView(R.layout.activity_serial_terminal); 

    mConnect = (Button) findViewById(R.id.deviceConnect); 
    mConnect.setOnClickListener(this); 
    mUpdateSettings = (Button) findViewById(R.id.updateSettings); 
    mUpdateSettings.setOnClickListener(this); 

    mBaudSpinner = (Spinner) findViewById(R.id.baudSpinner); 
    ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
      this, android.R.layout.simple_spinner_item); 
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
    mBaudSpinner.setAdapter(adapter); 
    String[] tempArray = SlickUSB2Serial.BAUD_RATES; 
    for (int i = 0; i < tempArray.length; i++) { 
     adapter.add(tempArray[i]); 
    } 
    mBaudSpinner.setSelection(SlickUSB2Serial.BaudRate.BAUD_9600.ordinal()); 

    mDataSpinner = (Spinner) findViewById(R.id.dataSpinner); 
    adapter = new ArrayAdapter<CharSequence>(this, 
      android.R.layout.simple_spinner_item); 
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
    mDataSpinner.setAdapter(adapter); 
    tempArray = SlickUSB2Serial.DATA_BITS; 
    for (int i = 0; i < tempArray.length; i++) { 
     adapter.add(tempArray[i]); 

    } 
    mDataSpinner 
      .setSelection(SlickUSB2Serial.DataBits.DATA_8_BIT.ordinal()); 

    mParitySpinner = (Spinner) findViewById(R.id.paritySpinner); 
    adapter = new ArrayAdapter<CharSequence>(this, 
      android.R.layout.simple_spinner_item); 
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
    mParitySpinner.setAdapter(adapter); 
    tempArray = SlickUSB2Serial.PARITY_OPTIONS; 
    for (int i = 0; i < tempArray.length; i++) { 
     adapter.add(tempArray[i]); 

    } 
    mParitySpinner.setSelection(SlickUSB2Serial.ParityOption.PARITY_NONE 
      .ordinal()); 

    mStopSpinner = (Spinner) findViewById(R.id.stopSpinner); 
    adapter = new ArrayAdapter<CharSequence>(this, 
      android.R.layout.simple_spinner_item); 
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
    mStopSpinner.setAdapter(adapter); 
    tempArray = SlickUSB2Serial.STOP_BITS; 
    for (int i = 0; i < tempArray.length; i++) { 
     adapter.add(tempArray[i]); 

    } 
    mStopSpinner 
      .setSelection(SlickUSB2Serial.StopBits.STOP_1_BIT.ordinal()); 

    mDeviceAdapters = new ArrayList<USB2SerialAdapter>(); 
    mDeviceOutputs = new ArrayList<String>(); 

    mDeviceSpinner = (Spinner) findViewById(R.id.deviceSpinner); 
    mDeviceSpinnerAdapter = new ArrayAdapter<CharSequence>(this, 
      android.R.layout.simple_spinner_item); 
    mDeviceSpinnerAdapter 
      .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
    mDeviceSpinner.setAdapter(mDeviceSpinnerAdapter); 
    mDeviceSpinner.setOnItemSelectedListener(this); 

    mCurrentSettings = (TextView) findViewById(R.id.currentSettings); 

    SlickUSB2Serial.initialize(this); 

    /* 
    * Text entry box at the bottom of the activity. Note that you can also 
    * send input (whether from a hardware device or soft keyboard) directly 
    * to the EmulatorView. 
    */ 
    mEntry = (EditText) findViewById(R.id.term_entry); 
    mEntry.setOnEditorActionListener(new TextView.OnEditorActionListener() { 

     @Override 
     public boolean onEditorAction(TextView v, int actionId, 
       KeyEvent event) { 

      /* Ignore enter-key-up events. */ 
      if (event != null && event.getAction() == KeyEvent.ACTION_UP) { 

       return false; 
      } 


      /* Don't try to send something if we are not connected yet. */ 
      TermSession session = mSession; 

      if (mSession == null) { 
      Log.d(TAG, "null session "); 
      return true; 

      } 

      Log.d(TAG, "in click event "); 
      Editable e = (Editable) v.getText(); 

      // call original sendData to send data over serial 
      String data = e.toString() + "\r\n"; 
      Log.d(TAG, "edittext data is " + data); 
      //doLocalEcho(data.getBytes()); 
      sendData(data.getBytes()); 

      // send data over serial using original sendData() method 
      mSelectedAdapter.sendData(data.getBytes()); 

      /* Write to the terminal session. */ 
      session.write(e.toString()); 
      //Log.d(TAG, "edittext to string is " + editText.toString()); 
      session.write('\r'); 
      TextKeyListener.clear(e); 
      return true; 
     } 
    }); 

    /* 
    * Sends the content of the text entry box to the terminal, without 
    * sending a carriage return afterwards 
    */ 
    Button sendButton = (Button) findViewById(R.id.term_entry_send); 
    sendButton.setOnClickListener(new View.OnClickListener() { 

     @Override 
     public void onClick(View v) { 

      /* Don't try to send something if we are not connected yet. */ 
      TermSession session = mSession; 
      if (mSession == null) { 
       Log.d(TAG, "mSession == NULLLLLLLLLLLLL "); 
       return; 
      } 

      Editable editText = (Editable) mEntry.getText(); 
      session.write(editText.toString()); 
      Log.d(TAG, "edittext is " + editText.toString()); 
      TextKeyListener.clear(editText); 
      Log.d(TAG, "send pressed "); 
     } 
    }); 

    /** 
    * EmulatorView setup. 
    */ 

    /* emulatorView from xml. */ 
    EmulatorView view = (EmulatorView) findViewById(R.id.emulatorView); 
    mEmulatorView = view; 

    /* Let the EmulatorView know the screen's density. */ 
    DisplayMetrics metrics = new DisplayMetrics(); 
    getWindowManager().getDefaultDisplay().getMetrics(metrics); 
    view.setDensity(metrics); 

    /* Create a TermSession. */ 
    // TermSession session = mSession; 
    mSession = new TermSession(); 

    //byte[] a=new byte[]{1,1,1}; 
    byte[] a = new byte[]{'h','e', 'l', 'l', 'o'}; 
    byte[] b = new byte[4096]; 
    //bis = new ByteArrayInputStream(a); 
    bis = new MyBAIsWrapper(b); 
    bos = new ByteArrayOutputStream(); 
    mSession.write("testTWO"); 
    //bis = new ByteArrayInputStream(b); 
    mSession.setTermIn(bis); 
    mSession.setTermOut(bos); 
    //session.setTermIn(in); 
    //session.setTermOut(out); 

    mSession.write("testONE"); 


    /* Attach the TermSession to the EmulatorView. */ 
    mEmulatorView.attachSession(mSession); 

    //mSession = session; 
// mSession.write("abc"); 
    //session.write("test"); 
    try { 
     bos.write(b); 
     bos.flush(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    /* TODO Monday: ByteArrayInputStream() can only be used once. The data in it at creation is all that'll ever be in. 
    *    Find a way to update what bis is pointing to without breaking the bind that bis has to the terminal. 
    *    Recover from Saturday's hangover. 
    */ 


    /* 
    * That's all you have to do! The EmulatorView will call the attached 
    * TermSession's initializeEmulator() automatically, once it can 
    * calculate the appropriate screen size for the terminal emulator. 
    */ 

} 

public void sendData(byte[] data) { 
    String str = new String(data); 
    Log.d(TAG, "send data method value is: " + str); 

    // this should echo what I send to the terminal in the correct format 
    //bos = new ByteArrayOutputStream(data.length); 
    mSession.write(data, 0, data.length); 
    try { 
     bos.write(data); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
     Log.d(TAG, "EXCEPTION in data sent "); 
    } 
    // mSession.write(data, 0, data.length); 
    // mSession.write('\r'); 

} 

public void onDataReceived(int id, byte[] data) { 

    String str = new String(data); 
    Log.d(TAG, "in data received " + str); 
     ((MyBAIsWrapper)bis).renew(data); 

    mSession.appendToEmulator(data, 0, data.length); 
    mSession.notifyUpdate(); 
    //mEmulatorView.invalidate(); 
    mEmulatorView.postInvalidate(); 
    /* bis = new ByteArrayInputStream(data); 
    SerialTerminalActivity.this.runOnUiThread(new Runnable() { 
     public void run() { 

       serialSession(); 
     } 
     });*/ 

    //cast added to keep original code structure 
    //I recommend defining the bis attribute as the MyBAIsWrapper type in this case 
    // ((MyBAIsWrapper)bis).renew(data); 


    //mSession.write(data, 0, data.length); 
    //mSession.write('\r'); 

} 

public void serialSession() { 
    Log.d(TAG, "in serial session"); 
    mSession.setTermIn(bis); 
    mSession.setTermOut(bos); 
    /* Attach the TermSession to the EmulatorView. */ 
    mEmulatorView.attachSession(mSession); 
} 

@Override 
public void onItemSelected(AdapterView<?> parent, View view, int position, 
     long id) { 
    // TODO Auto-generated method stub 
    changeSelectedAdapter(mDeviceAdapters.get(position)); 
} 

@Override 
public void onNothingSelected(AdapterView<?> arg0) { 
    // TODO Auto-generated method stub 
} 

public void changeSelectedAdapter(USB2SerialAdapter adapter) { 
    Toast.makeText(this, "in changeselectedadapter", Toast.LENGTH_SHORT) 
      .show(); 
    // if(mSelectedAdapter!=null){ 
    // mDeviceOutputs.set(mDeviceSpinnerAdapter.getPosition(mSelectedAdapter.getDeviceId()+""),mReceiveBox.getText().toString()); 

    mSelectedAdapter = adapter; 
    mBaudSpinner.setSelection(adapter.getBaudRate().ordinal()); 
    mDataSpinner.setSelection(adapter.getDataBit().ordinal()); 
    mParitySpinner.setSelection(adapter.getParityOption().ordinal()); 
    mStopSpinner.setSelection(adapter.getStopBit().ordinal()); 

    updateCurrentSettingsText(); 

    // mReceiveBox.setText(mDeviceOutputs.get(mDeviceSpinner.getSelectedItemPosition())); 
    Toast.makeText(this, 
      "Adapter switched toooo: " + adapter.getDeviceId() + "!", 
      Toast.LENGTH_SHORT).show(); 
} 

@Override 
public void onAdapterConnected(USB2SerialAdapter adapter) { 
    adapter.setDataListener(this); 
    mDeviceAdapters.add(adapter); 
    mDeviceOutputs.add(""); 
    mDeviceSpinnerAdapter.add("" + adapter.getDeviceId()); 
    mDeviceSpinner.setSelection(mDeviceSpinnerAdapter.getCount() - 1); 

    Toast.makeText(this, 
      "Adapter: " + adapter.getDeviceId() + " Connected!", 
      Toast.LENGTH_SHORT).show(); 
    // Toast.makeText(this, "Baud: "+adapter.getBaudRate()+" Connected!", 
    // Toast.LENGTH_SHORT).show(); 
} 

@Override 
public void onAdapterConnectionError(int error, String msg) { 
    // TODO Auto-generated method stub 
    if (error == AdapterConnectionListener.ERROR_UNKNOWN_IDS) { 
     final AlertDialog dialog = new AlertDialog.Builder(this) 
       .setIcon(0) 
       .setTitle("Choose Adapter Type") 
       .setItems(new String[] { "Prolific", "FTDI" }, 
         new DialogInterface.OnClickListener() { 
          public void onClick(DialogInterface dialog, 
            int optionSelected) { 
           if (optionSelected == 0) { 
            SlickUSB2Serial 
              .connectProlific(SerialTerminalActivity.this); 
           } else { 
            SlickUSB2Serial 
              .connectFTDI(SerialTerminalActivity.this); 
           } 
          } 
         }).create(); 
     dialog.show(); 
     return; 
    } 
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); 
} 

public void onClick(View v) { 

    if (v == mConnect) { 
     SlickUSB2Serial.autoConnect(this); 
     if (mSelectedAdapter == null) { 
      Toast.makeText(this, "no adapters detected", Toast.LENGTH_SHORT) 
        .show(); 
      return; 
     } 
    } 

    else if (v == mUpdateSettings) { 
     if (mSelectedAdapter == null) { 
      return; 
     } 

     mSelectedAdapter.setCommSettings(BaudRate.values()[mBaudSpinner 
       .getSelectedItemPosition()], DataBits.values()[mDataSpinner 
       .getSelectedItemPosition()], 
       ParityOption.values()[mParitySpinner 
         .getSelectedItemPosition()], 
       StopBits.values()[mStopSpinner.getSelectedItemPosition()]); 

     updateCurrentSettingsText(); 
     Toast.makeText(this, "Updated Settings", Toast.LENGTH_SHORT).show(); 

    } 

} 

private void updateCurrentSettingsText() { 
    mCurrentSettings.setText("Current Settings Areeee: " 
      + mBaudSpinner.getSelectedItem().toString() + ", " 
      + mDataSpinner.getSelectedItem().toString() + ", " 
      + mParitySpinner.getSelectedItem().toString() + ", " 
      + mStopSpinner.getSelectedItem().toString()); 
} 



/* Echoes local input from the emulator back to the emulator screen. */ 
private void doLocalEcho(byte[] data) { 

     Log.d(TAG, "echoing " + 
       Arrays.toString(data) + " back to terminal"); 
    //I added mSession, is it right? 
    mSession.appendToEmulator(data, 0, data.length); 
    mSession.notifyUpdate(); 
} 



@Override 
protected void onResume() { 
    super.onResume(); 

    /* 
    * You should call this to let EmulatorView know that it's visible on 
    * screen. 
    */ 
    mEmulatorView.onResume(); 

    mEntry.requestFocus(); 
} 

@Override 
protected void onPause() { 
    /* 
    * You should call this to let EmulatorView know that it's no longer 
    * visible on screen. 
    */ 
    mEmulatorView.onPause(); 

    super.onPause(); 
} 

@Override 
protected void onDestroy() { 
    /** 
    * Finish the TermSession when we're destroyed. This will free 
    * resources, stop I/O threads, and close the I/O streams attached to 
    * the session. 
    * 
    * For the local session, closing the streams will kill the shell; for 
    * the Telnet session, it closes the network connection. 
    */ 
    if (mSession != null) { 
     mSession.finish(); 
    } 
    SlickUSB2Serial.cleanup(this); 
    super.onDestroy(); 
} 

} 

回答

0

我試圖處理程序和它的工作原理:

Handler viewHandler = new Handler(); 
Runnable updateView = new Runnable(){ 
    @Override 
    public void run(){ 
    mEmulatorView.invalidate(); 
    viewHandler.postDelayed(updateView, 10); 
    } 
}; 

然後調用viewHandler.post(updateView);onDataReceived()

此更新屏幕每隔10ms,和作品,除非我把終端成爲關注的焦點,也不會更新直到我點擊發送或打到editText字段,這是爲什麼?

此外,爲什麼處理程序工作,但在方法本身調用它不? 我從來沒有用過處理程序,所以我不確定。

2

您需要無效的觀點,當你想更新它。從UI線程,使用invalidate(),並從非UI線程使用postInvalidate()

+0

我該如何解決這個問題,使我的視圖是全局的?以某種方式將它傳遞到onDataReceived? – Paul

+0

我不知道你的應用程序是如何構建的 - 也許你可以在某處使用findViewById()函數。 – 1615903

+0

嗨,我現在編輯了整個活動的代碼。我試圖在mEmulatorView和postInvalidate無效,但他們都沒有做任何事情。也許這不是我應該運行的。我只是把類似mEmulatorView.invalidate();在onDataReceived中。 – Paul