激情六月丁香婷婷|亚洲色图AV二区|丝袜AV日韩AV|久草视频在线分类|伊人九九精品视频|国产精品一级电影|久草视频在线99|在线看的av网址|伊人99精品无码|午夜无码视频在线

高校合作1:010-59833514 ?咨詢電話:400-810-1418 服務(wù)與監(jiān)督電話:400-810-1418轉(zhuǎn)接2

android 游戲輔助開發(fā)(Android App開發(fā)基礎(chǔ)篇)

發(fā)布時(shí)間:2023-11-27 21:58:17 瀏覽量:144次

?Android App開發(fā)基礎(chǔ)篇

android 游戲輔助開發(fā)(Android App開發(fā)基礎(chǔ)篇)

前言:Android開發(fā)中可以使用Java API提供的Socket和ServerSocket類來實(shí)現(xiàn)Socket通信。但是,通過這兩個(gè)類實(shí)現(xiàn)的Socket通信是阻塞式的,當(dāng)程序執(zhí)行輸入/輸出操作后,在這些操作返回之前會一直阻塞線程。當(dāng)有大量任務(wù)需要處理時(shí),這種方式會降低性能。在Java中提供了另一種NIO API,可以實(shí)現(xiàn)非阻塞的Socket通信,該NIO API主要提供了以下兩種特殊類:Selector和SelectableChannel。

Selector是SelectableChannel對象的多路復(fù)用器,可以同時(shí)監(jiān)控多個(gè)SelectableChannel的IO狀況,是非阻塞IO的核心。所有希望采用非阻塞方式進(jìn)行通信的Channel都應(yīng)該注冊到Selector對象。可通過調(diào)用Selector類的靜態(tài)open()方法來創(chuàng)建Selector實(shí)例。一個(gè)Selector實(shí)例包含3個(gè)SelectionKey集合:

(1)所有SelectionKey集合:通過keys()方法返回,表示注冊在該Selector上的所有Channel。

(2)被選擇的SelectionKey集合:通過selectedKeys()返回,表示所有可通過select()方法監(jiān)測到、需要進(jìn)行IO處理的Channel。

(3)被取消的SelectionKey集合:表示所有被取消注冊關(guān)系的Channel,在下一次執(zhí)行select()方法時(shí),這些Channel對應(yīng)的SelectionKey會被徹底刪除。程序通常無需直接訪問該集合。

除了3個(gè)SelectionKey集合,Selector還提供了和select()相關(guān)的方法:

(1)int select():監(jiān)控所有注冊的Channel,當(dāng)有Channel需要處理IO操作時(shí),該方法返回,并將對應(yīng)的SelectionKey加入被選擇的SelectionKey集合中。該方法返回這些Channel的數(shù)量。

(2)int select(long timeout):可以設(shè)置超時(shí)時(shí)長的select()操作。

(3)int selectNow():執(zhí)行一個(gè)立即返回的select()操作,相對于無參數(shù)的select()方法,該方法不會阻塞線程。

(4)Selector wakeup():使一個(gè)還未返回的select()方法立即返回。

SelectableChannel代表了可以支持非阻塞IO操作的Channel對象,可以將其注冊到Selector上,這種注冊的關(guān)系由SelectionKey實(shí)例表示。Java中可以調(diào)用SelectableChannel實(shí)例的register()方法將其注冊到指定的Selector上。當(dāng)注冊到Selector中的Channel當(dāng)中有需要處理IO操作時(shí),可以調(diào)用Selector的select()方法獲取它們的數(shù)量,并通過selectedKeys()方法返回它們對應(yīng)的SelectionKey集合。通過這個(gè)集合,可以獲取所需要處理IO操作的SelectableChannel集。

SelectableChannel支持阻塞和非阻塞兩種模式,默認(rèn)是阻塞的,必須通過非阻塞模式才能實(shí)現(xiàn)非阻塞IO操作??梢酝ㄟ^以下兩個(gè)方法來設(shè)置和返回Channel的模式:

(1)SelectionKey configureBlocking(boolean block):設(shè)置是否采用阻塞模式

(2)boolean isBlocking():返回該Channel是否阻塞模式。

不同的SelectableChannel所支持的操作不一樣。在SelectableChannel中提供了如下方法來返回不同SelectableSocketChannel所支持的操作:

android 游戲輔助開發(fā)(Android App開發(fā)基礎(chǔ)篇)

int validOps():返回一個(gè)bit mask,表示這個(gè)Channel上支持的IO操作。

此外,SelectableChannel還提供了如下方法獲取它的注冊狀態(tài):

boolean isRegistered():返回該Channel是否已注冊在一個(gè)或多個(gè)Selector上。

