Android点将台:颜值担当[-Activity-]

//点击时
id_btn_for_result.setOnClickListener {
val intent = Intent(this, ToActivity::class.java)
startActivityForResult(intent, DATA_CODE)
}
//回调
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
when (requestCode) {
DATA_CODE -> if (resultCode == Activity.RESULT_OK) {
val dataFormTarget = data.getStringExtra(“data”)
val personData = data.getBundleExtra(“To”)
val person = personData.get(“person”) as Person
id_tv_result_back.text = (“dataFormTarget:” + dataFormTarget

  • “\nperson:” + person.toString())
    }
    }
    }

---->[ToActivity传递数据给FromActivity]-----------
private fun backWithData() {
val jt = Person(“捷特”, 24)
val intent = Intent()
intent.putExtra(“data”, “我是ToActivity的数据”)
val bundle = Bundle()
bundle.putSerializable(“person”, jt)
intent.putExtra(“To”, bundle)
setResult(Activity.RESULT_OK, intent)
}


4.打开图库并设置图片

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

//点击图片
id_iv_icon.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK)
intent.type = “image/*”;
startActivityForResult(intent, 0)
}

//处理结果
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 0 && resultCode == Activity.RESULT_OK) {//成功
val selectedImage = data?.data ?: return
val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
val cursor = contentResolver.query(// 获取选择照片的数据视图
selectedImage, filePathColumn, null, null, null
)
cursor.moveToFirst()
// 从数据视图中获取已选择图片的路径
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
val picturePath = cursor.getString(columnIndex)
cursor.close()
id_iv_icon.setImageBitmap(BitmapFactory.decodeFile(picturePath))
}
}


三、Activity的四种启动模式

Activity任务栈:Activity的活动序列

standard:标准栈
singleTop:顶复用栈
singleTask:对象唯一栈
singleInstance:单独实例栈


1.standard: 标准栈

当启动一个Activity,创建该Activity的新实例。入栈处于栈顶
测试:Activity1、2皆为standard

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

依次打开Activity1、2、2、1、2
E/TASK_ID: Activity1 Task id is 89
E/TASK_ID: Activity2 Task id is 89
E/TASK_ID: Activity2 Task id is 89
E/TASK_ID: Activity1 Task id is 89
E/TASK_ID: Activity2 Task id is 89
依次返回
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁


2:singleTop模式:顶复用栈

在启动活动时若栈顶已经是该Activity,则直接使用它,不创建实例
测试:Activity1为standard, Activity2 为singleTop

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

依次打开Activity1、2、2、1、2
E/TASK_ID: Activity1 Task id is 82
E/TASK_ID: Activity2 Task id is 82
E/TASK_ID: Activity1 Task id is 82
E/TASK_ID: Activity2 Task id is 82
依次返回
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁


3:singleTask模式:对象唯一栈

整个栈中没有相同的实例,两次相同实例之间的Activity会被杀死(够霸道,我喜欢)
测试:Activity1为standard, Activity2 为singleTask

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

依次打开Activity1、2、2、1、2
E/TASK_ID: Activity1 Task id is 94
E/TASK_ID: Activity2 Task id is 94
E/TASK_ID: Activity1 Task id is 94
E/TASK_ID: Activity1 销毁
依次返回
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁


4:singleInstance 单独实例栈

启用一个新的活动栈来管理这个活动(够豪,够任性)
测试:Activity1为standard, Activity2 singleInstance

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

依次打开Activity1、2、2、1、2
E/TASK_ID: Activity1 Task id is 115
E/TASK_ID: Activity2 Task id is 116
E/TASK_ID: Activity1 Task id is 115
依次返回
E/TASK_ID: Activity2 销毁
E/TASK_ID: Activity1 销毁
E/TASK_ID: Activity1 销毁


注意一点:
singleTask模式和singleTop模式时,非第一次启动,不会调用onCreate方法!
但会走onNewIntent方法


四、Activity的跳转动画

这里只是简单的四个平移动画,需要的更酷炫的效果道理是一样的
关于动画的更多知识,这里不废话了,可详见:Android 动画 Animator 家族使用指南

默认修改
)

|

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

|


1.代码实现Activity跳转

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

/**

  • 作者:张风捷特烈
  • 时间:2019/1/20/020:18:25
  • 邮箱:1981462002@qq.com
  • 说明:红色Activity
    */
    class RedActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val view = View(this)
    view.setBackgroundColor(Color.RED)
    title = “RedActivity”
    view.setOnClickListener { v ->
    startActivity(Intent(this, BlueActivity::class.java))
    overridePendingTransition(R.anim.open_enter, R.anim.open_exit);
    }
    setContentView(view)
    }
    override fun onBackPressed() {
    super.onBackPressed()
    overridePendingTransition(R.anim.open_enter, R.anim.open_exit);
    }
    }

