Android应用程序启动过程源代码分析(3)

简介:

       Step 16. ActivityThread.handlePauseActivity

        这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

 
 
  1. public final class ActivityThread {   
  2.        
  3.     ......   
  4.    
  5.     private final void handlePauseActivity(IBinder token, boolean finished,   
  6.             boolean userLeaving, int configChanges) {   
  7.    
  8.         ActivityClientRecord r = mActivities.get(token);   
  9.         if (r != null) {   
  10.             //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);   
  11.             if (userLeaving) {   
  12.                 performUserLeavingActivity(r);   
  13.             }   
  14.    
  15.             r.activity.mConfigChangeFlags |= configChanges;   
  16.             Bundle state = performPauseActivity(token, finished, true);   
  17.    
  18.             // Make sure any pending writes are now committed.   
  19.             QueuedWork.waitToFinish();   
  20.    
  21.             // Tell the activity manager we have paused.   
  22.             try {   
  23.                 ActivityManagerNative.getDefault().activityPaused(token, state);   
  24.             } catch (RemoteException ex) {   
  25.             }   
  26.         }   
  27.     }   
  28.    
  29.     ......   
  30.    
  31. }   

         函数首先将Binder引用token转换成ActivityRecord的远程接口ActivityClientRecord,然后做了三个事情:1. 如果userLeaving为true,则通过调用performUserLeavingActivity函数来调用Activity.onUserLeaveHint通知Activity,用户要离开它了;2. 调用performPauseActivity函数来调用Activity.onPause函数,我们知道,在Activity的生命周期中,当它要让位于其它的Activity时,系统就会调用它的onPause函数;3. 它通知ActivityManagerService,这个Activity已经进入Paused状态了,ActivityManagerService现在可以完成未竟的事情,即启动MainActivity了

        Step 17. ActivityManagerProxy.activityPaused

        这个函数定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

 
 
  1. class ActivityManagerProxy implements IActivityManager   
  2. {   
  3.     ......   
  4.    
  5.     public void activityPaused(IBinder token, Bundle state) throws RemoteException   
  6.     {   
  7.         Parcel data = Parcel.obtain();   
  8.         Parcel reply = Parcel.obtain();   
  9.         data.writeInterfaceToken(IActivityManager.descriptor);   
  10.         data.writeStrongBinder(token);   
  11.         data.writeBundle(state);   
  12.         mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);   
  13.         reply.readException();   
  14.         data.recycle();   
  15.         reply.recycle();   
  16.     }   
  17.    
  18.     ......   
  19.    
  20. }   

        这里通过Binder进程间通信机制就进入到ActivityManagerService.activityPaused函数中去了。

        Step 18. ActivityManagerService.activityPaused

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

 
 
  1. public final class ActivityManagerService extends ActivityManagerNative   
  2.             implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {   
  3.     ......   
  4.    
  5.     public final void activityPaused(IBinder token, Bundle icicle) {   
  6.            
  7.         ......   
  8.    
  9.         final long origId = Binder.clearCallingIdentity();   
  10.         mMainStack.activityPaused(token, icicle, false);   
  11.            
  12.         ......   
  13.     }   
  14.    
  15.     ......   
  16.    
  17. }   

       这里,又再次进入到ActivityStack类中,执行activityPaused函数。       Step 19. ActivityStack.activityPaused

       这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

 
 
  1. public class ActivityStack {   
  2.    
  3.     ......   
  4.    
  5.     final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {   
  6.            
  7.         ......   
  8.    
  9.         ActivityRecord r = null;   
  10.    
  11.         synchronized (mService) {   
  12.             int index = indexOfTokenLocked(token);   
  13.             if (index >= 0) {   
  14.                 r = (ActivityRecord)mHistory.get(index);   
  15.                 if (!timeout) {   
  16.                     r.icicle = icicle;   
  17.                     r.haveState = true;   
  18.                 }   
  19.                 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);   
  20.                 if (mPausingActivity == r) {   
  21.                     r.state = ActivityState.PAUSED;   
  22.                     completePauseLocked();   
  23.                 } else {   
  24.                     ......   
  25.                 }   
  26.             }   
  27.         }   
  28.     }   
  29.    
  30.     ......   
  31.    
  32. }   

       这里通过参数token在mHistory列表中得到ActivityRecord,从上面我们知道,这个ActivityRecord代表的是Launcher这个Activity,而我们在Step 11中,把Launcher这个Activity的信息保存在mPausingActivity中,因此,这里mPausingActivity等于r,于是,执行completePauseLocked操作。

       Step 20. ActivityStack.completePauseLocked

       这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

 
 
  1. public class ActivityStack {   
  2.    
  3.     ......   
  4.    
  5.     private final void completePauseLocked() {   
  6.         ActivityRecord prev = mPausingActivity;   
  7.            
  8.         ......   
  9.    
  10.         if (prev != null) {   
  11.    
  12.             ......   
  13.    
  14.             mPausingActivity = null;   
  15.         }   
  16.    
  17.         if (!mService.mSleeping && !mService.mShuttingDown) {   
  18.             resumeTopActivityLocked(prev);   
  19.         } else {   
  20.             ......   
  21.         }   
  22.    
  23.         ......   
  24.     }   
  25.    
  26.     ......   
  27.    
  28. }   

 

        函数首先把mPausingActivity变量清空,因为现在不需要它了,然后调用resumeTopActivityLokced进一步操作,它传入的参数即为代表Launcher这个Activity的ActivityRecord。

        Step 21. ActivityStack.resumeTopActivityLokced
        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

 
 
  1. public class ActivityStack {   
  2.    
  3.     ......   
  4.    
  5.     final boolean resumeTopActivityLocked(ActivityRecord prev) {   
  6.         ......   
  7.    
  8.         // Find the first activity that is not finishing.   
  9.         ActivityRecord next = topRunningActivityLocked(null);   
  10.    
  11.         // Remember how we'll process this pause/resume situation, and ensure   
  12.         // that the state is reset however we wind up proceeding.   
  13.         final boolean userLeaving = mUserLeaving;   
  14.         mUserLeaving = false;   
  15.    
  16.         ......   
  17.    
  18.         next.delayedResume = false;   
  19.    
  20.         // If the top activity is the resumed one, nothing to do.   
  21.         if (mResumedActivity == next && next.state == ActivityState.RESUMED) {   
  22.             ......   
  23.             return false;   
  24.         }   
  25.    
  26.         // If we are sleeping, and there is no resumed activity, and the top   
  27.         // activity is paused, well that is the state we want.   
  28.         if ((mService.mSleeping || mService.mShuttingDown)   
  29.             && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {   
  30.             ......   
  31.             return false;   
  32.         }   
  33.    
  34.         .......   
  35.    
  36.    
  37.         // We need to start pausing the current activity so the top one   
  38.         // can be resumed...   
  39.         if (mResumedActivity != null) {   
  40.             ......   
  41.             return true;   
  42.         }   
  43.    
  44.         ......   
  45.    
  46.    
  47.         if (next.app != null && next.app.thread != null) {   
  48.             ......   
  49.    
  50.         } else {   
  51.             ......   
  52.             startSpecificActivityLocked(next, truetrue);   
  53.         }   
  54.    
  55.         return true;   
  56.     }   
  57.    
  58.    
  59.     ......   
  60.    
  61. }   

 

        通过上面的Step 9,我们知道,当前在堆栈顶端的Activity为我们即将要启动的MainActivity,这里通过调用topRunningActivityLocked将它取回来,保存在next变量中。之前最后一个Resumed状态的Activity,即Launcher,到了这里已经处于Paused状态了,因此,mResumedActivity为null。最后一个处于Paused状态的Activity为Launcher,因此,这里的mLastPausedActivity就为Launcher。前面我们为MainActivity创建了ActivityRecord后,它的app域一直保持为null。有了这些信息后,上面这段代码就容易理解了,它最终调用startSpecificActivityLocked进行下一步操作。

       Step 22. ActivityStack.startSpecificActivityLocked
       这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

 
 
  1. public class ActivityStack {   
  2.    
  3.     ......   
  4.    
  5.     private final void startSpecificActivityLocked(ActivityRecord r,   
  6.             boolean andResume, boolean checkConfig) {   
  7.         // Is this activity's application already running?   
  8.         ProcessRecord app = mService.getProcessRecordLocked(r.processName,   
  9.             r.info.applicationInfo.uid);   
  10.    
  11.         ......   
  12.    
  13.         if (app != null && app.thread != null) {   
  14.             try {   
  15.                 realStartActivityLocked(r, app, andResume, checkConfig);   
  16.                 return;   
  17.             } catch (RemoteException e) {   
  18.                 ......   
  19.             }   
  20.         }   
  21.    
  22.         mService.startProcessLocked(r.processName, r.info.applicationInfo, true0,   
  23.             "activity", r.intent.getComponent(), false);   
  24.     }   
  25.    
  26.    
  27.     ......   
  28.    
  29. }   

 

       注意,这里由于是第一次启动应用程序的Activity,所以下面语句:

 
 
  1. ProcessRecord app = mService.getProcessRecordLocked(r.processName,   
  2.     r.info.applicationInfo.uid);   

        取回来的app为null。在Activity应用程序中的AndroidManifest.xml配置文件中,我们没有指定Application标签的process属性,系统就会默认使用package的名称,这里就是"shy.luo.activity"了。每一个应用程序都有自己的uid,因此,这里uid + process的组合就可以为每一个应用程序创建一个ProcessRecord。当然,我们可以配置两个应用程序具有相同的uid和package,或者在AndroidManifest.xml配置文件的application标签或者activity标签中显式指定相同的process属性值,这样,不同的应用程序也可以在同一个进程中启动。

       函数最终执行ActivityManagerService.startProcessLocked函数进行下一步操作。

       Step 23. ActivityManagerService.startProcessLocked

       这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

 
 
  1. public final class ActivityManagerService extends ActivityManagerNative   
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {   
  3.    
  4.     ......   
  5.    
  6.     final ProcessRecord startProcessLocked(String processName,   
  7.             ApplicationInfo info, boolean knownToBeDead, int intentFlags,   
  8.             String hostingType, ComponentName hostingName, boolean allowWhileBooting) {   
  9.    
  10.         ProcessRecord app = getProcessRecordLocked(processName, info.uid);   
  11.            
  12.         ......   
  13.    
  14.         String hostingNameStr = hostingName != null   
  15.             ? hostingName.flattenToShortString() : null;   
  16.    
  17.         ......   
  18.    
  19.         if (app == null) {   
  20.             app = new ProcessRecordLocked(null, info, processName);   
  21.             mProcessNames.put(processName, info.uid, app);   
  22.         } else {   
  23.             // If this is a new package in the process, add the package to the list   
  24.             app.addPackage(info.packageName);   
  25.         }   
  26.    
  27.         ......   
  28.    
  29.         startProcessLocked(app, hostingType, hostingNameStr);   
  30.         return (app.pid != 0) ? app : null;   
  31.     }   
  32.    
  33.     ......   
  34.    
  35. }   

 

        这里再次检查是否已经有以process + uid命名的进程存在,在我们这个情景中,返回值app为null,因此,后面会创建一个ProcessRecord,并存保存在成员变量mProcessNames中,最后,调用另一个startProcessLocked函数进一步操作:

 
 
  1. public final class ActivityManagerService extends ActivityManagerNative   
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {   
  3.    
  4.     ......   
  5.    
  6.     private final void startProcessLocked(ProcessRecord app,   
  7.                 String hostingType, String hostingNameStr) {   
  8.    
  9.         ......   
  10.    
  11.         try {   
  12.             int uid = app.info.uid;   
  13.             int[] gids = null;   
  14.             try {   
  15.                 gids = mContext.getPackageManager().getPackageGids(   
  16.                     app.info.packageName);   
  17.             } catch (PackageManager.NameNotFoundException e) {   
  18.                 ......   
  19.             }   
  20.                
  21.             ......   
  22.    
  23.             int debugFlags = 0;   
  24.                
  25.             ......   
  26.                
  27.             int pid = Process.start("android.app.ActivityThread",   
  28.                 mSimpleProcessManagement ? app.processName : null, uid, uid,   
  29.                 gids, debugFlags, null);   
  30.                
  31.             ......   
  32.    
  33.         } catch (RuntimeException e) {   
  34.                
  35.             ......   
  36.    
  37.         }   
  38.     }   
  39.    
  40.     ......   
  41.    
  42. }   

        这里主要是调用Process.start接口来创建一个新的进程,新的进程会导入android.app.ActivityThread类,并且执行它的main函数,这就是为什么我们前面说每一个应用程序都有一个ActivityThread实例来对应的原因。

        Step 24. ActivityThread.main

        这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

 
 
  1. public final class ActivityThread {   
  2.    
  3.     ......   
  4.    
  5.     private final void attach(boolean system) {   
  6.         ......   
  7.    
  8.         mSystemThread = system;   
  9.         if (!system) {   
  10.    
  11.             ......   
  12.    
  13.             IActivityManager mgr = ActivityManagerNative.getDefault();   
  14.             try {   
  15.                 mgr.attachApplication(mAppThread);   
  16.             } catch (RemoteException ex) {   
  17.             }   
  18.         } else {   
  19.    
  20.             ......   
  21.    
  22.         }   
  23.     }   
  24.    
  25.     ......   
  26.    
  27.     public static final void main(String[] args) {   
  28.            
  29.         .......   
  30.    
  31.         ActivityThread thread = new ActivityThread();   
  32.         thread.attach(false);   
  33.    
  34.         ......   
  35.    
  36.         Looper.loop();   
  37.    
  38.         .......   
  39.    
  40.         thread.detach();   
  41.            
  42.         ......   
  43.     }   
  44. }   

 

       这个函数在进程中创建一个ActivityThread实例,然后调用它的attach函数,接着就进入消息循环了,直到最后进程退出。

       函数attach最终调用了ActivityManagerService的远程接口ActivityManagerProxy的attachApplication函数,传入的参数是mAppThread,这是一个ApplicationThread类型的Binder对象,它的作用是用来进行进程间通信的。

      Step 25. ActivityManagerProxy.attachApplication

      这个函数定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

 
 
  1. class ActivityManagerProxy implements IActivityManager   
  2. {   
  3.     ......   
  4.    
  5.     public void attachApplication(IApplicationThread app) throws RemoteException   
  6.     {   
  7.         Parcel data = Parcel.obtain();   
  8.         Parcel reply = Parcel.obtain();   
  9.         data.writeInterfaceToken(IActivityManager.descriptor);   
  10.         data.writeStrongBinder(app.asBinder());   
  11.         mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);   
  12.         reply.readException();   
  13.         data.recycle();   
  14.         reply.recycle();   
  15.     }   
  16.    
  17.     ......   
  18.    
  19. }   

 

       这里通过Binder驱动程序,最后进入ActivityManagerService的attachApplication函数中。

       Step 26. ActivityManagerService.attachApplication

       这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

 
 
  1. public final class ActivityManagerService extends ActivityManagerNative   
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {   
  3.    
  4.     ......   
  5.    
  6.     public final void attachApplication(IApplicationThread thread) {   
  7.         synchronized (this) {   
  8.             int callingPid = Binder.getCallingPid();   
  9.             final long origId = Binder.clearCallingIdentity();   
  10.             attachApplicationLocked(thread, callingPid);   
  11.             Binder.restoreCallingIdentity(origId);   
  12.         }   
  13.     }   
  14.    
  15.     ......   
  16.    
  17. }   

 

      这里将操作转发给attachApplicationLocked函数。

        Step 27. ActivityManagerService.attachApplicationLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

 
 
  1. public final class ActivityManagerService extends ActivityManagerNative   
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {   
  3.    
  4.     ......   
  5.    
  6.     private final boolean attachApplicationLocked(IApplicationThread thread,   
  7.             int pid) {   
  8.         // Find the application record that is being attached...  either via   
  9.         // the pid if we are running in multiple processes, or just pull the   
  10.         // next app record if we are emulating process with anonymous threads.   
  11.         ProcessRecord app;   
  12.         if (pid != MY_PID && pid >= 0) {   
  13.             synchronized (mPidsSelfLocked) {   
  14.                 app = mPidsSelfLocked.get(pid);   
  15.             }   
  16.         } else if (mStartingProcesses.size() > 0) {   
  17.             ......   
  18.         } else {   
  19.             ......   
  20.         }   
  21.    
  22.         if (app == null) {   
  23.             ......   
  24.             return false;   
  25.         }   
  26.    
  27.         ......   
  28.    
  29.         String processName = app.processName;   
  30.         try {   
  31.             thread.asBinder().linkToDeath(new AppDeathRecipient(   
  32.                 app, pid, thread), 0);   
  33.         } catch (RemoteException e) {   
  34.             ......   
  35.             return false;   
  36.         }   
  37.    
  38.         ......   
  39.    
  40.         app.thread = thread;   
  41.         app.curAdj = app.setAdj = -100;   
  42.         app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;   
  43.         app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;   
  44.         app.forcingToForeground = null;   
  45.         app.foregroundServices = false;   
  46.         app.debugging = false;   
  47.    
  48.         ......   
  49.    
  50.         boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);   
  51.    
  52.         ......   
  53.    
  54.         boolean badApp = false;   
  55.         boolean didSomething = false;   
  56.    
  57.         // See if the top visible activity is waiting to run in this process...   
  58.         ActivityRecord hr = mMainStack.topRunningActivityLocked(null);   
  59.         if (hr != null && normalMode) {   
  60.             if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid   
  61.                 && processName.equals(hr.processName)) {   
  62.                     try {   
  63.                         if (mMainStack.realStartActivityLocked(hr, app, truetrue)) {   
  64.                             didSomething = true;   
  65.                         }   
  66.                     } catch (Exception e) {   
  67.                         ......   
  68.                     }   
  69.             } else {   
  70.                 ......   
  71.             }   
  72.         }   
  73.    
  74.         ......   
  75.    
  76.         return true;   
  77.     }   
  78.    
  79.     ......   
  80.    
  81. }   

 

        在前面的Step 23中,已经创建了一个ProcessRecord,这里首先通过pid将它取回来,放在app变量中,然后对app的其它成员进行初始化,最后调用mMainStack.realStartActivityLocked执行真正的Activity启动操作。这里要启动的Activity通过调用mMainStack.topRunningActivityLocked(null)从堆栈顶端取回来,这时候在堆栈顶端的Activity就是MainActivity了。





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/965990,如需转载请自行联系原作者

目录
相关文章
|
1月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
140 4
|
1月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
19天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
44 14
|
22天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
23天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
28 8
|
20天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
27天前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
34 1
|
20天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
25 0
|
1月前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
1月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。