有Java基础的人怎么学Android原生开发——一个20年后端程序员的26个类

有Java基础的人怎么学Android原生开发------一个20年后端程序员的26个类

文章目录

一、前提:你有基础,只是没碰过Android

我说的是这种情况:Java写了十年以上,知道反射、泛型、设计模式,写过前后端、数据库、工作流。但从来没打开过 Android Studio。有一天你决定------学一下Android。

你和零基础的人最大的区别不是"学得快",而是你能判断什么东西是重要的,什么东西以后能查到

零基础的人看到 onCreate 要背下来。你看到 onCreate 会想------这就是一个构造回调,生命周期的一部分,我的初始化逻辑放这里就行。零基础的人在记API,你在建认知框架

我的认知框架是什么?就是这张图:

二、一张图:先理解Android跟你熟悉的Java有什么不同

你熟悉的(后端Java) Android的对应 关键差异
JVM上跑,程序不挂就一直运行 Dalvik/ART上跑,Activity随时可能被杀 生命周期是核心,不是边缘情况
请求-响应,短暂持有状态 用户在界面间跳转,状态要持久化 SharedPreferences、SQLite、onSaveInstanceState
数据库直连,想开几个连接就开 SQLite是嵌入式,文件就在手机里 没有网络开销,但有并发限制
RPC调用、消息队列 Intent显式/隐式跳转 Intent就是Android的IPC和路由
多线程、ExecutorService AsyncTask(已废弃)/Handler/Service 不许在非UI线程操作UI
配置文件 + 数据库配置 AndroidManifest.xml 四大组件必须在这声明
部署用Tomcat启动 打包APK,系统发广播,四大组件响应 你的代码是被"调用"的,不是一直跑的

这张图清楚了,学Android就是填每一行的细节,而不是重新建一个认知体系。

三、我是怎么学的:一个项目覆盖所有核心概念

我建了一个项目叫 ActivityTest,26个Java类,12个Activity,每个Activity练一个概念。不是照着教程抄,是自己设计场景,把概念用出来

Activity 生命周期 --- 最核心的概念

Android的Activity不像Servlet------Servlet随请求创建和销毁,Activity是在"可见"和"不可见"之间反复切换。用户切到桌面、接了个电话、旋转了屏幕------你的Activity可能被回收。

我写了一个 BaseAcitvity(注意拼写,这是我学习路上真实的痕迹),让所有Activity继承它:

java 复制代码
public class BaseAcitvity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityContain.addActivity(this);  // 自己维护一个Activity栈
        Log.d("BaseActivity", getClass().getSimpleName() + " onCreate");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityContain.removeActivity(this);
    }
}

这个维护Activity栈的做法,是典型的"后端思维"------我想知道当前有哪些Activity活着,要能一键关掉全部。后来我知道 Android Jetpack 有 ActivityLifecycleCallbacks 可以做同样的事,但自己写一遍,理解了它为什么存在。

Intent --- Android的URL路由

后端开发习惯了 @RequestMapping("/user/save") 做URL路由。Android的路由机制叫 Intent。

显式Intent就是直接指定目标类(相当于内部方法调用)。更关键的是隐式Intent:

java 复制代码
// 打开百度网页
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);

// 拨打电话
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);

你不需要知道"谁来处理这个请求"------Android系统会找能打开的Activity。这就是"隐式路由"。

我在 SecondActivity 上还自定义了一个隐式Intent:

xml 复制代码
<intent-filter>
    <action android:name="com.browise.activitytest.ACTION_START" />
    <category android:name="com.browise.activitytest.MY_CATEGORY" />
</intent-filter>

别的应用知道了这个action,就能调起我。这让我想到------Android的IPC本质上就是一个注册+查找+调用的机制,只不过注册通过Manifest,查找通过Intent匹配,调用通过startActivity。

BroadcastReceiver --- Android的事件总线

后端里我们有消息队列、事件总线、配置中心。Android里同样的概念叫 BroadcastReceiver。

系统发出的广播(开机完成、网络变化、电量低)和自定义广播(会话过期、强制下线)都用同样的机制接收。静态注册通过Manifest,动态注册写代码:

java 复制代码
// 动态注册网络变化监听
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver, intentFilter);

我写了一个"强制下线"的场景------发一条自定义广播,接收后关闭所有Activity,跳回登录页:

java 复制代码
public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        ActivityContain.finishAll();  // 关掉当前所有Activity
        Intent i = new Intent(context, LoginActivity.class);
        context.startActivity(i);
    }
}

理解了BroadcastReceiver,就看懂了Android的BootReceiver(开机自启动服务)、AlarmReceiver(定时任务)、PushReceiver(推送通知)------它们的本质都是"接收广播→做动作"。

Service --- 后台任务守护

