編輯:關於Android編程
網頁源碼查看器案例實現在EditText中輸入網址,點擊按鈕獲取,獲取到網頁源碼,顯示在TextView上。
在IE浏覽器中,快捷鍵Shift+F12可以調出httpwatch。用來查看發送請求的一些信息。
案例效果圖:
使用api:HttpURLConnection ,用於發送或接收數據。
由於是網絡請求,所以需要加入聯網權限:
源碼查看器實現邏輯:
new Thread() { public void run() { try { //獲取EditText中輸入的網址路徑 String path = et_path.getText().toString().trim(); //創建URL對象,參數傳入我們需要訪問的網址路徑 URL url = new URL(path); //通過URL的openConnection()方法獲取一個HttpURLConnection對象,用來發送和接收網絡數據; HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //設置發送的請求方式,GET要大寫,固定寫法 conn.setRequestMethod("GET"); //設置請求超時時間為5000ms就是5s conn.setConnectTimeout(5000); //獲取服務器返回的狀態碼,200代表請求資源成功(206代表請求部分資源成功) int code = conn.getResponseCode(); if (code == 200) { //調用HttpURLConnection的getInputStream()方法獲取服務器返回的流對象 InputStream in = conn.getInputStream(); //StreamTools中的readStream方法,把InputStream轉換成一個String String content = StreamTools.readStream(in); tv_reuslt.setText(content); } } catch (Exception e) { e.printStackTrace(); } }; }.start();
StreamTools工具類,實現將輸入流轉換成String:
public static String readStream(InputStream in) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len = -1; byte[] buffer = new byte[1024]; // 1kb while ((len = in.read(buffer)) != -1) { baos.write(buffer, 0, len); } in.close(); String content = new String(baos.toByteArray()); return content; }
運行效果:
ScrollView控件能夠滾動,只能包裹一個子布局。注意:ScrollView控件中只能有一個根布局。
(1) ANR 即Application Not Response,表示應用無響應,這裡指的是主線程(UI線程)無響應;
(2) 如果在主線程中進行了耗時的操作(比如連接網絡,拷貝大數據,調用Thread.sleep()方法)就會發生ANR異常;
(3) 避免ANR,可以把耗時操作放到子線程。
(4) 在4.0之後谷歌強制要求連接網絡不能在主線程中進行訪問。如果在主線程中連接網絡會發生如下錯誤,錯誤日志如下:
09-26 01:49:03.818: W/System.err(1638):android.os.NetworkOnMainThreadException
(5) 只有在主線程(UI線程)才可以更新UI,在子線程更新UI會發生以下錯誤,錯誤日志如下:
09-26 01:51:50.050: W/System.err(1708):android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
(6) 消息機制可以用來處理這種更新UI的情況。
(1) 在主線程定義一個Handler
private Handler handler = new Handle();
(2) 重寫handler裡面的handlemessage方法
public void handleMessage(android.os.Message msg) {}
(3) 用我們在主線程創建的handler 去子線程發消息
handler.sendMessage(msg);
(4) 當sendMessage(mgs)方法執行後,handlemessage方法就會執行,在這個方法裡面更新UI
首先在主線程中創建Handler對象實例:
//創建Handler對象 private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { //msg.what是用戶自定義的消息碼 switch (msg.what) { case REQUESTSUCESS: //msg.obj是message攜帶的數據 String content = (String) msg.obj; tv_reuslt.setText(content); break; case REQUESTNOTFOUND: Toast.makeText(getApplicationContext(), "請求資源不存在",0).show(); break; case REQUESTEXCEPTION: Toast.makeText(getApplicationContext(), "服務器忙 請稍後....",1).show(); break; default: break; } }; };
在子線程中調用sendMessage方法:
new Thread(){ @Override public void run() { //創建消息對象 Message msg = new Message(); //設置自定義的消息碼 msg.what = REQUESTSUCESS; //將數據添加到消息對象中 msg.obj = content; //發送消息,調用該方法後,會調用Handler的handleMessage方法 handler.sendMessage(msg); } };
1.Message
Message是在線程之間傳遞的消息,它可以在內部攜帶少量的信息what字段,用於在不同線程之間交換數據。除此之外還可以使用arg1和arg2字段來攜帶一些整型數據,使用obj字段攜帶一個Object對象。
2.Handler
Handler顧名思義也就是處理者的意思,它主要是用於發送和處理消息的。發送消息一般是使用Handler的sendMessage()方法,而發出的消息經過一系列地輾轉處理後,最終會傳遞到Handler的handleMessage()方法中。
3.MessageQueue<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjwvYmxvY2txdW90ZT4NCjxwPk1lc3NhZ2VRdWV1ZcrHz/vPorbTwdC1xNLiy7yjrMv81vfSqtPD09q05rfFy/nT0M2ouf1IYW5kbGVyt6LLzbXEz/vPoqGj1eKyv7fWz/vPorvh0rvWsbTm1NrT2s/7z6K208HQ1tCjrLXItP2xu7SmwO2ho8O/uPbP37PM1tDWu7vh09DSu7j2TWVzc2FnZVF1ZXVlttTP86GjPC9wPg0KPGJsb2NrcXVvdGU+DQoJPHA+NC5Mb29wZXI8L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cD5Mb29wZXLKx8O/uPbP37PM1tC1xE1lc3NhZ2VRdWV1ZbXEudy80qOstffTw0xvb3BlcrXEbG9vcCgpt723qLrzo6y+zbvhvfjI67W90ru49s7ez97Rrbu3tbHW0KOsyLu688O/tbG3os/WTWVzc2FnZVF1ZXVl1tC05tTa0rvM9c/7z6KjrL7Nu+G9q8v8yKGz9qOssqK0q7Xdtb1IYW5kbGVytcRoYW5kbGVNZXNzYWdlKCm3vbeo1tCho8O/uPbP37PM1tDSsta7u+HT0NK7uPZMb29wZXK21M/zoaM8L3A+DQo8cD48c3Ryb25nPjxlbT655tTyOiCyu7ncxOPKssO0sOaxvrXEyta7+iDWu9Kq1/a6xMqxtcSy2df3KLHIyOfBrL3TzfjC5yCxyMjnv72xtLTztcTK/b7dILXItcgpIL7N19S8ur+q0ru49tfTz9+zzKOsu/HIocr9vt2688/r0qq4/NDCdWkgvs3KudPDSGFuZGxlcr7Nv8nS1MHLoaM8L2VtPjwvc3Ryb25nPjwvcD4NCjxoMSBpZD0="6-圖片查看器">6. 圖片查看器
本案例實現在EditText中輸入圖片地址,點擊獲取,通過網絡請求獲取到圖片數據,將圖片數據轉換成Bitmap對象,最終在下方的ImageView中顯示。
圖片查看器開發步驟:
(1)網絡請求獲取服務器資源;
(2)把流信息轉換成bitmap對象;
(2)BitmapFactory.decodeStream(inputStream in)換成Bitmap對象
(3)記得加上網絡訪問權限
(4)對圖片進行緩存
定義Handler處理更新UI:private Handler hander = new Hander(){ public void handlerMessage(Message msg){ Bitmapbitmap = (Bitmap)msg.obj; iv_img.setImageBitmap(bitmap); } };獲取網絡圖片:
public void click(View v) { new Thread() { public void run() { String path = et_path.getText().toString().trim(); try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); int code = conn.getResponseCode(); if (code == 200) { InputStream inputStream = conn.getInputStream(); //利用BitmapFactory.decodeStream()方法將流轉換成Bitmap對象 final Bitmap bitmap = BitmapFactory.decodeStream(inputStream); //Message.obtain();該方法返回一個消息對象,如果有消息就復用消息池裡的消息,如果沒有消息就創建一個新的消息 Message msg = Message.obtain(); //msg.obg可以攜帶參數 msg.obj = bitmap; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); } }; }.start(); }7. cache和files目錄
cache和files目錄會生成在應用程序包名目錄下,如下圖:
生成cache目錄:public void click1(View v) { try { File file = new File(getCacheDir(), "info.txt"); FileOutputStream fos = new FileOutputStream(file); fos.write("hhehe".getBytes()); fos.close(); } catch (Exception e) { e.printStackTrace(); } }成一個files目錄:
public void click2(View v) { try { FileOutputStream fos = openFileOutput("info.txt", 0); fos.write("haha".getBytes()); fos.close(); } catch (Exception e) { e.printStackTrace(); } }應用管理界面,清除緩存cache會被清除,files文件夾不會刪除,如果清除數據,都會被清除。
一般做緩存數據,我們用cache目錄,但是如果是重要的數據可以放到files目錄。8. runOnUiThread()使用
runOnUiThread(),顧名思義就是運行在UI線程,也就是主線程。
new Thread() { public void run() { try { // Thread.sleep(100); tv.setText("哈哈 我更新了ui"); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start();以上代碼在子線程中直接更新UI,運行時並不會報錯,但是如果將第4行代碼注釋打開繼續運行,程序會運行報錯。原因是,並不是在子線程當中不能更新UI,而是Android系統底層有一個審計機制,當阻塞達到一定時間,就不能更新UI。
(1) 如果僅僅就是更新UI,那麼我們可以用runOnUiThread(),當中的代碼都會在主線程中執行。
(2) 當我們需要傳遞參數的時候,這時候就需要使用handler來實現runOnUiThread(new Runnable() { public void run() { iv.setImageBitmap(cacheBitmap); } });9. Handler常用的api
postDelayed();應用場景:手機應用打開Splash頁面,過3秒跳轉到主頁面。
new Handler().postDelayed(new Runnable() { @Override public void run() { tv.setText("哈哈哈哈哈 "); } }, 5000);類似於定時器Timer類:
private Timer timer; private TimerTask task; //創建timer實例 timer = new Timer(); //創建任務實例,run方法是在子線程運行 task = new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { public void run() { tv.setText("呵呵呵呵 "); } }); } }; //調用timer.schedule()執行任務,參數1是任務對象,參數2是過多長時間開始執行任務,參數3是間隔多長時間執行一次任務 timer.schedule(task, 3000,1000);取消任務:
timer.cancel(); task.cancel();10. 新聞客戶端案例
本案例,實現網易新聞客戶端頁面ListView展示復雜子條目。
10.1. 服務器准備
在服務器tomcat目錄下有一個news.xml文件,文件內容就是服務器返回來的新聞數據,如下圖:
注意點:
(1) 啟動tomcat服務器一閃而過,需要配置JAVA_HOME
(2) 圖片訪問地址必須是電腦的ip地址,不能是localhost,因為手機訪問localhost是訪問手機本機的地址,而不是訪問電腦服務器的地址。10.2. 創建界面
界面只有一個ListView用來展示新聞條目:
子條目布局:
10.3. 准備ListView顯示的數據
從服務器獲取,將獲取到的數據封裝到javabean,存入集合中。
首先定義新聞實體類News:public class News { private String title; private String description; private String image; private String type; private String comment; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } }從服務器獲取數據:
private void initListData() { new Thread() { public void run() { try { String path = "http://192.168.11.86:8080/news.xml"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); int code = conn.getResponseCode(); if (code == 200) { InputStream in = conn.getInputStream(); //XmlParserUtils.parseXml()方法是用來解析服務器獲取到的數據 newsLists = XmlParserUtils.parserXml(in); System.out.println("newsLists:"+newsLists.size()); runOnUiThread(new Runnable() { public void run() { //lv.setAdapter()方法需要在主線程中執行,不然會報錯 lv.setAdapter(new MyAdapter()); } }); } } catch (Exception e) { e.printStackTrace(); } }; }.start(); }下面解析從服務器獲取的數據:
public static ListparserXml(InputStream in) throws Exception { List newsLists = null; News news = null; XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, "utf-8"); int type = parser.getEventType(); while (type != XmlPullParser.END_DOCUMENT) { switch (type) { case XmlPullParser.START_TAG: if ("channel".equals(parser.getName())) { newsLists = new ArrayList (); } else if ("item".equals(parser.getName())) { news = new News(); } else if ("title".equals(parser.getName())) { news.setTitle(parser.nextText()); } else if ("description".equals(parser.getName())) { news.setDescription(parser.nextText()); } else if ("image".equals(parser.getName())) { news.setImage(parser.nextText()); } else if ("type".equals(parser.getName())) { news.setType(parser.nextText()); } else if ("comment".equals(parser.getName())) { news.setComment(parser.nextText()); } break; case XmlPullParser.END_TAG: if ("item".equals(parser.getName())) { newsLists.add(news); } break; } type = parser.next(); } return newsLists; } 10.4. 提供ListView數據適配器
創建ListView數據適配器,該類繼承BaseAdapter。
private class MyAdapter extends BaseAdapter { @Override public int getCount() { return newsLists.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; if (convertView == null) { view = View.inflate(getApplicationContext(), R.layout.item, null); } else { view = convertView; } SmartImageView iv_icon = (SmartImageView) view.findViewById(R.id.iv_icon); TextView tv_title = (TextView) view.findViewById(R.id.tv_title); TextView tv_desc = (TextView) view.findViewById(R.id.tv_desc); TextView tv_type = (TextView) view.findViewById(R.id.tv_type); String imageUrl = newsLists.get(position).getImage(); iv_icon.setImageUrl(imageUrl, R.drawable.bg); tv_title.setText(newsLists.get(position).getTitle()); tv_desc.setText(newsLists.get(position).getDescription()); String typee = newsLists.get(position).getType(); String comment = newsLists.get(position).getComment(); int type = Integer.parseInt(typee); switch (type) { case 1: tv_type.setText(comment + "國內"); break; case 2: tv_type.setText("跟帖"); break; case 3: tv_type.setText("國外"); break; default: break; } return view; } }運行效果:
11. SmartImageView的使用
(1) 把com包,源碼包拷貝到當前工程;
(2) 在布局裡面定義,使用類的完整包名+類名。12. SmartImageView的原理
我們自己寫一個類似SmartImageView的控件來實現快速加載圖片,該類需要繼承ImageView,原理就是在子線程當中獲取圖片數據轉換成bitmap,利用handler顯示數據。
public class MySmartImageView extends ImageView { private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case 1: Bitmap bitmap = (Bitmap) msg.obj; MySmartImageView.this.setImageBitmap(bitmap); break; case 2: int resource = (Integer) msg.obj; MySmartImageView.this.setBackgroundResource(resource); break; case 3: int resource1 = (Integer) msg.obj; MySmartImageView.this.setBackgroundResource(resource1); break; default: break; } }; }; public MySmartImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MySmartImageView(Context context, AttributeSet attrs) { super(context, attrs); } public MySmartImageView(Context context) { super(context); } public void setImageUrl(final String path) { new Thread() { public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); int code = conn.getResponseCode(); if (code == 200) { InputStream in = conn.getInputStream(); Bitmap bitmap = BitmapFactory.decodeStream(in); Message msg = Message.obtain(); msg.obj = bitmap; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); } }; }.start(); } public void setImageUrl(final String path, final int resource) { new Thread() { public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); int code = conn.getResponseCode(); if (code == 200) { InputStream in = conn.getInputStream(); Bitmap bitmap = BitmapFactory.decodeStream(in); Message msg = Message.obtain(); msg.what = 1; msg.obj = bitmap; handler.sendMessage(msg); } else { Message msg = Message.obtain(); msg.what = 2; msg.obj = resource; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); Message msg = Message.obtain(); msg.what = 3; msg.obj = resource; handler.sendMessage(msg); } }; }.start(); } }(a)上面的handler,用來更新界面。由於獲取網絡數據是在子線程當中執行的,所以我們需要通過handler來實現在主線程當中更新UI。通過message攜帶參數,將bitmap對象傳遞給ImageView進行顯示
(b)setImageUrl(final String path)方法,開啟一個子線程網絡獲取圖片信息,然後將流信息轉換成bitmap對象,最後通過handler傳遞給ImageView顯示
(c)setImageUrl(final String path, final int resource)方法,該方法多了一個參數resource,用來當請求失敗或者發生異常時顯示的圖片。13. Get和Post登錄方式
Get請求和Post請求的區別:
(1)請求路徑不同;
(2)Post請求比get請求多了content-type和content-length兩個請求頭;
(3)Post請求是以流的形式把數據寫給服務器;
(4)Get請求數據大小有限制,在IE中是1k,在其他浏覽器中是4k。
Get請求登錄代碼:public void click1(View v) { final String pwd = et_password.getText().toString().trim(); final String name = et_username.getText().toString().trim(); new Thread() { public void run() { try { /將用戶名和密碼拼接成Url訪問路徑/ String path = "http://192.168.19.89:8080/web/LoginServlet?username=" + name + "&password=" + pwd ; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); int code = conn.getResponseCode(); if (code == 200) { InputStream inputStream = conn.getInputStream(); String content = StreamUtils.readStream(inputStream); showToast(content); } } catch (Exception e) { e.printStackTrace(); } }; }.start(); } public void showToast(final String content) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), content, 1).show(); } }); }Post請求登錄代碼:
public void click2(View v) { final String pwd = et_password.getText().toString().trim(); final String name = et_username.getText().toString().trim(); new Thread() { public void run() { try { //拼接用戶名和密碼,作為參數體傳遞給服務器 String path = "http://192.168.19.89:8080/web/LoginServlet"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); //設置請求方式為POST conn.setRequestMethod("POST"); conn.setConnectTimeout(5000); String data = "username=" + name + "&password=" + pwd; //設置Content-type頭信息 conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //Content-Length頭信息,第二個參數是數據的字節數 conn.setRequestProperty("Content-Length", data.length() + ""); //setDoOutput(true)該方法設置一個標記,允許向服務器輸出數據 conn.setDoOutput(true); //調用getOutputStream()方法獲取輸出流,通過輸出流向服務器寫入數據 conn.getOutputStream().write(data.getBytes()); int code = conn.getResponseCode(); if (code == 200) { InputStream inputStream = conn.getInputStream(); String content = StreamUtils.readStream(inputStream); showToast(content); } } catch (Exception e) { e.printStackTrace(); } }; }.start(); }
轉載請注明出處:http://blog.csdn.net/zhaokaiqiang1992 本文主要介紹了當我們使用限定符修飾我們的資源文件夾,例如drawable-en
Android 如何查看Wifi密碼前言:在Android手機中,連接了Wifi之後,密碼一般就看不到了,那有沒有什麼辦法可以查看到這些密碼呢?辦法一般有兩種,一種是通過
首先明確流程 既然實現自動更新,我們首先必須讓我們的應用知道是否存在新版本的軟件,因此我們可以在自己的網站上放置配置文件,存放軟件的版本信息: 2
先看看效果圖:開源項地址:https://github.com/chrisbanes/Android-PullToRefresh 下拉刷新這個功能我們都比較常見