selectionKey keyFor(Selector sel):返回該Channel和Selector之間的注冊關(guān)系,如不存在注冊關(guān)系,則返回null。

下面介紹兩種SelectableSocketChannel,分別是對應(yīng)于java.net.ServerSocket的ServerSocketChannel和對應(yīng)于java.net.Socket的SocketChannel。

ServerSocketChannel代表一個(gè)ServerSocket,提供了一個(gè)TCP協(xié)議的IO接口,對應(yīng)于java.net.ServerSocket,支持非阻塞模式。它只支持OP_ACCEPT操作。同時(shí),該類也提供了accept()方法,功能相當(dāng)于ServerSocket的accept()方法。

SocketChannel對應(yīng)于java.net.Socket,同樣提供一個(gè)TCP協(xié)議的IO接口,支持非阻塞模式。它支持OP_CONNECT、OP_READ和OP_WRITE操作。此外,該類還實(shí)現(xiàn)了ByteChannel接口、ScatteringByteChannel接口和GatheringByteChannel接口,可以直接通過SocketChannel來讀寫B(tài)yteBuffer對象。

服務(wù)器上所有的Channel都需要向Selector注冊,包括ServerSocketChannel和SocketChannel。該Selector負(fù)責(zé)監(jiān)控這些Channel的IO狀態(tài),當(dāng)有Channel需要IO操作時(shí),Selector的select()方法將會返回具有IO操作的Channel的數(shù)量。并且,可通過selectedKeys()方法獲取這些Channel對應(yīng)的SelectionKey集合,進(jìn)而獲取到具有IO操作的SelectableChannel集。下面以一個(gè)實(shí)例來說明Java中NIO Socket的使用。直接上代碼加注釋