/**

  • 作者:张风捷特烈
  • 时间:2019/1/20/020:18:25
  • 邮箱:1981462002@qq.com
  • 说明:绿色Activity
    */
    class BlueActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val view = View(this)
    view.setBackgroundColor(Color.BLUE)
    title = “BlueActivity”
    view.setOnClickListener { v ->
    startActivity(Intent(this, RedActivity::class.java))
    overridePendingTransition(R.anim.close_enter, R.anim.close_exit)
    }
    setContentView(view)
    }
    override fun onBackPressed() {
    super.onBackPressed()//右移入—右移出
    overridePendingTransition(R.anim.close_enter, R.anim.close_exit)
    }
    }

2.跳转动画

---->[open_enter.xml]----------------------

<?xml version="1.0" encoding="utf-8"?>


---->[open_exit.xml]----------------------

<?xml version="1.0" encoding="utf-8"?>


---->[close_enter.xml----------------------

<?xml version="1.0" encoding="utf-8"?>


---->[close_exit.xml]----------------------

<?xml version="1.0" encoding="utf-8"?>


这样就可以了


3.另外还可以配置动画的style

用起来比在代码里方便些


五、Acticity的启动源码分析

一直想总结一下Activity的启动流程(),这里从Activity的生命周期入手
本文所讲述的启动流程主要是ActivityThread的H在接收到消息之后,即handleMessage
至于消息如何传递过来的将在跨进程通信篇讲述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


1.谁是幕后黑手?

翻一下源码可以看出Context只是一个抽象类,定义了很多抽象方法
而ContextWrapper作为实现类将所有的工作甩手给了一个mBase的Context成员变量
ContextThemeWrapper寥寥百行代码,也不会是幕后黑手,现在台面上只有mBase

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


2.Activity是如何创建的?

相信应该没有人去new Activity(),framework 层是如何创建Activity的实例呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

---->[ActivityThread]-------
final H mH = new H();

---->[ActivityThread$H#handleMessage]-------
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {//启动Activity
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityStart”);
//r:记录Activity的一些描述信息
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
//通过r来获取包信息
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
//开启的核心方法(划重点)
handleLaunchActivity(r, null, “LAUNCH_ACTIVITY”);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

---->[ActivityThread#handleLaunchActivity]-------
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
//在这里返回来Activity的对象
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations®;
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
//略…
}

---->[ActivityThread#performLaunchActivity]-------
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//略…
ComponentName component = r.intent.getComponent();
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//此处可见是mInstrumentation创建的Activity
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
//略…
return activity;
}

---->[Instrumentation#newActivity]-------
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
//通过类加载器生成Activity实例
return (Activity)cl.loadClass(className).newInstance();
}


3.Application实例化及onCreate()方法调用

实现移到刚才创建Activity的performLaunchActivity方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

---->[ActivityThread#performLaunchActivity]-------
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//略…
ComponentName component = r.intent.getComponent();
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
//略…
try {
//创建Activity之后通过ActivityClientRecord的packageInfo对象的makeApplication
//来创建Application,packageInfo是一个LoadedApk类的对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//略…
}

---->[LoadedApk#makeApplication]-------
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
//略…

try {
java.lang.ClassLoader cl = getClassLoader();
//略…
//这里ContextImpl出场了
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//这里通过mInstrumentation的newApplication方法创建Application对象
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
//将创建的Application设置到appContext上
appContext.setOuterContext(app);
}
//略…
//mActivityThread将当前app加入mAllApplications列表中
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
//这时调用application的OnCreate方法
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!instrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()

  • ": " + e.toString(), e);
    }
    }
    }
    return app;
    }

