最近在找Android開發(fā)的工作辕漂,遇到了一些面試的問題呢灶,加上朋友面試遇到的一些問題吴超,感覺有必要在此記錄一下,也分享給大家鸯乃,說不定還有用呢鲸阻。
1跋涣、線程同步問題:有3個(gè)線程abc,循環(huán)輸出十次abc鸟悴。
這個(gè)問題簡單的就是使用AtomicInteger
來實(shí)現(xiàn)陈辱,具體實(shí)現(xiàn)方式如下:
private AtomicInteger sycValue = new AtomicInteger(0);
private static final int MAX_SYC_VALUE = 3 * 10;
public void test() {
new Thread(new RunnableA()).start();
new Thread(new RunnableB()).start();
new Thread(new RunnableC()).start();
}
private class RunnableA implements Runnable {
public void run() {
while (sycValue.get() < MAX_SYC_VALUE) {
if (sycValue.get() % 3 == 0) {
System.out.println(String.format("第%d遍", sycValue.get() / 3 + 1));
System.out.println("A");
sycValue.getAndIncrement();
}
}
}
}
private class RunnableB implements Runnable {
public void run() {
while (sycValue.get() < MAX_SYC_VALUE) {
if (sycValue.get() % 3 == 1) {
System.out.println("B");
sycValue.getAndIncrement();
}
}
}
}
private class RunnableC implements Runnable {
public void run() {
while (sycValue.get() < MAX_SYC_VALUE) {
if (sycValue.get() % 3 == 2) {
System.out.println("C");
System.out.println();
sycValue.getAndIncrement();
}
}
}
}
2、多線程下載同一個(gè)文件
這個(gè)問題主要分三步來考慮:
- 獲取文件總長度细诸,通過總長度來確定開啟幾個(gè)線程下載沛贪,并不是線程越多就越好。
- 分段下載文件震贵,確定線程數(shù)后利赋,每個(gè)線程下載相應(yīng)的數(shù)據(jù)。
- 將分段下載的文件拼接為一個(gè)完整的文件猩系。
private void test() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("開始下載");
download("https://a-ssl.duitang.com/uploads/item/201307/11/20130711155049_yhiWQ.jpeg", 3);
}
}).start();
}
private void download(String path, int threadNum) {
try {
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5 * 1000);
//獲取文件長度
int length = connection.getContentLength();
//計(jì)算每個(gè)線程下載長度
int block = (length % threadNum) == 0 ? length / threadNum : length / threadNum + 1;
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
path.substring(path.lastIndexOf("/") + 1));
for (int i = 0; i < threadNum; i++)
new DownThread(i, file, block, url).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public class DownThread extends Thread {
/**
* 線程序號(hào)id
*/
private int id;
/**
* 目標(biāo)文件
*/
private File file;
/**
* 每個(gè)線程下載文件的長度
*/
private int block;
/**
* 下載地址
*/
private URL url;
public DownThread(int id, File file, int block, URL url) {
this.id = id;
this.file = file;
this.block = block;
this.url = url;
}
@Override
public void run() {
int start = (id * block);// 當(dāng)前線程開始下載處
int end = (id + 1) * block - 1;// 當(dāng)前線程結(jié)束下載處
try {
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rwd");
randomAccessFile.seek(start);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5 * 1000);
connection.setRequestMethod("GET");
// 指定網(wǎng)絡(luò)位置從什么位置開始下載,到什么位置結(jié)束
connection.setRequestProperty("Range", "bytes=" + start + "-" + end);
InputStream in = connection.getInputStream();
byte[] data = new byte[1024];
int len = 0;
while ((len = in.read(data)) != -1) {
randomAccessFile.write(data, 0, len);
}
in.close();
randomAccessFile.close();
System.out.println("線程" + id + "下載完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}
3媚送、網(wǎng)頁端生成二維碼,手機(jī)端掃描登錄
這個(gè)問題需要服務(wù)器端的配合寇甸,這里就講一講大概的思路了塘偎。
- 網(wǎng)頁端生成二維碼,同時(shí)長連接等待服務(wù)器響應(yīng)拿霉。
- 手機(jī)端掃描二維碼吟秩,然后判斷手機(jī)端是否登錄,如果沒有就先登錄绽淘,然后通知服務(wù)器掃描結(jié)果峰尝。
- 網(wǎng)頁端收到服務(wù)器響應(yīng),顯示已經(jīng)掃描待手機(jī)端確認(rèn)登錄收恢,同時(shí)手機(jī)端顯示確認(rèn)界面武学。
- 手機(jī)端確認(rèn)或取消登錄,同時(shí)通知服務(wù)器結(jié)果伦意,網(wǎng)頁端收到服務(wù)器響應(yīng)火窒,同時(shí)顯示相應(yīng)結(jié)果。
4驮肉、廣播的種類和不同之處
Android系統(tǒng)中有3種廣播熏矿,話說當(dāng)時(shí)只知道前面3種常用的,后來回來查資料才發(fā)現(xiàn)有5種离钝。
- 普通廣播(Normal Broadcast)
- 系統(tǒng)廣播(System Broadcast)
- App應(yīng)用內(nèi)廣播(Local Broadcast)
- 有序廣播(Ordered Broadcast)
- 粘性廣播(Sticky Broadcast)
普通廣播(Normal Broadcast)
普通廣播是完全異步的票编,可以在同一時(shí)刻(邏輯上)被所有廣播接收者接收到,消息傳遞的效率比較高卵渴,廣播接收者中注冊(cè)時(shí)intentFilter的action與廣播匹配慧域,才會(huì)接收到此廣播。發(fā)送普通廣播使用的是Context.sendBroadcast()
浪读。
系統(tǒng)廣播(System Broadcast)
Android中內(nèi)置了多個(gè)系統(tǒng)廣播昔榴,只要涉及到手機(jī)的基本操作(如開機(jī)辛藻、網(wǎng)絡(luò)狀態(tài)變化、拍照等等)互订,都會(huì)發(fā)出相應(yīng)的廣播吱肌,每個(gè)廣播都有特定的Intent - Filter(包括具體的action)。當(dāng)使用系統(tǒng)廣播時(shí)仰禽,只需要在注冊(cè)廣播接收者時(shí)定義相關(guān)的action即可氮墨,并不需要手動(dòng)發(fā)送廣播,當(dāng)系統(tǒng)有相關(guān)操作時(shí)會(huì)自動(dòng)進(jìn)行系統(tǒng)廣播吐葵。
App應(yīng)用內(nèi)廣播(Local Broadcast)
App應(yīng)用內(nèi)廣播可理解為一種局部廣播勇边,廣播的發(fā)送者和接收者都同屬于一個(gè)App。相比于全局廣播(普通廣播)折联,App應(yīng)用內(nèi)廣播優(yōu)勢(shì)體現(xiàn)在:安全性高 & 效率高粒褒。使用方式上與普通廣播幾乎相同,只是注冊(cè)/取消注冊(cè)廣播接收器和發(fā)送廣播時(shí)將參數(shù)的Context
變成了LocalBroadcastManager
的單一實(shí)例诚镰。并且只能通過LocalBroadcastManager
動(dòng)態(tài)注冊(cè)奕坟,不能靜態(tài)注冊(cè)。
//動(dòng)態(tài)注冊(cè)
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, intentFilter);
//取消注冊(cè)
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
//發(fā)送應(yīng)用內(nèi)廣播
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
有序廣播(Ordered Broadcast)
有序廣播是按照接收者聲明的優(yōu)先級(jí)別(聲明在intent-filter元素的android:priority屬性中清笨,數(shù)越大優(yōu)先級(jí)別越高,取值范圍:-1000到1000月杉。也可以調(diào)用IntentFilter對(duì)象的setPriority()進(jìn)行設(shè)置),被接收者依次接收廣播抠艾。如:A的級(jí)別高于B,B的級(jí)別高于C,那么苛萎,廣播先傳給A,再傳給B检号,最后傳給C腌歉。A得到廣播后,可以往廣播里存入數(shù)據(jù)齐苛,當(dāng)廣播傳給B時(shí),B可以從廣播中得到A存入的數(shù)據(jù)翘盖。
//發(fā)送有序廣播
Context.sendOrderedBroadcast(intent)
//終止廣播
BroadcastReceiver.abortBroadcast()
粘性廣播(Sticky Broadcast)
由于在Android5.0 & API 21中已經(jīng)失效,所以不建議使用凹蜂,在這里也不作過多的總結(jié)了馍驯。
5、移動(dòng)支付
話說現(xiàn)在移動(dòng)支付還是用得挺常見的玛痊,正好也弄過常見的微信支付汰瘫、支付寶支付和銀聯(lián)支付,總體來說使用起來并不會(huì)有什么難度擂煞,各家的SDK都是介紹得很詳細(xì)的混弥,這里就貼一下各家的開發(fā)文檔地址。(傳送門:微信支付颈娜、支付寶支付剑逃、銀聯(lián)支付)
6浙宜、死鎖的四個(gè)條件
- 互斥條件:進(jìn)程對(duì)所分配到的資源不允許其他進(jìn)程進(jìn)行訪問官辽,若其他進(jìn)程訪問該資源蛹磺,只能等待,直至占有該資源的進(jìn)程使用完成后釋放該資源
- 請(qǐng)求和保持條件:進(jìn)程獲得一定的資源之后同仆,又對(duì)其他資源發(fā)出請(qǐng)求萤捆,但是該資源可能被其他進(jìn)程占有,此事請(qǐng)求阻塞俗批,但又對(duì)自己獲得的資源保持不放
- 不可剝奪條件:是指進(jìn)程已獲得的資源俗或,在未完成使用之前,不可被剝奪岁忘,只能在使用完后自己釋放
- 環(huán)路等待條件:是指進(jìn)程發(fā)生死鎖后辛慰,必然存在一個(gè)進(jìn)程--資源之間的環(huán)形鏈
處理死鎖的基本方法
- 預(yù)防死鎖:通過設(shè)置一些限制條件,去破壞產(chǎn)生死鎖的必要條件
- 避免死鎖:在資源分配過程中干像,使用某種方法避免系統(tǒng)進(jìn)入不安全的狀態(tài)帅腌,從而避免發(fā)生死鎖
- 檢測(cè)死鎖:允許死鎖的發(fā)生,但是通過系統(tǒng)的檢測(cè)之后麻汰,采取一些措施速客,將死鎖清除掉
- 解除死鎖:該方法與檢測(cè)死鎖配合使用
7、Object的公共方法
眾所周知Java中所有的類都是繼承于Object五鲫,所以我們編寫的類默認(rèn)都具有這些方法溺职,包括有hashCode()
、wait()
位喂、notify()
浪耘、notifyAll()
、equals()
塑崖、getClass()
点待、toString()
、clone()
弃舒、finalize()
等癞埠。
- hashCode()方法簡單地說就是返回一個(gè)integer類型的值,這個(gè)值是通過該Object的內(nèi)部地址(internal address)轉(zhuǎn)換過來的聋呢,這個(gè)哈希碼是可以通過getClass()方法看到具體值的苗踪,顯示的是十六進(jìn)制的數(shù),有時(shí)候可以通過此方法來判斷對(duì)象的引用是否相等削锰。
- wait()用于多線程中通铲,使當(dāng)前線程等待該對(duì)象的鎖,當(dāng)前線程必須是該對(duì)象的擁有者器贩,也就是具有該對(duì)象的鎖颅夺。
- notify用于喚醒在該對(duì)象上等待的某個(gè)線程朋截,notifyAll()用于喚醒在該對(duì)象上等待的所有線程。
- equals()用于判斷這兩個(gè)引用是否指向的是同一個(gè)對(duì)象吧黄。
- getClass()用戶獲取該對(duì)象的運(yùn)行時(shí)類的java.lang.Class 對(duì)象部服。
- toString()方法返回一個(gè)字符串,它的值等于:getClass().getName()+ '@' + Integer.toHexString(hashCode())拗慨。
- clone()保護(hù)方法廓八,實(shí)現(xiàn)對(duì)象的淺復(fù)制,只有實(shí)現(xiàn)了Cloneable接口才可以調(diào)用該方法赵抢,否則拋出CloneNotSupportedException異常剧蹂。
- finalize()用于當(dāng)垃圾回收器確定不存在對(duì)該對(duì)象的更多引用時(shí),由對(duì)象的垃圾回收器調(diào)用此方法烦却。子類重寫finalize 方法宠叼,以配置系統(tǒng)資源或執(zhí)行其他清除。
** ---- End ---- 暫時(shí)記錄到這其爵,后面不定時(shí)更新冒冬,歡迎關(guān)注。**