2012-12-20 37 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