public class NIOSocketServer implements ActionListener { private String ip = "192.168.1.132";  private Window mWindow;  private JButton mBtnSend;  private JButton mBtnSendAll;  private JTextField mTextFiled;  private JTextArea mTextArea;  private JButton mBtnClear;  // 用于檢測所有Channel狀態(tài)的Selector  private Selector mSelector = null;  // 定義實(shí)現(xiàn)編碼、解碼的字符集對象  private Charset mCharset = Charset.forName("UTF-8");  private SocketChannel mSocketChannel = null;  // private static ExecutorService mThreadPool;  // private static SocketRun mSocketRun;   public NIOSocketServer() { mWindow = new Window("服務(wù)端");  mBtnSend = mWindow.getSendButton();  mBtnSend.setName("發(fā)送");  mBtnSendAll = mWindow.getSendAllButton();  mBtnSendAll.setName("群發(fā)");  mBtnClear = mWindow.getClearButton();  mBtnClear.setName("clear");  mTextFiled = mWindow.getTextField();  mTextArea = mWindow.getJTextArea();  mBtnSend.addActionListener(this);  mBtnSendAll.addActionListener(this);  mBtnClear.addActionListener(this);  // mSocketRun = new SocketRun();  // mThreadPool = Executors.newCachedThreadPool();  } public static void main(String[] args) throws IOException { System.out.println("服務(wù)端已啟動...");  new NIOSocketServer().init();  } @Override public void actionPerformed(ActionEvent event) { JButton source = (JButton) event.getSource();  String name = source.getName();  if (mBtnSend.getName().equals(name)) { // 向單個(gè)客戶端發(fā)送消息  String content = mTextFiled.getText().toString();  if (mSocketChannel != null) { try { mSocketChannel.write(mCharset.encode(content));  } catch (IOException e) { e.printStackTrace();  } } } else if (mBtnSendAll.getName().equals(name)) { // 向所有客戶端發(fā)送消息  String content = mTextFiled.getText().toString();  sendToAll(content);  } else if (mBtnClear.getName().equals(name)) { mTextArea.setText("");  } } private void sendToAll(String message) { for (SelectionKey sk : mSelector.keys()) { Channel channel = sk.channel();  if (channel instanceof SocketChannel) { SocketChannel dest = (SocketChannel) channel;  if (dest.isOpen()) { try { dest.write(mCharset.encode(message));  } catch (IOException e) { e.printStackTrace();  } } } } } public void init() throws IOException { mSelector = Selector.open();  // 通過open方法打開一個(gè)未綁定的ServerSocketChannel實(shí)例  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  InetSocketAddress inetSocketAddress = new InetSocketAddress(ip, 30000);  // 將該ServerSocketChannel綁定到指定的IP地址  serverSocketChannel.socket().bind(inetSocketAddress);  // 設(shè)置ServerSocket以非阻塞方式工作  serverSocketChannel.configureBlocking(false);  // 將serverSocketChannel注冊到指定Selector對象  serverSocketChannel.register(mSelector, SelectionKey.OP_ACCEPT);  while (mSelector.select() > 0) { // 依次處理selector上的每個(gè)已選擇的SelectionKey  Set<SelectionKey> selectedKeys = mSelector.selectedKeys();  //這里必須用iterator,如果用for遍歷Set程序會報(bào)錯(cuò)  Iterator<SelectionKey> iterator = selectedKeys.iterator();  while (iterator.hasNext()) { SelectionKey sk = iterator.next();  // 從selector上的已選擇的SelectionKey集合中刪除正在處理的SelectionKey  iterator.remove();  // 如果sk對應(yīng)的通道包含客戶端的連接請求  if (sk.isAcceptable()) { // 調(diào)用accept方法接受連接,產(chǎn)生服務(wù)端對應(yīng)的SocketChannel  SocketChannel socketChannel = serverSocketChannel.accept();  mTextArea.append("客戶端接入,IP:"+socketChannel.getLocalAddress()+"\n");  // 設(shè)置采用非阻塞模式  socketChannel.configureBlocking(false);  mSocketChannel = socketChannel;  // 將該SocketChannel也注冊到selector  socketChannel.register(mSelector, SelectionKey.OP_READ);  // 將sk對應(yīng)的Channel設(shè)置成準(zhǔn)備接受其他請求  sk.interestOps(SelectionKey.OP_ACCEPT);   } // 如果sk對應(yīng)的通道有數(shù)據(jù)需要讀取  if (sk.isReadable()) { // 獲取該SelectionKey對應(yīng)的Channel,該Channel中有可讀的數(shù)據(jù)  SocketChannel socketChannel = (SocketChannel) sk.channel();  mSocketChannel = socketChannel;  // 定義準(zhǔn)備執(zhí)行讀取數(shù)據(jù)的ByteBuffer  ByteBuffer buffer = ByteBuffer.allocate(1024);  String content = "";  // 開始讀取數(shù)據(jù)  try { while (socketChannel.read(buffer) > 0) { buffer.flip();  content += mCharset.decode(buffer);  } if ("shutdown".equals(content)) { sk.cancel();  if (sk.channel() != null) { sk.channel().close();  } sendToAll("reconnect");  } else { // 打印從該sk對應(yīng)的Channel里讀取到的數(shù)據(jù)  mTextArea.append("來自客戶端的消息:" + content + "\n");  // 將sk對應(yīng)的Channel設(shè)置成準(zhǔn)備下一次讀取  sk.interestOps(SelectionKey.OP_READ);  } } // 如果捕捉到該sk對應(yīng)的Channel出現(xiàn)了異常,即表明該Channel  // 對應(yīng)的Client出現(xiàn)了問題,所以從Selector中取消sk的注冊  catch (IOException ex) { // 從Selector中刪除指定的SelectionKey  sk.cancel();  if (sk.channel() != null) { sk.channel().close();  } sendToAll("reconnect");  } } } } } } 


Server端創(chuàng)建GUI界面輔助測試的Window類

public class Window extends JFrame {

   /**
    * 窗口類 定義客戶端和服務(wù)器端的窗口
    */
   private static final long serialVersionUID = 2L;
   private String windowName;
   private JFrame myWindow;
   private JTextArea area;
   private JTextField field;
   private JButton btnSend;
   private JButton btnSendAll;
   private JButton btnClear;

   public Window(String windowName) {
      this.windowName = windowName;
      myWindow = new JFrame(windowName);
      myWindow.setLayout(new FlowLayout());
      myWindow.setSize(new Dimension(600, 300));
      // 不能改變窗口大小
      myWindow.setResizable(false);

      area = new JTextArea();
      field = new JTextField();
      btnSend = new JButton("發(fā)送");
      btnSendAll = new JButton("群發(fā)");
      btnClear = new JButton("clear");

      // 設(shè)置field的大小
      field.setPreferredSize(new Dimension(300, 30));
      myWindow.add(field);
      myWindow.add(btnSend);
      myWindow.add(btnSendAll);
      myWindow.add(btnClear);
      myWindow.add(area);
      // 改變area的大小
      area.setPreferredSize(new Dimension(470, 210));
      area.setBackground(Color.PINK);
      area.setEditable(false);
      // 設(shè)置窗口顯示在電腦屏幕的某區(qū)域
      myWindow.setLocation(400, 200);

      myWindow.setVisible(true);
      // 點(diǎn)擊關(guān)閉按鈕時(shí)觸發(fā)該方法
      closeMyWindow();
   }

   /**
    * 方法名:closeMyWindow()
    * 
    * @param
    * @return 功能:當(dāng)用戶點(diǎn)擊關(guān)閉按鈕時(shí),退出并且關(guān)閉該窗口
    */
   private void closeMyWindow() {
      myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   }

