怎么樣分析一個(gè)網(wǎng)站百度搜索引擎seo
1.四大基本組件
activity
安卓中的基本組件之一,一個(gè)activity表示一個(gè)與用戶進(jìn)行交互的窗口。一般來(lái)說(shuō)MainActivity就相當(dāng)于Java項(xiàng)目中Main。
onCreate()方法,相當(dāng)于public static void main(String args[]),照著寫就完事了。
每個(gè)Activity固定的開(kāi)頭
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);}
注意每次從后臺(tái)重新進(jìn)入頁(yè)面時(shí),Activity都會(huì)重新被調(diào)用一次,也就是說(shuō)onCreate()都會(huì)重新執(zhí)行一遍。也就是說(shuō)是新的代碼。
onCreate()中不能擁有阻塞操作(死循環(huán),socket.connect,readLine()),每次進(jìn)入Activity中必須保證onCreate中得代碼能夠一次性執(zhí)行完,這東西相當(dāng)于初始化操作。
service
//開(kāi)始Service
Intent intent=new Intent(this,MyService.class) //intent后面講,MyService是繼承Service的自定義類
startService(intent);MyService內(nèi)部執(zhí)行過(guò)程:1.onCreate(),只用第一次start會(huì)調(diào)用 2.onStartCommand(變量忘了),每次start都會(huì)調(diào)用,代碼寫在這里。
//結(jié)束
stopService(intent); MyService:直接執(zhí)行onDestroyed里面的函數(shù)
2.View組件
用來(lái)繪制圖像的畫板,相當(dāng)于Swing中的Frame和JPanel合體版。View只是一個(gè)畫板
view的一些基本方法
*boolean onKeyDown(int keyCode , KeyEventevent);用戶在該組件上按下時(shí)觸發(fā)的
*boolean onKeyLongPress(int keyCode ,keyEvent event);用戶在該組件上長(zhǎng)按時(shí)觸發(fā)的
*boolean onkeyShorcut(int keyCode ,keyEvent event);當(dāng)一個(gè)鍵盤快捷鍵事件發(fā)生時(shí)觸發(fā)該方法
*boolean onkeyUp(int keyCode , keyEventevent);用戶松開(kāi)按鍵的時(shí)候觸發(fā)的事件
*boolean onTouchEvent(MotionEvent event);用戶在該組件上觸發(fā)觸摸屏?xí)r觸發(fā)該方法
*boolean onTrackballEvent(MotionEventevent);用戶在該組件商觸發(fā)軌跡球時(shí)觸發(fā)該方法
setContentView()
setContentView()只能在Activity中的onCreate()中進(jìn)行,不能新建一條線程,不然直接暴斃,會(huì)啟動(dòng)不了。我也不知道是什么原因。反正不能新建線程create。
3.R類
android studio在編譯時(shí)會(huì)自動(dòng)生成一個(gè)R類。R類可以調(diào)用res文件夾下的所有資源,一般是指res/layout
例如,我在res/layout中定義了一個(gè)button組件,他的id是button1
則可以通過(guò)如下代碼獲得組件,和Javascript很像
findViewById(R.id.button1)
4.前端
布局
布局方面和Web開(kāi)發(fā)很像,通過(guò)XML進(jìn)行組件的布局,只不過(guò)沒(méi)有CSS的存在
5.多線程
Handler類
多線程中,每隔線程的消息都需要發(fā)送到Handler類,Handler集中處理。大概是這樣
主線程和子線程
在一個(gè)Activity中能夠更新UI的只有主線程(就是onCreate那個(gè)),其他人工新建的子線程都不能直接操作UI界面,同時(shí)主線程是絕對(duì)不能出現(xiàn)阻塞操作,例如在onCreate里面執(zhí)行Thread.sleep(),同步鎖之類的都是絕對(duì)不會(huì)被允許的,所以耗時(shí)的操作只能新建一條線程來(lái)實(shí)現(xiàn)。例如網(wǎng)絡(luò)連接,網(wǎng)絡(luò)請(qǐng)求都要放在新建的子線程中去搞。setContentView只能在主線程中實(shí)現(xiàn),子線程中無(wú)法使用
通過(guò)Handler去操作主線程
子線程如果想要更新UI界面必須通過(guò)Handler向主線程發(fā)出請(qǐng)求,然后更新UI。簡(jiǎn)單的來(lái)說(shuō)Handler就是主線程和子線程的通信媒介,使得子線程也能間接的執(zhí)行更新UI的操作,當(dāng)然Handler也可以用于子線程之間
Android異步通信:這是一份Handler消息傳遞機(jī)制的使用教程 - 簡(jiǎn)書
核心的handler類代碼,在handleMessage中執(zhí)行更新UI的操作,具體查看上述鏈接
class mHandle extends Handler{@Overridepublic void handleMessage(Message msg){//重寫這部分代碼用來(lái)更新UI}
}
需要注意的是,一條線程只能使用Handler一次,也就是說(shuō)每條線程只有一次通過(guò)Handler向主線程發(fā)起更新請(qǐng)求的機(jī)會(huì),如果要多次發(fā)出更新UI的線程建議在子線程里面再新建一條線程
6.繪畫
安卓的繪畫需要在View模塊中進(jìn)行?;舅悸肥窃赩iew里面新建一個(gè)線程Thread進(jìn)行繪畫的動(dòng)作更新,然后再View里面的surfaceCreated()中調(diào)用線程。
public void run(){draw();
}public void surfaceCreated(){new Thread(this).start;
}
與Swing開(kāi)發(fā)的區(qū)別在于,這個(gè)View類相當(dāng)于Frame和Panel的混合體。畫的過(guò)程必須是新建線程,不能再主線程中畫。
SurfaceHolder可以視作是用來(lái)管理SurfaceView的接口
獲得畫布
myCanvas=mySurfaceHolder.lockCanvas();
圖片重復(fù)或抖動(dòng)的現(xiàn)象
canvas畫圖的基本原理應(yīng)該是覆蓋,而不是清空。如果你的圖片太小,沒(méi)辦法覆蓋整個(gè)屏幕的話,此時(shí)如果你循環(huán)繪制同樣的圖片且每次繪制都偏移一點(diǎn),應(yīng)該會(huì)出現(xiàn)重復(fù)或抖動(dòng)的現(xiàn)象。
在飛機(jī)大作戰(zhàn)中,會(huì)出現(xiàn)抖動(dòng)的現(xiàn)象,如圖
?大概率是因?yàn)閳D片太小了,沒(méi)辦法覆蓋整個(gè)屏幕,所以導(dǎo)致重疊。解決方法,用canvas繪畫前,先清空之前的畫布?;蚴钦乙粋€(gè)特別大的圖片覆蓋整個(gè)屏幕。
或是再繪畫前先使用canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)來(lái)清空之前的畫布
提供一個(gè)圖片縮放的算法
SurfaceView的執(zhí)行過(guò)程
1.進(jìn)入程序調(diào)用surfaceCreated()
2.調(diào)用surfaceChanged(),改變屏幕的長(zhǎng)和寬
3.推出程序,例如點(diǎn)擊home或返回,或是直接刷新內(nèi)存時(shí),都會(huì)調(diào)用surfaceDestroyed()
Bitmap
Bitmap用來(lái)加載圖片,相當(dāng)于Java中的BufferImage,方法都是類似的。
//聲明圖片的變量
private Bitmap imgae;//獲取圖片
image=BitmapFactory.decodeResource(getResource(),R.drawable.image);
7.音視頻MediaPlayer
Android內(nèi)置多媒體播放器,MediaPlayer,能夠播放音視頻。
不過(guò)要注意的是MediaPlayer是一個(gè)有限狀態(tài)機(jī),所以要在合適的狀態(tài)調(diào)用合適的方法,否則會(huì)出現(xiàn)一堆的報(bào)錯(cuò)。有一種比較簡(jiǎn)單的粗暴但性能很低的調(diào)用方法時(shí),每次播放音視頻前都實(shí)例化MediaPlayer一次,在用start播放音視頻。
示例
//初始化播放器
MediaPlayer player=MediaPlayer.create(this,R.raw.mymusic);//是否循環(huán)播放,默認(rèn)是不循環(huán)
player.setLooping(false);//播放音樂(lè)
player.start();
這東西不能用在View
SoundPool
SoundPool一般是用來(lái)播放特效音樂(lè)的,例如游戲當(dāng)中的爆炸聲,子彈射擊聲音。之所以這樣晚會(huì)是因?yàn)槿绻加胢ediaPlayer播放會(huì)很卡,mediaPlayer是一個(gè)文件接一個(gè)文件的播放的,每次只能播放一個(gè)音樂(lè),而SoundPool在播放時(shí)會(huì)單獨(dú)設(shè)置線程,支持同時(shí)播放多個(gè)音樂(lè)。
使用步驟如下
1.初始化
8.網(wǎng)絡(luò)開(kāi)發(fā)
網(wǎng)絡(luò)開(kāi)發(fā)需要兩部分程序(即兩個(gè)project),一個(gè)服務(wù)器,一個(gè)客戶端。
服務(wù)器啟動(dòng)后不斷的監(jiān)聽(tīng)客戶端,以做出響應(yīng),做出響應(yīng)新建一條線程來(lái)處理響應(yīng),防止監(jiān)聽(tīng)中斷。
socket:網(wǎng)絡(luò)上的搬運(yùn)工
服務(wù)器和客戶端通過(guò)socket進(jìn)行信息的交互,客戶端通過(guò)socket發(fā)出信息,服務(wù)器通過(guò)socket接收信息。scoket這個(gè)類就是一個(gè)搬運(yùn)工。
socket中的端口port的作用是為了讓服務(wù)器識(shí)別客戶端,每一個(gè)客戶端都有一個(gè)單獨(dú)的port,這個(gè)port相當(dāng)于一個(gè)ID。例如飛機(jī)大作戰(zhàn)聯(lián)網(wǎng)中,用戶A的port是1,B的是2;則在服務(wù)器要建立兩個(gè)socket分別對(duì)應(yīng)A和B
對(duì)于同一個(gè)端口多次建立連接時(shí),每次連接都是不同客戶,所以沒(méi)連接一次要單獨(dú)開(kāi)一條請(qǐng)求線程處理請(qǐng)求,這樣就能實(shí)現(xiàn)Socket一對(duì)多的通信。
ServerSocket serverSocket=new ServerSocket(9999);//監(jiān)聽(tīng)端口號(hào)9999int count=0;
while(true){count++;Socket socket=serverSocket.accept();System.out.println("第"+count+"個(gè)客戶");new ServiceThread().start();//處理客戶請(qǐng)求的多線程,自己去實(shí)現(xiàn)
}
服務(wù)器
服務(wù)器是一個(gè)信號(hào)中轉(zhuǎn)站,用來(lái)實(shí)現(xiàn)不同的客戶之間的信號(hào)交互,或是服務(wù)器與用戶的信號(hào)交互。服務(wù)器創(chuàng)建后時(shí)刻監(jiān)聽(tīng)客戶的請(qǐng)求,根據(jù)用戶的請(qǐng)求做出具體的響應(yīng)。關(guān)閉的服務(wù)器與用戶連接的邏輯代碼建立在服務(wù)器內(nèi),客戶端中存在的永遠(yuǎn)都是請(qǐng)求而不是具體的處理邏輯。
BufferReader
網(wǎng)絡(luò)中數(shù)據(jù)的交互需要通過(guò)bufferreader和bufferwriter處理流來(lái)進(jìn)行IO操作
需要注意的是BufferReader中的readline()返回一個(gè)字符串,而且只會(huì)返回一次,返回后就沒(méi)了,這個(gè)其實(shí)和在控制臺(tái)用BufferReader進(jìn)行輸入操作是一樣的,控制臺(tái)中輸入一次數(shù)據(jù)就是一次readline(),程序通過(guò)readline()把數(shù)據(jù)傳到變量中,下一次輸入就是下一個(gè)readline()。在網(wǎng)絡(luò)開(kāi)發(fā)中也一樣。一次請(qǐng)求,數(shù)據(jù)發(fā)送端通過(guò)BufferWriter輸出一個(gè)數(shù)據(jù),接收方用BufferReader的readline()接受數(shù)據(jù)據(jù)并讀出。讀完后就沒(méi)了,再次readline()直接為空。
使用readLine()后,如果readLine()沒(méi)有讀到值,不會(huì)輸出null,而是進(jìn)入一個(gè)阻塞狀態(tài),一致等待有東西輸入,就像在控制臺(tái)那樣,這樣就實(shí)現(xiàn)了服務(wù)器對(duì)客戶端請(qǐng)求的時(shí)刻監(jiān)聽(tīng)。
socket的連接一旦關(guān)閉后,那么對(duì)應(yīng)的InputStream會(huì)立刻變?yōu)榭?#xff0c;也就是說(shuō)readLine()這時(shí)候讀的肯定是空。socket重新連接時(shí),會(huì)先關(guān)閉再連接。
BufferReader in=new BufferReader(new InputStreamReader(socket.getInputStream))//之后正常的用 in.readLine()就可以讀數(shù)據(jù)了
PrintWriter
PrintWriter用來(lái)輸出數(shù)據(jù),可以理解為發(fā)射
PrintWriter writer=new PrintWriter(new BufferWriter(new OutputWriter(socket.getOutputStreamWriter)))//之后用 writer.println()正常的輸出就好
多線程
服務(wù)器對(duì)一個(gè)客戶端的的監(jiān)聽(tīng)是一條線程,一個(gè)客戶端對(duì)應(yīng)一條線程,別把兩個(gè)客戶放到同一個(gè)線程中,這樣耦合程度太高了
客戶端對(duì)服務(wù)器的響應(yīng)和請(qǐng)求也是一個(gè)線程,這樣實(shí)現(xiàn)數(shù)據(jù)傳輸和邏輯功能的解耦,主線程從子線程中拿數(shù)據(jù)用就好。
無(wú)論是客戶端請(qǐng)求連接還是處理連接,或是服務(wù)器端監(jiān)聽(tīng)客戶端時(shí)刻響應(yīng)連接都必須要使用多線程,不然socket.connect()會(huì)報(bào)錯(cuò)
基本思想是,在請(qǐng)求連接或是響應(yīng)數(shù)據(jù)傳送時(shí)都要使用多線程
以飛機(jī)大作戰(zhàn)為例
服務(wù)器:監(jiān)聽(tīng)玩家得得分情況和傳送對(duì)手得分是一條單獨(dú)得線程
客戶端:建立連接需要一條請(qǐng)求連接線程
? ? ? ? ? ? 響應(yīng)數(shù)據(jù)傳送(傳送己方得分,接受對(duì)方得分)需要一條線程
服務(wù)器端
while(true){Socket socket=SocketServer.accept()//等待客戶端發(fā)起連接,如果沒(méi)接收到就一直等new ServiceThread().start();//開(kāi)啟服務(wù)線程
}
客戶端
//連接線程
class ConnectThread extends Thread{public void run(){(1) 方法一 Socket socket=new Socket("IP 地址",端口號(hào));//端口號(hào)相當(dāng)于客戶得ID,隨便取名(2) 方法二 Socket socket=new Socket();socket.connect(new InetSocketAddress("IP",端口),連接時(shí)間界限);//連接超過(guò)時(shí)間界限會(huì)報(bào)錯(cuò)}
JSON的使用
1.客戶端端
直接調(diào)用JSONObject就好,這個(gè)JSONObject可以完全當(dāng)成javascript里面的對(duì)象去弄就好。
//聲明JSONObject
JSONObject jsonObject=new JSONObject();//給json中增加鍵值對(duì)或是改變json的鍵值對(duì)的值
jsonObject.put(key,value);
2.需要引入JSONObject的相關(guān)依賴
GitHub - joytom/json_all: java使用json所需要的全部jar包
這個(gè)JSONObject和Android自帶的JSONObject可以看作是兩個(gè)東西,大部分地方一樣,但在細(xì)節(jié)層面上有所不同。
//其他類轉(zhuǎn)為JSON
jsonObejct=JSONObject.fromObject(Object);//JSON的put方法只能引入鍵值對(duì)
jsonObject.put(key,value);//更改同一個(gè)key的value不能使用put方法,只能先轉(zhuǎn)化位Map再通過(guò)更改Map后再次轉(zhuǎn)為Json
//這里需要使用迭代器
Map<String,Object> map=new HashMap<>();
for(Iterator<String> it=jsonObject.keys();it.hasNext();){String key=it.next;switch(key){case "key1":map.put(key,value1);break;case "key2":map.put(key,value2);break;....default:}jsonObject=JSONObject.fromObject(map);
}
Socket和輸出輸出流的創(chuàng)建
個(gè)人建議請(qǐng)求連接和監(jiān)聽(tīng)程序放在同一個(gè).java文件(或是說(shuō)同一個(gè)類)當(dāng)中實(shí)現(xiàn),盡量避免出現(xiàn)需要使用socket傳參。輸出流和輸入流的建立需要在connect后直接建立,不然會(huì)暴斃,會(huì)出現(xiàn)報(bào)錯(cuò)。報(bào)錯(cuò)的原因大概率是因?yàn)榻nput和output是socket還是空,所以沒(méi)辦法建立連接。所以使用socket時(shí)盡可能的保證socket.connect后直接創(chuàng)建輸入流和輸出流,而且必須要先connect在創(chuàng)建輸入和輸出流,不然會(huì)創(chuàng)建失敗。這個(gè)說(shuō)明輸入輸出流和connect如果在兩條線程里面執(zhí)行的話,必須保證connect的結(jié)束后才會(huì)啟動(dòng)輸入輸出流的創(chuàng)建線程,同時(shí)輸入輸出流用到的socket一定是已經(jīng)connect的socket。
簡(jiǎn)單的來(lái)說(shuō)創(chuàng)建輸入輸出流要保證如下的順序
socket.connect(new InetSocketAddress(Ip,端口),5000)PrintWriter writer=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream)));
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
建議先創(chuàng)建輸出流再創(chuàng)建輸入流養(yǎng)成良好的習(xí)慣
IP地址查詢
1.局域網(wǎng)IP
再命令行中輸入ipconfig即可顯示出本機(jī)的局域網(wǎng)下的IP地址
以太網(wǎng):有線局域網(wǎng)連接標(biāo)準(zhǔn),如果電腦不接網(wǎng)線,這東西默認(rèn)是什么都沒(méi)有。里面的IP都是有線局域網(wǎng)下的IP,例如192.168.xx.xx
無(wú)線局域網(wǎng) wlan:wifi連接下本機(jī)的局域網(wǎng)IP,只需要關(guān)注IPv4就好,這個(gè)IPv4就是在當(dāng)前wifi下你這臺(tái)電腦的IP地址。一般情況下如果要實(shí)現(xiàn)同一個(gè)wifi下的網(wǎng)絡(luò)通信,客戶端用這個(gè)IPv4去連接服務(wù)器。注意這里的IP是指服務(wù)器的IP。
2.公網(wǎng)的IP
在百度上面輸入IP就可以查到本機(jī)的公網(wǎng)IP了。這個(gè)IP是全球唯一,由運(yùn)營(yíng)商分配的,你不用管,也管不了。
部分內(nèi)網(wǎng)可能有權(quán)限設(shè)置,此時(shí)用內(nèi)網(wǎng)的IP可能無(wú)法進(jìn)行網(wǎng)絡(luò)通信(例如校園網(wǎng))。這時(shí)會(huì)出現(xiàn)android.system.ErrnoException: isConnected failed: EHOSTUNREACH (No route to host)錯(cuò)誤。
解決方法:用手機(jī)開(kāi)熱點(diǎn),同時(shí)連接服務(wù)器和客戶端
9.樣式拼接
recycleview和listview