---->[Instrumentation#newApplication]-------
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
//也是通过反射获取Application实例
return newApplication(cl.loadClass(className), context);
}

---->[Instrumentation#callApplicationOnCreate]-------
public void callApplicationOnCreate(Application app) {
app.onCreate();//直接调用onCreate onCreate
}


4.Activity的Context的创建及onCreate()方法的调用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

---->[ActivityThread#performLaunchActivity]-------
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
//Activity的一些配置信息
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "

  • r.activityInfo.name + " with config " + config);
    Window window = null;
    if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
    window = r.mPendingRemoveWindow;
    r.mPendingRemoveWindow = null;
    r.mPendingRemoveWindowManager = null;
    }
    //将Activity和window绑定
    activity.attach(appContext, this, getInstrumentation(), r.token,
    r.ident, app, r.intent, r.activityInfo, title, r.parent,
    r.embeddedID, r.lastNonConfigurationInstances, config,
    r.referrer, r.voiceInteractor, window);

if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}

activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}

---->[ActivityThread#createBaseContextForActivity]-------
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
//略…
//看这里appContext是ContextImpl类对象,Activity的Context幕后黑手出现了
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;

final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity’s package name contains the value of
// the “debug.use-second-display” system property as a substring, then show
// its content on a secondary display if there is one.
String pkgName = SystemProperties.get(“debug.second-display.pkg”);
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int id : dm.getDisplayIds()) {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
baseContext = appContext.createDisplayContext(display);
break;
}
}
}
return baseContext;
}

---->[ContextImpl#createActivityContext]-------
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException(“packageInfo”);
return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
null, overrideConfiguration, displayId);
}

---->[Instrumentation#callActivityOnCreate]-------
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}

---->[Activity#performCreate]-------
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle, persistentState);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}

---->[Activity#attach]-----------------
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);

mFragments.attachHost(null /parent/);
//这里的Window实现类是PhoneWindow
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();

mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}

mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}


5.Activity的布局加载

setContentView我们再熟悉不过了,看一下Activity源码是如何加载的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

---->[Activity#setContentView]-----------------
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}

//可见是通过Window的setContentView来加载布局的,
//通过attach方法知道这个window对象是PhoneWindow类

---->[PhoneWindow#setContentView]-----------------
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();//初始化DecorView
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
mContentParent.addView(view, params);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}