后端的后台任务靠挂一个JVM进程,Android里靠Service。Service有两种:启动型(startService)和绑定型(bindService)。前者适合"下载文件"这种相对独立的操作,后者适合"音乐播放器"这种需要交互的操作。

我的 DownLoadService 是一个绑定型服务,支持断点续传。核心做法是在HTTP请求里加 Range 头:

java 复制代码
connection.setRequestProperty("Range", "bytes=" + downloadedLength + "-");

然后 RandomAccessFile.seek(downloadedLength) 把写指针移到已有文件末尾。服务关掉后重连,从上次断掉的位置继续。这个思路和后端的断点续传是一样的------只是后端用消息队列做进度通知,Android用 Notification + Handler

SQLite --- 没有网络开销的数据库

后端数据库是远程的、多连接的、有连接池的。Android的SQLite是文件级的、本地的、单连接的。操作方式封在 SQLiteOpenHelper 里:

java 复制代码
public class MySqLiteOpenHelper extends SQLiteOpenHelper {
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table Book(id integer primary key autoincrement, name text, ...)");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table if exists Book");
        onCreate(db);
    }
}

onUpgrade 这行 drop table 让我有一种"果然如此"的感觉------这是一个学习项目,数据库升级直接删表重建。但它的机制(数据库版本号触发onUpgrade)让我联想到后端Liquibase/Flyway------理念是一样的,只是粒度不同。

ContentResolver --- 读写联系人不需要权限?

Android规定应用之间不能直接互相访问数据。要读通讯录,不能用JDBC、不能用文件IO,只能用 ContentResolver

java 复制代码
Cursor cursor = getContentResolver().query(
    ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null
);
while (cursor.moveToNext()) {
    String name = cursor.getString(cursor.getColumnIndex(
        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
    String number = cursor.getString(cursor.getColumnIndex(
        ContactsContract.CommonDataKinds.Phone.NUMBER));
}

这完全不是后端的思维方式------后端你想查数据库就 select * from contacts。Android在中间拦了一道,用ContentProvider把数据包了一层。理解了这个,对Android的权限模型就有了底。

运行时权限 --- 为什么打电话要弹窗

Android 6.0以后,危险权限(通讯录、电话、定位、存储)需要在运行时弹窗请求,用户点"允许"才能用。后端开发从来没有这个概念------后端权限是角色认证、接口鉴权。

java 复制代码
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
        != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
        new String[]{Manifest.permission.CALL_PHONE}, 1);
} else {
    call(); // 已经有权限,直接打
}

这个模式用了几次就记住了------先检查是否已有权限,没有就申请,申请结果在 onRequestPermissionsResult 里处理。

自定义控件 --- 封装可重用的View

后端封装组件靠类和方法。Android封装UI靠自定义View。我的 TitleLayout 就是一个自定义标题栏------继承 LinearLayout,在构造函数里 inflate 布局,在代码里处理按钮事件。任何一个Activity想用这个标题栏,一行 <include layout="@layout/title"/> 就行。

这不就是前端组件化的思想吗?只是Android比Vue/React早了很多年。

剩下的概念,接触了就知道

  • ListView + ViewHolder :列表复用的标准写法,convertView == null 时才 inflate,tag存引用
  • AlertDialog / ProgressDialog:系统弹窗
  • Thread + Handler:非UI线程更新UI的标准套路
  • AsyncTask替代 :自己封装 ExecutorService + Handler 搞了一套后台任务框架
  • 通知(Notification)NotificationManager.notify(),带 PendingIntent 做点击跳转

这些不是要背下来,是用到了知道去哪找

四、这个项目能证明什么

26个Java类,12个Activity,做完之后我知道:

  • 给我一个需求,我能画出Activity跳转关系图------哪些是显式跳转、哪些用隐式Intent
  • 需要后台跑了,我知道什么时候用Service什么时候用线程+Handler
  • 读写数据了我能判断是存SharedPreferences、SQLite还是文件
  • 系统发广播了我知道怎么注册、怎么拦截、怎么响应
  • 权限不够我知道要申请、知道申请结果在哪处理

不熟练的地方是有的------比如动画、自定义View测量、多点触摸、NDK。但这些不是常态需求。Android原生的核心概念,这个项目已经全部走了一遍。

五、结语

有Java基础的人学Android原生开发,不是从零开始,是从80分开始。你要补的不是编程基础,是Android这个平台特有的概念和机制------Activity生命周期、Intent路由、Service守护、Broadcast通信、ContentProvider数据共享、运行时权限、SQLite嵌入式数据库。这些概念用一个完备的练习项目全部走一遍,比看十本书都管用。

剩下的不熟练只是练得少。多做几个界面、多填几个生命周期回调日志、多看几次 onStoponDestroy 的打印------慢慢就内化了。

如果你也是Java后端想学Android:不要看文档,写一个项目。一个项目踏完所有基础概念,从此以后查什么都有方向。