編輯:關於Android編程
2、通過url打開網絡連接(連接方式有http連接,ftp連接,https連接,rtsp連接) 此處獲取網絡連接用到的是http連接,所以使打開一個HttpURLConnection
HttpURLConnection openConnection = (HttpConnection)url.openConnection(); openConnection.setRequestMethod("GET");//設置請求方式 openConnection.setConnectTimeout(5000);//設置請求超時時間
3、打開連接後就可以獲取網絡返回的數據(例)
String contentType = openConnection.getContentType();//獲取返回的數據類型 Object content = openConnection.getContent();//獲取放回的數據 int code = openConnection.getResponseCode();//獲取響應碼,200--返回正確,404--資源沒找到,503--服務器內部錯誤 ......4、獲取輸入流,保存返回的數據
InputStream inputStream = openConnection.getInputStream();5、根據資源類型將網絡資源轉換成相應的資源,如是圖片資源,則如下轉換
Bitmap decodeStream = BitmapFactory.decodeStream(inputStream);6、訪問網絡需要添加網絡權限 7、一個常用的參數:User-Agent,我們可以通過這個參數來獲取這個資源的來源信息,如某個網站,iphone6 plus等 例:
openConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64;Trident/4.0;SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; InfoPath.2");8、網絡路徑中不能包含中文,如果在路徑中需要涉及到中文,需要使用將中文使用URLEncoder對中文進行編碼
URLEncoder.encode("中文",utf-8);二、使用smartImageView加載網絡圖片 smartImageView繼承自ImageView,具有ImageView的所有功能,同時擴展了ImageVIew的功能,如常用的方法setImageUrl(URL url),這個方法可以通過直接傳遞圖片的URL地址來給smartImageView控件設置圖片。 smartIamgeView使用異步加載的方式從網絡獲取網絡圖片,加載過程在子線程中執行,在使用時只需要傳遞圖片的路徑即可,不需要在子線程訪問網絡和加載的問題。
public class MainActivity extends Activity { String path = "http://f.hiphotos.baidu.com/image/pic/item/a8014c086e061d9507500dd67ff40ad163d9cacd.jpg"; private SmartImageView smiv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button bt = (Button) findViewById(R.id.bt); smiv = (SmartImageView) findViewById(R.id.smiv); } public void click(View v){ smiv.setImageUrl(path); } }
三、使用Get請求方式請求網絡 模擬QQ登錄
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //01010101 String qq = request.getParameter("qq");//采用的編碼是iso-8859-1 String pwd = request.getParameter("pwd"); System.out.println("qq:"+new String(qq.getBytes("iso-8859-1"),"utf-8")); System.out.println("pwd:"+new String(pwd.getBytes("iso-8859-1"),"utf-8")); //查詢數據庫 看qq和密碼是否存在 if("10000".equals(qq)&&"abcde".equals(pwd)){ //tomcat容器如果發現字符串不識別就默認采用本地碼表 response.getOutputStream().write("登陸成功".getBytes("utf-8")); }else{ response.getOutputStream().write("登陸失敗".getBytes("utf-8")); } }服務器端會通過HttpServletRequestrequestgetParameter()方法獲取到用戶請求網絡的參數,如用戶名和密碼。用戶發送請求時,輸入的請求參數都會展示在地址欄,即地址欄的所有的參數就是服務器端要獲取到的所有參數。在發送請求時,只需要在請求地址後面加上相應的參數就能發送get請求,如www.qq.com/web/LogingServlet?qq=10000&pwd=abcde
2、客戶端在發送get請求時,需要將請求的參數傳遞到URL中,然後在發送請求。如:
//獲取請求的參數 final String qq = et_qq.getText().toString().trim(); final String pwd = et_pwd.getText().toString().trim(); //將參數添加到請求地址中 String path = "http://192.168.1.103:8080/web/LoginServlet?qq="+URLEncoder.encode(qq, "utf-8")+"&pwd="+URLEncoder.encode(pwd, "utf-8");3、get請求的優缺點
優點:使用方便,只需要的地址後面組拼請求參數即可發送請求
缺點:(1)請求參數在地址欄都能展示出來,不安全;
(2)數據的長度有限制
四、使用post請求方式發送網絡請求 1、post請求方式的優缺點 優點:安全,數據不是在url後面組拼,而是通過流的形式寫給服務器;數據的長度沒有限制 缺點:編寫麻煩 2、post請求和get請求的區別 (1)get請求需要在URL後面組拼提交的數據,post請求不需要組拼任何數據 (2)post請求必須要指定請求提交的數據長度(如下圖,post請求比get請求多了Content-Type請求頭) (3)post請求是以流的方式吧數據寫給服務器,所有的http請求頭必須要告訴服務器寫多長的數據(如下圖,post請求比get請求多了Content-Length請求頭) 3、服務端代碼示例
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("post過來的請求"); doGet(req, resp); }4、示例代碼
五、使用HTTPClient發送網絡請求 1、發送get請求URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //1.設置請求方式為POST conn.setRequestMethod("POST"); //注意單詞必須大寫. conn.setConnectTimeout(5000); //2.設置http請求數據的類型為表單類型 conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //3.設置給服務器寫的數據的長度 //qq=10000&pwd=abcde String data = "qq="+URLEncoder.encode(qq, "utf-8")+"&pwd="+URLEncoder.encode(pwd, "utf-8"); conn.setRequestProperty("Content-Length", String.valueOf(data.length())); //4.記得指定要給服務器寫數據 conn.setDoOutput(true); //5.開始向服務器寫數據 conn.getOutputStream().write(data.getBytes());
String path = "http://192.168.1.103:8080/web/LoginServlet?qq="+URLEncoder.encode(qq, "utf-8")+"&pwd="+URLEncoder.encode(pwd, "utf-8"); HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(path); HttpResponse response = client.execute(httpGet); //獲取狀態碼 int code = response.getStatusLine().getStatusCode(); if(code == 200){ InputStream is = response.getEntity().getContent(); String result = StreamTools.readStream(is); Message msg = Message.obtain(); msg.what = SUCCESS; msg.obj = result; handler.sendMessage(msg); }else{ Message msg = Message.obtain(); msg.what = ERROR; handler.sendMessage(msg); }
String path = "http://192.168.1.103:8080/web/LoginServlet"; HttpClient client = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(path); Listparameters = new ArrayList (); parameters.add(new BasicNameValuePair("qq", qq)); parameters.add(new BasicNameValuePair("pwd", pwd)); httpPost.setEntity(new UrlEncodedFormEntity(parameters, "utf-8")); HttpResponse response = client.execute(httpPost); //獲取狀態碼 int code = response.getStatusLine().getStatusCode(); if(code == 200){ InputStream is = response.getEntity().getContent(); String result = StreamTools.readStream(is); Message msg = Message.obtain(); msg.what = SUCCESS; msg.obj = result; handler.sendMessage(msg); }else{ Message msg = Message.obtain(); msg.what = ERROR; handler.sendMessage(msg); }
StreamTools.readStream()
public class StreamTools { /** * 工具方法 * @param is 輸入流 * @return 文本字符串 * @throws Exception */ public static String readStream(InputStream is) throws Exception{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while((len = is.read(buffer))!=-1){ baos.write(buffer, 0, len); } is.close(); String temp = baos.toString(); return temp; } }六、使用過異步網絡加載框架AsyncHttpClient請求網絡 1、AsyncHttpClient進一步對HttpClient進行了封裝,這個框架考慮到了子線程問題,我們在使用時就不用再創建子線程,直接使用估計可,同時框架中還使用了線程池,使加載效率更高。 2、發送get請求
String path = "http://192.168.1.103:8080/web/LoginServlet?qq="+URLEncoder.encode(qq)+"&pwd="+URLEncoder.encode(pwd); AsyncHttpClient client = new AsyncHttpClient(); client.get(path, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { tv_status.setText(new String(responseBody)); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { tv_status.setText("http請求失敗"+new String(responseBody)); } });3、發送post請求
String path = "http://192.168.1.103:8080/web/LoginServlet"; AsyncHttpClient client = new AsyncHttpClient(); RequestParams params = new RequestParams(); params.put("qq", qq); params.put("pwd", pwd); client.post(path, params, new AsyncHttpResponseHandler(){ @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { tv_status.setText("登陸結果:"+new String(responseBody)); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { tv_status.setText("請求失敗請檢查網絡"); } });
1.簡介
Android中網絡請求一般使用Apache HTTP Client或者采用HttpURLConnect,但是直接使用這兩個類庫需要寫大量的代碼才能完成網絡post和get請求,而使用android-async-http這個庫可以大大的簡化操作,它是基於Apache’s HttpClient ,所有的請求都是獨立在UI主線程之外,通過回調方法處理請求結果,采用android Handlermessage 機制傳遞信息。public void upload(View view){ String path = et_path.getText().toString().trim(); File file = new File(path); if(file.exists()&&file.length()>0){ //上傳 AsyncHttpClient client = new AsyncHttpClient(); RequestParams params = new RequestParams(); try { params.put("file", file); } catch (FileNotFoundException e) { e.printStackTrace(); } client.post("http://192.168.1.103:8080/web/UploadServlet", params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { Toast.makeText(MainActivity.this, "上傳成功", 0).show(); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { Toast.makeText(MainActivity.this, "上傳失敗", 0).show(); } }); }else{ Toast.makeText(this, "請檢查文件是否存在", 0).show(); } }
八、使用HttpUtils加載網絡 1、發送get請求
HttpUtils http = new HttpUtils(); http.send(HttpRequest.HttpMethod.GET, "http://www.lidroid.com", new RequestCallBack2、下載 支持斷點續傳,隨時停止下載任務,開始任務(){ @Override public void onLoading(long total, long current, boolean isUploading) { testTextView.setText(current + "/" + total); } @Override public void onSuccess(ResponseInfo responseInfo) { textView.setText(responseInfo.result); } @Override public void onStart() { } @Override public void onFailure(HttpException error, String msg) { } });
HttpUtils http = new HttpUtils(); HttpHandler handler = http.download("http://apache.dataguru.cn/httpcomponents/httpclient/source/httpcomponents-client-4.2.5-src.zip", "/sdcard/httpcomponents-client-4.2.5-src.zip", true, // 如果目標文件存在,接著未完成的部分繼續下載。服務器不支持RANGE時將從新下載。 true, // 如果從請求返回信息中獲取到文件名,下載完成後自動重命名。 new RequestCallBack() { @Override public void onStart() { testTextView.setText("conn..."); } @Override public void onLoading(long total, long current, boolean isUploading) { testTextView.setText(current + "/" + total); } @Override public void onSuccess(ResponseInfo responseInfo) { testTextView.setText("downloaded:" + responseInfo.result.getPath()); } @Override public void onFailure(HttpException error, String msg) { testTextView.setText(msg); } });
Range表示范圍,後面的字符串為范圍值(8)使用隨機文件訪問流的seek(intindex)方法設置每個線程下載文件後在本地文件中寫入的起始位置
(9)將獲取到的數據寫入到本地文件中
public void download(View view) { path = et_path.getText().toString().trim(); if (TextUtils.isEmpty(path) || (!path.startsWith("http://"))) { Toast.makeText(this, "對不起路徑不合法", 0).show(); return; } new Thread(){ public void run() { try { //1、連接網絡 URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); if (code == 200) { //2、使用getContentLength()方法獲取網絡文件的大小 int length = conn.getContentLength(); System.out.println("服務器文件的長度為:" + length); //3、使用RandomAccessFile在本地創建一個空文件 RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+getFileName(path), "rw"); //4、將空文件的大小設置為與網絡文件大小相同 raf.setLength(length); raf.close(); //5、設置將文件劃分的塊數,threadCount--線程數 int blocksize = length / threadCount; runningThreadCount = threadCount; //6、設置每個線程下載的文件區域 for (int threadId = 0; threadId < threadCount; threadId++) { int startIndex = threadId * blocksize; int endIndex = (threadId + 1) * blocksize - 1; if (threadId == (threadCount - 1)) { endIndex = length - 1; } new DownloadThread(threadId, startIndex, endIndex).start(); } } } catch (Exception e) { e.printStackTrace(); } }; }.start(); }
//創建線程下載文件 private class DownloadThread extends Thread { /** * 線程id */ private int threadId; /** * 線程下載的理論開始位置 */ private int startIndex; /** * 線程下載的結束位置 */ private int endIndex; /** * 當前線程下載到文件的那一個位置了. */ private int currentPosition; public DownloadThread(int threadId, int startIndex, int endIndex) { this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; System.out.println(threadId + "號線程下載的范圍為:" + startIndex + " ~~ " + endIndex); currentPosition = startIndex; } @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //檢查當前線程是否已經下載過一部分的數據了 File info = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+threadId+".position"); RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+getFileName(path), "rw"); if(info.exists()&&info.length()>0){ FileInputStream fis = new FileInputStream(info); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); currentPosition = Integer.valueOf(br.readLine()); conn.setRequestProperty("Range", "bytes="+currentPosition+"-"+endIndex); System.out.println("原來有下載進度,從上一次終止的位置繼續下載"+"bytes="+currentPosition+"-"+endIndex); fis.close(); raf.seek(currentPosition);//每個線程寫文件的開始位置都是不一樣的. }else{ //告訴服務器 只想下載資源的一部分 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); System.out.println("原來沒有有下載進度,新的下載"+ "bytes="+startIndex+"-"+endIndex); raf.seek(startIndex);//每個線程寫文件的開始位置都是不一樣的. } InputStream is = conn.getInputStream(); byte[] buffer = new byte[1024]; int len = -1; while((len = is.read(buffer))!=-1){ //把每個線程下載的數據放在自己的空間裡面. // System.out.println("線程:"+threadId+"正在下載:"+new String(buffer)); raf.write(buffer,0, len); currentPosition+=len; File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+threadId+".position"); RandomAccessFile fos = new RandomAccessFile(file,"rwd"); //System.out.println("線程:"+threadId+"寫到了"+currentPosition); fos.write(String.valueOf(currentPosition).getBytes()); fos.close();//fileoutstream數據是不一定被寫入到底層設備裡面的,有可能是存儲在緩存裡面. //raf 的 rwd模式,數據是立刻被存儲到底層硬盤設備裡面. int max = endIndex - startIndex; int progress = currentPosition - startIndex; if(threadId==0){ pb0.setMax(max); pb0.setProgress(progress); }else if(threadId==1){ pb1.setMax(max); pb1.setProgress(progress); }else if(threadId==2){ pb2.setMax(max); pb2.setProgress(progress); } } raf.close(); is.close(); System.out.println("線程:"+threadId+"下載完畢了..."); File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+threadId+".position"); f.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+threadId+".position.finish")); synchronized (MainActivity.class) { runningThreadCount--; if(runningThreadCount<=0){ for(int i=0;i /** * 獲取一個文件名稱 * @param path * @return */ public String getFileName(String path){ int start = path.lastIndexOf("/")+1; return path.substring(start); }
一.問題引入ListView控件:給Item綁定了點擊事件,卻點擊無效。二.解決方案ListView使用了自定義布局文件,在布局文件中有button等控件時,這些控件獲取
在Google發布了support:design:23+以後我們發現有這麼一個東西TextInputLayout,先看下效果圖:<android.support.d
本篇博客主要講解怎樣自定義一個circleIndicator控件?下一遍博客主要講解怎樣更改ViewPager切換的效果, 預計明天晚上之前更新。效果圖如下1)首先我們先
ProgressDialog類似於ProgressBar類。用於顯示一個過程,通常用於耗時操作。 幾個方法介紹:1.setMax()設置對話框中進度條的最大值。