1

Androidのライブラリを使用してターミナルエミュレータに接続しようとしています。これによりシリアルデバイスに接続され、送受信されたデータが表示されます。どちらの場合も、端末の下にあるテキストボックスを介して、または端末自体を入力してキーボードのEnterキーを押すことにより、接続を介してデータを送信できるはずです。

データを送信すると、コマンドへの応答がライブラリからメソッドに返されますonDataReceived(int id, byte[] data)。これは、データを取得するたびに自動的に実行されます。ログに到着したデータを確認できます。

私の問題は、シリアルデバイスからデータが返されるたびに、テキストボックスにフォーカスを合わせるか、キーボードのEnterボタンを押すまで画面が更新されないことです。何かを受け取ったときに画面を更新するにはどうすればよいですか。データを受信して​​いることはわかっています。テキストボックスまたはEnterボタンを押すと、受信したすべてのデータが表示されます。

これが私がデータを受け取ったときの呼び方です。aByteArrayInputStreamは新しいデータで更新されます。 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;
        }
    });

ユーザーの操作を更新するだけでなく、画面をリアルタイムで更新するにはどうすればよいですか?

編集:invalidate()は私が必要としているものだと思いますが、機能しません。私はそれを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();
}

}
4

2 に答える 2

2

ビューを更新するときは、ビューを無効にする必要があります。UIスレッドからはinvalidate()を使用し、非UIスレッドからはpostInvalidate()を使用します。

于 2012-12-20T10:52:58.523 に答える
0

ハンドラーを試しましたが、機能します。

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

その後、電話 viewHandler.post(updateView);をかけますonDataReceived()

これにより、画面が10ミリ秒ごとに更新され、機能します。端末にフォーカスを合わせない限り、送信を押すかeditTextフィールドを押すまで更新されません。これはなぜですか。

また、ハンドラーが機能したのに、メソッド自体でハンドラーを呼び出しても機能しないのはなぜですか?ハンドラーを実際に使用したことがないので、よくわかりません。

于 2012-12-20T16:30:57.607 に答える