Long Luo's Life Notes

每一天都是奇迹

By LongLuo

在PC上,绝大部分软件都是Windows应用且闭源的,Linux系统只占了很小的份额,只有专业人士才会使用。随着移动互联网的到来,在智能手机系统中,Android由于开源免费的特性,已经占据了主要份额。当然iOS App由于闭源,且Apple软硬件一体,管控严格,体验更好,比如安全、动画流程、不卡顿等。

对于开发人员来说,最佳的学习方式莫过于开源项目了,我们可以学习到App的功能是如何实现的,提高我们自身的开发能力。我收集了一些最好的开源Android App项目,这些Apps可以作为很好的示例,帮助程序员们提高其Android开发技能。

下面就开始学习吧!

UI界面

FluentUI Android

微软开发的UI框架,用于在Android上Office App中实现统一的用户界面,从中可以学习如何构建UI部件及界面。

Source Code

QMUI Android

QMUI Android是腾讯开发的一个项目,设计目的是用于辅助快速搭建一个具备基本设计还原效果的Android项目,同时利用自身提供的丰富控件及兼容处理,让开发者能专注于业务需求而无需耗费精力在基础代码的设计上。不管是新项目的创建,或是已有项目的维护,均可使开发效率和项目质量得到大幅度提升。

官网:http://qmuiteam.com/android

Source Code

相机

Open Camera

一个全功能开源Android相机App,包括自动稳定、远程拍照等,如果想开发一款相机App,请学习这个项目!

Source Code

多媒体播放器

TimberX Music Player

一个全功能Android音乐播放器,遵循Material Design风格的用户界面,同时应用了最新的工具,包括Kotlin、组件、数据绑定等。

支持跨平台,可在手机、Android Wear、Android Auto、Chromecast和其他投射设备甚至谷歌助手上运行,如果你想编写一个音乐播放器以及适配各种设备,那这个App是最好不过的了!

官网:https://namand.in/

Source Code

Sound Recorder

一个Material Design风格的简易开源录音机App,可以学习到如何在Android中集成录音和操作功能。

Source Code

LeafPic

一个全功能相册App,如果想了解如何实现一个相册,请从这个开始!

Source Code

AntennaPod

一个播客App,你可以学习到如何开发一个播客App。

官网:https://www.antennapod.org/

Source Code

聊天

Telegram

Telegram是最常用的加密即时通讯App之一,适用于Android和iOS。如果想了解如何实现一个即时通信App,可以认真学习其源码!

Source Code

邮件客户端

K-9 Mail App

一个全功能电子邮件客户端,支持多帐户、多文件夹同步、标记、归档、BCC 自我、签名等等。
如果想了解电子邮件客户端的工作原理,开始动手写一个邮件客户端就从吃透这个项目源码开始吧!

官网地址:https://k9mail.app/

Source Code

阅读全文 »

By LongLuo

牛顿有句耳熟能详的名言:“如果我比别人看得远些,那是因为站在巨人肩上的缘故。” 对于每个程序员来说,都希望自己成为一名高手,升职加薪,迎娶白富美,出任CEO,走上人生巅峰。《劝学》里也说“君子生非异也,善假于物也”,告诫我们君子的本性和其他人没有什么不同,只不过是善于利用和借助客观工具, 善于借助外部系统的能量。大神也是从小白过来的,每个小白只要掌握正确的方法,坚持努力,也可以成为大神。

开源项目就是那个巨人,我们可以通过学习开源项目的源码,了解其设计思想,将其应用于我们自己的项目中,吃透其代码,不知不觉中我们的能力也会有大幅度提高。

个人收集了一些很好的Android开源项目,认真学习并掌握,可以大大提升我们的能力。

Android

Google Android开发者官方网站

不用说,Android开发官方权威网站,网站提供的示例和文档值得认真学习和阅读。

https://developer.android.google.cn/

Android Samples

Android官方提供的各种示例和实践,值得认真学习。

https://github.com/android

Android Source Code

在线阅读Android系统源码,提供Android源码的交叉索引,可以快速的搜索符合特定条件的Android源代码,后台是基于OpenGrok引擎,OpenGrok是一个快速,便于使用的源码搜索引擎与对照引擎,它能够帮助我们快速的搜索、定位、对照代码树。

http://androidxref.com/

Github Android Topics

Github 的Android Topics,可以查询到一些Android知名开源项目:

https://github.com/topics/android

Android开源项目汇总

Trinea收集的Android开源项目,内容非常丰富,大家可以各取所需,不过绝大部分偏重于App开发。

https://github.com/Trinea/android-open-project

大前端 跨平台开发

Flutter

官网:https://flutter.dev/

Source Code

架构

architecture-samples

https://github.com/android/architecture-samples

阅读全文 »

By Long Luo

