我的Android面试之路

最近在找Android开发的工作,遇到了一些面试的问题,加上朋友面试遇到的一些问题,感觉有必要在此记录一下,也分享给大家,说不定还有用呢。

1、线程同步问题:有3个线程abc,循环输出十次abc。

这个问题简单的就是使用AtomicInteger来实现,具体实现方式如下:

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、多线程下载同一个文件

这个问题主要分三步来考虑:

  • 获取文件总长度,通过总长度来确定开启几个线程下载,并不是线程越多就越好。
  • 分段下载文件,确定线程数后,每个线程下载相应的数据。
  • 将分段下载的文件拼接为一个完整的文件。
  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();
        //计算每个线程下载长度
        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 {
    /**
     * 线程序号id
     */
    private int id;
    /**
     * 目标文件
     */
    private File file;
    /**
     * 每个线程下载文件的长度
     */
    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);// 当前线程开始下载处
        int end = (id + 1) * block - 1;// 当前线程结束下载处
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rwd");
            randomAccessFile.seek(start);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(5 * 1000);
            connection.setRequestMethod("GET");
            // 指定网络位置从什么位置开始下载,到什么位置结束
            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、网页端生成二维码,手机端扫描登录

这个问题需要服务器端的配合,这里就讲一讲大概的思路了。

  1. 网页端生成二维码,同时长连接等待服务器响应。
  2. 手机端扫描二维码,然后判断手机端是否登录,如果没有就先登录,然后通知服务器扫描结果。
  3. 网页端收到服务器响应,显示已经扫描待手机端确认登录,同时手机端显示确认界面。
  4. 手机端确认或取消登录,同时通知服务器结果,网页端收到服务器响应,同时显示相应结果。

4、广播的种类和不同之处

Android系统中有3种广播,话说当时只知道前面3种常用的,后来回来查资料才发现有5种。

  • 普通广播(Normal Broadcast)
  • 系统广播(System Broadcast)
  • App应用内广播(Local Broadcast)
  • 有序广播(Ordered Broadcast)
  • 粘性广播(Sticky Broadcast)
普通广播(Normal Broadcast)

普通广播是完全异步的,可以在同一时刻(逻辑上)被所有广播接收者接收到,消息传递的效率比较高,广播接收者中注册时intentFilter的action与广播匹配,才会接收到此广播。发送普通广播使用的是Context.sendBroadcast()

系统广播(System Broadcast)

Android中内置了多个系统广播,只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播,每个广播都有特定的Intent - Filter(包括具体的action)。当使用系统广播时,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播。

App应用内广播(Local Broadcast)

App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高。使用方式上与普通广播几乎相同,只是注册/取消注册广播接收器和发送广播时将参数的Context变成了LocalBroadcastManager的单一实例。并且只能通过LocalBroadcastManager动态注册,不能静态注册。

//动态注册 
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, intentFilter);
//取消注册
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
//发送应用内广播
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
有序广播(Ordered Broadcast)

有序广播是按照接收者声明的优先级别(声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000。也可以调用IntentFilter对象的setPriority()进行设置),被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C。A得到广播后,可以往广播里存入数据,当广播传给B时,B可以从广播中得到A存入的数据。

//发送有序广播
Context.sendOrderedBroadcast(intent)
//终止广播
BroadcastReceiver.abortBroadcast()
粘性广播(Sticky Broadcast)

由于在Android5.0 & API 21中已经失效,所以不建议使用,在这里也不作过多的总结了。

5、移动支付

话说现在移动支付还是用得挺常见的,正好也弄过常见的微信支付、支付宝支付和银联支付,总体来说使用起来并不会有什么难度,各家的SDK都是介绍得很详细的,这里就贴一下各家的开发文档地址。(传送门:微信支付支付宝支付银联支付

6、死锁的四个条件

  1. 互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
  2. 请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
  3. 不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
  4. 环路等待条件:是指进程发生死锁后,必然存在一个进程--资源之间的环形链

处理死锁的基本方法

  • 预防死锁:通过设置一些限制条件,去破坏产生死锁的必要条件
  • 避免死锁:在资源分配过程中,使用某种方法避免系统进入不安全的状态,从而避免发生死锁
  • 检测死锁:允许死锁的发生,但是通过系统的检测之后,采取一些措施,将死锁清除掉
  • 解除死锁:该方法与检测死锁配合使用

7、Object的公共方法

众所周知Java中所有的类都是继承于Object,所以我们编写的类默认都具有这些方法,包括有hashCode()wait()notify()notifyAll()equals()getClass()toString()clone()finalize()等。

  • hashCode()方法简单地说就是返回一个integer类型的值,这个值是通过该Object的内部地址(internal address)转换过来的,这个哈希码是可以通过getClass()方法看到具体值的,显示的是十六进制的数,有时候可以通过此方法来判断对象的引用是否相等。
  • wait()用于多线程中,使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。
  • notify用于唤醒在该对象上等待的某个线程,notifyAll()用于唤醒在该对象上等待的所有线程。
  • equals()用于判断这两个引用是否指向的是同一个对象。
  • getClass()用户获取该对象的运行时类的java.lang.Class 对象。
  • toString()方法返回一个字符串,它的值等于:getClass().getName()+ '@' + Integer.toHexString(hashCode())。
  • clone()保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
  • finalize()用于当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。子类重写finalize 方法,以配置系统资源或执行其他清除。

** ---- End ---- 暂时记录到这,后面不定时更新,欢迎关注。**


写在最后的话:个人能力有限,欢迎大家在下面吐槽。喜欢的话就为我点一个赞吧。也欢迎 Fork Me On Github 。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容