   /**
    * 方法名:getFieldText()
    * 
    * @param
    * @return string 功能:獲取窗口的TextField中的字符串
    */
   public String getFieldText() {
      return field.getText().toString();
   }

   /**
    * 方法名:getSendButton()
    * 
    * @param
    * @return JButton 功能:獲得該窗口中的按鈕
    */
   public JButton getSendButton() {
      return btnSend;
   }

   /**
    * 方法名:getSendAllButton()
    * 
    * @param
    * @return JButton 功能:獲得該窗口中的按鈕
    */
   public JButton getSendAllButton() {
      return btnSendAll;
   }

   /**
    * 方法名:getClearButton()
    * 
    * @param
    * @return JButton 功能:獲得該窗口中的按鈕
    */
   public JButton getClearButton() {
      return btnClear;
   }

   /**
    * 方法名:getJTextArea()
    * 
    * @param
    * @return JTextArea 功能:返回窗口中的JTextArea
    */
   public JTextArea getJTextArea() {
      return area;
   }

   /**
    * 方法名:getTextField()
    * 
    * @param
    * @return JTextField 功能:獲得窗口中的textfield
    */
   public JTextField getTextField() {
      return field;
   }
}


MainActivity代碼:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "MainActivity";
    private String ip = "192.168.1.132";
    private TextView contentTv;
    // 定義檢測SocketChannel的Selector對象
    private Selector mSelector;
    // 客戶端SocketChannel
    private SocketChannel mSocketChannel;
    // 定義處理編碼、解碼的字符集
    private Charset mCharset = Charset.forName("UTF-8");
    private String mData = "";
    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message message) {
            switch (message.what) {
                case 0:
                    contentTv.append("連接成功...\n");
                    break;
                case 1:
                    contentTv.append("來自服務(wù)端端:" + mData + "\n");
                    break;
            }
            return false;
        }
    });
    private EditText mContentEt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        contentTv = (TextView) findViewById(R.id.content_tv);
        mContentEt = (EditText) findViewById(R.id.content_et);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_conn:
                //Android里面網(wǎng)絡(luò)操作不能放在UI線程,
                // 所以開啟一個(gè)線程來測試
                new connectThread().start();
                break;
            case R.id.btn_send:
                new sendMsgThread().start();
                break;
        }
    }

    private class sendMsgThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                mSocketChannel.write(mCharset.encode(mContentEt.getText().toString()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private class connectThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                mSelector = Selector.open();
                InetSocketAddress inetSocketAddress = new InetSocketAddress(ip, 30000);
                // 調(diào)用open方法創(chuàng)建連接到指定主機(jī)的SocketChannel
                mSocketChannel = SocketChannel.open(inetSocketAddress);
                mHandler.sendEmptyMessage(0);
                // 設(shè)置該SocketChannel以非阻塞方式工作
                mSocketChannel.configureBlocking(false);
                // 將該SocketChannle對象注冊到指定的Selector
                mSocketChannel.register(mSelector, SelectionKey.OP_READ);
                // 讀取服務(wù)端消息
                while (mSelector != null && mSelector.select() > 0) {
                    Set<SelectionKey> selectionKeys = mSelector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey sk = iterator.next();
                        iterator.remove();
                        if (sk != null && sk.isReadable()) {
                            mSocketChannel = (SocketChannel) sk.channel();
                            ByteBuffer buff = ByteBuffer.allocate(1024);
                            String data = "";
                            while (mSocketChannel.read(buff) > 0) {
                                mSocketChannel.read(buff);
                                buff.flip();
                                data += mCharset.decode(buff);
                                buff.clear();
                            }
                            Log.e(TAG, "run: data:" + data);
                            mData = data;
                            mHandler.sendEmptyMessage(1);
                            sk.interestOps(SelectionKey.OP_READ);
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG, "run: e:" + e.getMessage());
            }
        }
    }
}
activity_main.xml代碼
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.niosocketdemo.MainActivity">


    <Button
        android:id="@+id/btn_conn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="連接" />

    <Button
        android:id="@+id/btn_send"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="發(fā)送消息" />

    <EditText
        android:id="@+id/content_et"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入要發(fā)送的消息" />

    <TextView
        android:id="@+id/content_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="消息:\n" />
</LinearLayout>




android 游戲輔助開發(fā)(Android App開發(fā)基礎(chǔ)篇)

熱門課程推薦

熱門資訊

請綁定手機(jī)號

x

同學(xué)您好!

您已成功報(bào)名0元試學(xué)活動,老師會在第一時(shí)間與您取得聯(lián)系,請保持電話暢通!
確定