---->[PhoneWindow#installDecor]-----------------
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
//通过DecorView来创建mContentParent
mContentParent = generateLayout(mDecor);
//对mDecor进行处理,略…

---->[PhoneWindow#generateDecor]-----------------
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}

DecorView何许人也?
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker
可见是一个帧布局FrameLayout,最顶层的视图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


6.Activity的onResume和onRestart方法的回调

onCreate分析了,onResume基本是差不多,还是在H类中的
handleMessage中处理信息,当标识为RESUME_ACTIVITY时,调用handleResumeActivity

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

---->[ActivityThread#handleMessage]-------
case RESUME_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityResume”);
SomeArgs args = (SomeArgs) msg.obj;
handleResumeActivity((IBinder) args.arg1, true, args.argi1 != 0, true,
args.argi3, “RESUME_ACTIVITY”);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

---->[ActivityThread#handleResumeActivity]-------
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (!checkAndUpdateLifecycleSeq(seq, r, “resumeActivity”)) {
return;
}

// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;

// TODO Push resumeArgs into the activity for consideration
r = performResumeActivity(token, clearHide, reason);

---->[ActivityThread#performResumeActivity]-------
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide, String reason) {
ActivityClientRecord r = mActivities.get(token);
//略…
r.activity.performResume();

---->[Activity#performResume]-------
final void performResume() {
performRestart();//可见是先调用了Restart方法
mFragments.execPendingActions();
mLastNonConfigurationInstances = null;
mCalled = false;
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
if (!mCalled) {

---->[Activity#performRestart]-------
final void performRestart() {
//略…
mInstrumentation.callActivityOnRestart(this);
//又看到老朋友mInstrumentation了,
//可以看到Activity的生命周期由mInstrumentation全权负责
//就连调用本类的一个onRestart方法都要mInstrumentation来转手

---->[Instrumentation#callActivityOnRestart]-------
public void callActivityOnRestart(Activity activity) {
activity.onRestart();
}

---->[Instrumentation#callActivityOnResume]-------
public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
activity.onResume();

if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
am.match(activity, activity, activity.getIntent());
}
}

文末

初级工程师拿到需求会直接开始做,然后做着做着发现有问题了,要么技术实现不了,要么逻辑有问题。

而高级工程师拿到需求会考虑很多,技术的可行性?对现有业务有没有帮助?对现有技术架构的影响?扩展性如何?等等…之后才会再进行设计编码阶段。

而现在随着跨平台开发,混合式开发,前端开发之类的热门,Android开发者需要学习和掌握的技术也在不断的增加。

通过和一些行业里的朋友交流讨论,以及参考现在大厂面试的要求。我们花了差不多一个月时间整理出了这份Android高级工程师需要掌握的所有知识体系。你可以看下掌握了多少。

混合式开发,微信小程序。都是得学会并且熟练的

这些是Android相关技术的内核,还有Java进阶

高级进阶必备的一些技术。像移动开发架构项目实战等

Android前沿技术;包括了组件化,热升级和热修复,以及各种架构跟框架的详细技术体系

以上即是我们整理的Android高级工程师需要掌握的技术体系了。可能很多朋友觉得很多技术自己都会了,只是一些新的技术不清楚而已。应该没什么太大的问题。

而这恰恰是问题所在!为什么别人高级工程师能年限突破30万,而你只有十几万呢?

就因为你只需补充你自己认为需要的,但并不知道企业需要的。这个就特别容易造成差距。因为你的技术体系并不系统,是零碎的,散乱的。那么你凭什么突破30万年薪呢?

我这些话比较直接,可能会戳到一些人的玻璃心,但是我知道肯定会对一些人起到点醒的效果的。而但凡只要有人因为我的这份高级系统大纲以及这些话找到了方向,并且付出行动去提升自我,为了成功变得更加努力。那么我做的这些就都有了意义。

喜欢的话请帮忙转发点赞一下能让更多有需要的人看到吧。谢谢!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

通过和一些行业里的朋友交流讨论,以及参考现在大厂面试的要求。我们花了差不多一个月时间整理出了这份Android高级工程师需要掌握的所有知识体系。你可以看下掌握了多少。

混合式开发,微信小程序。都是得学会并且熟练的

[外链图片转存中…(img-VRH5dMYn-1714745124987)]

这些是Android相关技术的内核,还有Java进阶

[外链图片转存中…(img-civX5srZ-1714745124988)]

高级进阶必备的一些技术。像移动开发架构项目实战等

[外链图片转存中…(img-QYBxH9rn-1714745124989)]

Android前沿技术;包括了组件化,热升级和热修复,以及各种架构跟框架的详细技术体系

[外链图片转存中…(img-bH9feuyr-1714745124990)]

以上即是我们整理的Android高级工程师需要掌握的技术体系了。可能很多朋友觉得很多技术自己都会了,只是一些新的技术不清楚而已。应该没什么太大的问题。

而这恰恰是问题所在!为什么别人高级工程师能年限突破30万,而你只有十几万呢?

就因为你只需补充你自己认为需要的,但并不知道企业需要的。这个就特别容易造成差距。因为你的技术体系并不系统,是零碎的,散乱的。那么你凭什么突破30万年薪呢?

我这些话比较直接,可能会戳到一些人的玻璃心,但是我知道肯定会对一些人起到点醒的效果的。而但凡只要有人因为我的这份高级系统大纲以及这些话找到了方向,并且付出行动去提升自我,为了成功变得更加努力。那么我做的这些就都有了意义。

喜欢的话请帮忙转发点赞一下能让更多有需要的人看到吧。谢谢!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值