java - Android 屏幕在没有用户操作的情况下不会更新

标签 java android android-edittext inputstream outputstream

我正在尝试使用 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;
        }
    });

我该怎么做才能使屏幕实时更新,而不仅仅是根据用户操作进行更新?

编辑:我认为 invalidate() 是我需要的,但它不起作用。我在 emulatorView 上调用它。 emulatorView 显示终端仿真器的屏幕,是库中继承自 View 的类 http://pastebin.com/MNJ0Zf8P

编辑:所以使整个 View 无效没有任何作用,但我注意到当我使 mEmulatorView 无效时,当我解锁它时屏幕会更新。也是更新后的第一次,我可以点击终端本身,它就会更新。进一步的水龙头什么都不做。非常奇怪,所以它显然正在改变行为,但在我调用它时并没有自动执行任何操作。

编辑:为什么处理程序可以工作而调用它却没有?

编辑,我的全部 Activity :

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();
}

}

最佳答案

当你想更新它时,你需要使 View 失效。在 UI 线程中,使用 invalidate() , 从非 UI 线程使用 postInvalidate() .

关于java - Android 屏幕在没有用户操作的情况下不会更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13970312/

相关文章:

android - 无法在 ListView 项目中正确选择文本

java - 如何使用 TextWatcher Android 添加 3 位小数货币格式到 edittext

java - 使用java代码创建Neo4j节点

java - Eclipse Juno - 为什么对未使用的带注释的私有(private)字段没有警告?

android - Activity noHistory ="true"在屏幕锁定时不起作用

java - 需要 SQLite 查询帮助

android - 为什么点击 Android 中的 Toggle 按钮时,光标总是跳到 EditText 的开头?

java - beans xml 配置中带有 <set> 标记的列表的行为与 Set 相同

java - Solrj Hello World -/solr/update 未找到

android - 如何在android中使用volley下载视频文件?