美文网首页
Android网络通信

Android网络通信

作者: 云承寒 | 来源:发表于2017-07-17 23:55 被阅读0次

    Android4.0后,规定耗时操作(网络连接,大数据操作)不能在主线程中运行,应放置到子线程,否则会产生Anr(应用无响应)异常。

    Android同样规定,UI 操作只能在主线程中进行,这就需要在获取请求后要通知主线程进行 UI 修改。

    Android提供通知主线程的方式
    
    1.Context提供的方法
    new Thread(new Runnable() {
          @Override
          public void run() {
    
            runOnUiThread(new Runnable() {
               @Override
                public void run() {
    
               }
          });
       }
    }).start();
    
    
    2.使用Handler通知
    private Handler mHandler = new Handler(){
          @Override
          public void handleMessage(Message msg) {
                
          }
    };
    

    下面通过简单的登录案例,来了解通信流程。
    服务端
    @WebServlet(value = "/login")
    public class LoginServlet extends HttpServlet {
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
    
            req.setCharacterEncoding("UTF-8");
            resp.setContentType("text/html;charset=UTF-8");
    
            String userName = req.getParameter("userName");
            String userPwd = req.getParameter("userPwd");
    
            if (userName.equals("admin") && userPwd.equals("123"))
                resp.getWriter().print("登录成功");
            else
                resp.getWriter().print("登录失败");
        }
    }
    
    Android端,Get方式
    添加网络权限
    <uses-permission android:name="android.permission.INTERNET" />
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "MainActivity";
    
        private EditText mEtUserName, mEtUserPwd;
        private Button mBtnLogin;
        private Context mContext;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initView();
            initEvent();
        }
    
        private void getLogin() {
            try {
                HttpURLConnection conn = (HttpURLConnection)
                        new URL(getRequestUrl()).openConnection();
    
                conn.setReadTimeout(3 * 1000);
                conn.setRequestMethod("GET");
    
                //Android HttpURLConnection 的输出流开关默认是关闭的
                conn.setDoInput(true);
                conn.setDoOutput(true);
    
                if (conn.getResponseCode() == 200) {
                    InputStream is = conn.getInputStream();
                    BufferedReader br = new BufferedReader(new InputStreamReader(is));
                    final String result = br.readLine();
    
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
                        }
                    });
    
                } else {
                    Log.i(TAG, "Request fail");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private void initEvent() {
            mBtnLogin.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            getLogin();
                        }
                    }).start();
                }
            });
        }
    
        private void initView() {
            mEtUserName = findViewById(R.id.et_user_name);
            mEtUserPwd = findViewById(R.id.et_user_pwd);
            mBtnLogin = findViewById(R.id.btn_login);
            mContext = this;
        }
    
        private String getRequestUrl() {
            return "http://192.168.0.105:8080/login?userName="
                    + getUserName() +
                    "&userPwd="
                    + getUserPwd();
        }
    
        private String getUserName() {
            return mEtUserName.getText().toString().trim();
        }
    
        private String getUserPwd() {
            return mEtUserPwd.getText().toString().trim();
        }
    }
    
    
    Post方式
    差别在于参数的传递
    
    private String getRequestUrl() {
          return "http://192.168.0.105:8080/login";
    }
    
    private void getLogin() {
            try {
                HttpURLConnection conn = (HttpURLConnection)
                        new URL(getRequestUrl()).openConnection();
    
                conn.setReadTimeout(3 * 1000);
                conn.setRequestMethod("POST");
    
                conn.setDoInput(true);
                conn.setDoOutput(true);
    
                //写入参数
                String requestParameter = "userName=" +
                        getUserName() +
                        "&userPwd=" +
                        getUserPwd();
                conn.getOutputStream().write(requestParameter.getBytes());
    
                if (conn.getResponseCode() == 200) {
                    InputStream is = conn.getInputStream();
                    BufferedReader br = new BufferedReader(new InputStreamReader(is));
                    final String result = br.readLine();
    
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
                        }
                    });
    
                } else {
                    Log.i(TAG, "Request fail");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    Handler

    Handler是Android提供的一套异步消息处理机制,当子线程处理完数据后,通知主线程更新UI。

    Handler组成
    Message,Handler,MessageQueue,Looper
    
    1.Message 
    用来在线程间传递消息,并且可以携带数据,在不同线程间进行交换。
    
    2.Handler
    用于发送和处理消息
    
    3.MessageQueue
    消息队列,用于存放所有通过Handler发送的消息。
    这部分消息会一直存在消息队列中,等待处理。
    每个线程只会有一个MessageQueue对象。
    
    4.Looper
    Looper是每个线程中的MessageQueue的管家。
    Looper调用loop()后,会进入无限循环。
    然后每当发现MessageQueue中存在一条消息,就将它取出,并传递到Handler的handlerMessage()中。
    每个线程也只有一个Looper对象。
    
    private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 201:
                        String result = (String) msg.obj;
                        Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
                        break;
                }
            }
    };
    
     private void getLogin() {
            try {
                HttpURLConnection conn = (HttpURLConnection)
                        new URL(getRequestUrl()).openConnection();
    
                conn.setReadTimeout(3 * 1000);
                conn.setRequestMethod("POST");
    
                conn.setDoInput(true);
                conn.setDoOutput(true);
    
                //写入参数
                String requestParameter = "userName=" +
                        getUserName() +
                        "&userPwd=" +
                        getUserPwd();
                conn.getOutputStream().write(requestParameter.getBytes());
    
                if (conn.getResponseCode() == 200) {
                    InputStream is = conn.getInputStream();
                    BufferedReader br = new BufferedReader(new InputStreamReader(is));
                    final String result = br.readLine();
    
                    //消息通知
                    Message message = Message.obtain();
                    message.what = 201;
                    message.obj = result;
                    mHandler.sendMessage(message);
    
                } else {
                    Log.i(TAG, "Request fail");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    获取图片的案例
    服务端
    将图片放在Tomcat,Root文件夹下。
    新建文本文档,存放图片的路径。
    
    Android端
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private Button mBtnPre, mBtnNext;
        private ImageView mIvShowImg;
    
        private ArrayList<String> mImgUrlList;
        private String mImgUrls = "http://192.168.0.105:8080/img/imgUrl.txt";
    
        private int mCurImgIndex;
    
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                Bitmap bitmap = (Bitmap) msg.obj;
                mIvShowImg.setImageBitmap(bitmap);
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initView();
            initData();
        }
    
        private void initData() {
            mImgUrlList = new ArrayList<>();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    getImgUrls();
                    getImg(0);
                }
            }).start();
        }
    
        //读取图片路径,放入集合
        private void getImgUrls() {
            InputStream is = getUrlResource(mImgUrls);
            if (is != null) {
                try {
                    BufferedReader br = new BufferedReader(new InputStreamReader(is));
                    String len;
                    while ((len = br.readLine()) != null) {
                        mImgUrlList.add(len);
                    }
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        //根据图片路径,获取图片
        private void getImg(int index) {
            String imgUrl = mImgUrlList.get(index);
            String imgName = getImgName(imgUrl);
    
            //判断图片是否已缓存,若已缓存,则不从服务器读取
            File goalImg = new File(getFilesDir(), imgName);
            if (goalImg.exists() && goalImg.length() > 0) {
                Bitmap bitmap = BitmapFactory.decodeFile(goalImg.getAbsolutePath());
                Message message = Message.obtain();
                message.obj = bitmap;
                mHandler.sendMessage(message);
                return;
            }
    
            InputStream is = getUrlResource(imgUrl);
            try {
                if (is != null) {
                    Bitmap bitmap = BitmapFactory.decodeStream(is);
    
                    //将图片缓存到本地,
                    //参数:图片类型,图片缓存的质量 0~100,图片写入
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100,
                            openFileOutput(imgName, MODE_PRIVATE));
    
                    Message message = Message.obtain();
                    message.obj = bitmap;
                    mHandler.sendMessage(message);
                    is.close();
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private void initView() {
            mBtnPre = findViewById(R.id.btn_pre);
            mBtnNext = findViewById(R.id.btn_next);
            mIvShowImg = findViewById(R.id.iv_show_img);
            mBtnPre.setOnClickListener(this);
            mBtnNext.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_pre:
                    mCurImgIndex--;
                    if (mCurImgIndex < 0) {
                        mCurImgIndex = mImgUrlList.size() - 1;
                    }
    
                    showImg();
                    break;
                case R.id.btn_next:
                    mCurImgIndex++;
                    if (mCurImgIndex > mImgUrlList.size() - 1) {
                        mCurImgIndex = 0;
                    }
    
                    showImg();
                    break;
            }
        }
    
        //获取服务器上的资源
        private InputStream getUrlResource(String path) {
            try {
                HttpURLConnection conn = (HttpURLConnection)
                        new URL(path).openConnection();
    
                if (conn.getResponseCode() == 200) {
                    return conn.getInputStream();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private String getImgName(String path) {
            return path.substring(path.lastIndexOf("/") + 1);
        }
    
        private void showImg() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    getImg(mCurImgIndex);
                }
            }).start();
        }
    }
    

    相关文章

      网友评论

          本文标题:Android网络通信

          本文链接:https://www.haomeiwen.com/subject/nccckxtx.html