Leetcode 232. 用栈实现队列 ,难度为Easy


  1. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push\texttt{push}pop\texttt{pop}peek\texttt{peek}empty\texttt{empty}):

实现MyQueue\texttt{MyQueue}类:

  • void push(int x)\texttt{void push(int x)}将元素xx推到队列的末尾
  • int pop()\texttt{int pop()}从队列的开头移除并返回元素
  • int peek()\texttt{int peek()}返回队列开头的元素
  • boolean empty()\texttt{boolean empty()}如果队列为空,返回true\textit{true};否则,返回false\textit{false}

说明:

你 只能 使用标准的栈操作 —— 也就是只有push to top, peek/pop from top, size, 和is empty操作是合法的。
你所使用的语言也许不支持栈。你可以使用list或者deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]

解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  • 1 <= x <= 9
  • 最多调用100100push\texttt{push}pop\texttt{pop}peek\texttt{peek}empty\texttt{empty}
    假设所有操作都是有效的 (例如,一个空的队列不会调用pop\texttt{pop}或者peek\texttt{peek}操作)

进阶:

你能否实现每个操作均摊时间复杂度为 O(1)O(1) 的队列?换句话说,执行 nn 个操作的总时间复杂度为 O(n)O(n),即使其中一个操作可能花费较长时间。


之前我们已经实现了 225. 用队列实现栈 ,今天我们来学习如何用队列来实现栈。

因为队列是FIFO,而栈是LIFO,所以我们需要用到两个栈,用其中一个来反转元素的入队顺序,而另一个则用来存储元素的最终顺序。

2个栈 (push - O(n), pop - O(1))

使用 22 个栈 stack1\textit{stack}_1stack2\textit{stack}_2stack1\textit{stack}_1 作为主栈,而 stack2\textit{stack}_2 是辅助栈。

入栈时:

  1. stack1\textit{stack}_1 中所有的元素移到 stack2\textit{stack}_2 中;
  2. stack2\textit{stack}_2 中压入新元素;
  3. stack2\textit{stack}_2 中所有的元素弹出,再把弹出的元素压入 stack1\textit{stack}_1

代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class MyQueue {
Stack<Integer> stack1;
Stack<Integer> stack2;

public MyQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}

public void push(int x) {
if (stack1.empty()) {
stack1.push(x);
return;
}

while (!stack1.empty()) {
stack2.push(stack1.pop());
}
stack2.push(x);
while (!stack2.empty()) {
stack1.push(stack2.pop());
}
}

public int pop() {
return stack1.pop();
}

public int peek() {
return stack1.peek();
}

public boolean empty() {
return stack1.empty() && stack2.empty();
}
}
阅读全文 »

By Long Luo

Leetcode 225. 用队列实现栈 ,难度为Easy


  1. 用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push\texttt{push}top\texttt{top}pop\texttt{pop}empty\texttt{empty})。

实现 MyStack\texttt{MyStack} 类:

  • void push(int x)\texttt{void push(int x)} 将元素 x\textit{x} 压入栈顶。
  • int pop()\texttt{int pop()} 移除并返回栈顶元素。
  • int top()\texttt{int top()} 返回栈顶元素。
  • boolean empty()\texttt{boolean empty()} 如果栈是空的,返回 true\textit{true};否则,返回 false\textit{false}

注意:

  • 你只能使用队列的基本操作 —— 也就是push to backpeek/pop from frontsizeis empty这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用list(列表)或者deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

提示:

  • 1 <= x <= 9
  • 最多调用 100100push\texttt{push}pop\texttt{pop}top\texttt{top}empty\texttt{empty}
  • 每次调用 pop\texttt{pop}top\texttt{top} 都保证栈不为空

进阶:你能否仅用一个队列来实现栈。


这道题考察的是队列两种数据结构知识。

栈是一种**后进先出(LIFO)**的数据结构,元素从顶端入栈,然后从顶端出栈。

队列是一种**先进先出(FIFO)**的数据结构,元素从后端入队,然后从前端出队。

2个队列

题目的要求是用 22 个队列实现一个栈,但是把一个队列中的数据导入另一个队列中,数据的顺序并没有发生改变,并不会变成先进后出的顺序。

那该如何做呢?

22 个队列 queue1\textit{queue}_1queue2\textit{queue}_2

  1. 11 个元素 A\textit{A},那非常简单,直接压入弹出即可;
  2. 22 个元素 A\textit{A}B\textit{B}queue1\textit{queue}_1 压入 AAqueue2\textit{queue}_2 压入 BB,然后将 queue1\textit{queue}_1 中元素压入 queue2\textit{queue}_2,这样 queue2\textit{queue}_2 中的元素顺序就是正确的;
  3. 因为 queue1\textit{queue}_1 是主队列,所以还需要将 queue2\textit{queue}_2 中元素重新导入到 queue1\textit{queue}_1

代码如下所示:

阅读全文 »
0%