finish 和 onDestroy 的区域

本文详细解释了 Android 中 Activity 的 finish() 方法与 onDestory() 方法的区别,以及 System.exit(0) 对应用程序的影响。通过阅读本文,你可以了解到这些方法在 Activity 生命周期中的作用及资源释放的时机。

Activity.finish()
Call this when your activity is done and should be closed.
在你的activity动作完成的时候,或者Activity需要关闭的时候,调用此方法。
当你调用此方法的时候,系统只是将最上面的Activity移出了栈,并没有及时的调用onDestory()方法,其占用的资源也没有被及时释放。因为移出了栈,所以当你点击手机上面的“back”按键的时候,也不会再找到这个Activity。
Activity.onDestory()
the system is temporarily destroying this instance of the activity to save space.
系统销毁了这个Activity的实例在内存中占据的空间。
在Activity的生命周期中,onDestory()方法是他生命的最后一步,资源空间等就被回收了。
当重新进入此Activity的时候,必须重新创建,执行onCreate()方法。
System.exit(0)
这玩意是退出整个应用程序的,是针对整个Application的。将整个进程直接KO掉。

------------------------------------------

finish函数仅仅把当前Activity退出了,但是并没有释放他的资源。安卓系统自己决定何时从内存中释放应用程序。当系统没有可用内存到时候,会按照优先级,释放部分应用。


原文:http://blog.youkuaiyun.com/imzoer/article/details/9380807


/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.localepicker; import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT; import android.app.FragmentTransaction; import android.content.Intent; import android.os.Bundle; import android.os.LocaleList; import android.provider.Settings; import android.util.Log; import android.view.MenuItem; import android.window.OnBackInvokedCallback; import androidx.core.view.ViewCompat; import com.android.internal.app.LocalePickerWithRegion; import com.android.internal.app.LocaleStore; import com.android.settings.R; import com.android.settings.core.SettingsBaseActivity; /** A activity to show the locale picker page. */ public class LocalePickerWithRegionActivity extends SettingsBaseActivity implements LocalePickerWithRegion.LocaleSelectedListener, MenuItem.OnActionExpandListener { private static final String TAG = LocalePickerWithRegionActivity.class.getSimpleName(); private static final String PARENT_FRAGMENT_NAME = "localeListEditor"; private LocalePickerWithRegion mSelector; private final OnBackInvokedCallback mOnBackInvokedCallback = () -> { handleBackPressed(); }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActionBar().setDisplayHomeAsUpEnabled(true); setTitle(R.string.add_a_language); LocaleList explicitLocales = null; if (isDeviceDemoMode()) { Bundle bundle = getIntent().getExtras(); explicitLocales = bundle == null ? null : bundle.getParcelable(Settings.EXTRA_EXPLICIT_LOCALES, LocaleList.class); Log.i(TAG, "Has explicit locales : " + explicitLocales); } getOnBackInvokedDispatcher() .registerOnBackInvokedCallback(PRIORITY_DEFAULT, mOnBackInvokedCallback); mSelector = LocalePickerWithRegion.createLanguagePicker( this, LocalePickerWithRegionActivity.this, false /* translate only */, explicitLocales, null /* appPackageName */, this); getFragmentManager() .beginTransaction() .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) .replace(R.id.content_frame, mSelector) .addToBackStack(PARENT_FRAGMENT_NAME) .commit(); } @Override public void onDestroy() { super.onDestroy(); getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mOnBackInvokedCallback); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { handleBackPressed(); return true; } return super.onOptionsItemSelected(item); } @Override public void onLocaleSelected(LocaleStore.LocaleInfo locale) { final Intent intent = new Intent(); intent.putExtra(LocaleListEditor.INTENT_LOCALE_KEY, locale); setResult(RESULT_OK, intent); finish(); } private void handleBackPressed() { if (getFragmentManager().getBackStackEntryCount() > 1) { super.onBackPressed(); } else { setResult(RESULT_CANCELED); finish(); } } private boolean isDeviceDemoMode() { return Settings.Global.getInt( getContentResolver(), Settings.Global.DEVICE_DEMO_MODE, 0) == 1; } @Override public boolean onMenuItemActionExpand(MenuItem item) { // To prevent a large space on tool bar. mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/); // To prevent user can expand the collpasing tool bar view. ViewCompat.setNestedScrollingEnabled(mSelector.getListView(), false); return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/); ViewCompat.setNestedScrollingEnabled(mSelector.getListView(), true); return true; } } 中点击English进入第二项的逻辑在哪
最新发布
06-08
<think>我们正在分析用户的问题:在Android系统的语言选择界面(LocalePickerWithRegionActivity)中,当点击“English”后进入的子界面(第二级界面)没有显示“English(Zawgyi)”(即en-Qaag)选项。我们已经确认在locale_config.xml中添加了en-Qaag,并且在LocaleStore的fillCache方法中处理了该语言标签且打印了相关信息。现在需要定位点击English后进入子界面的逻辑,并分析为什么en-Qaag没有出现在这个子界面。根据用户上一次的问题,我们知道en-Qaag已经添加到系统中,但是未在English的子界面中显示。因此,我们需要分析:1.点击English进入子界面的代码逻辑(即如何构建子界面的列表)。2.构建该子界面列表时,en-Qaag被过滤或未正确分组的原因。###逻辑分析在Android设置中,语言选择通常分为两级:第一级:按语言(如English,中文)分组显示。第二级:当点击某个语言组(如English)时,显示该语言下的具体区域变体(如English(UnitedStates),English(UnitedKingdom)等)。因此,我们关注LocalePickerWithRegionActivity中:1.如何构建第一级列表(按语言分组)2.如何构建第二级列表(某个语言下的具体区域)###关键代码位置在Android源代码中,实现这一功能的核心类为`LocalePickerWithRegionActivity``LocaleStore`。####点击进入子界面的逻辑当用户点击第一级列表的某一项(如English)时,会触发一个事件,该事件会启动一个新的Activity(实际是同一个Activity,但以不同的模式运行)来显示该语言下的区域列表。具体路径:1.在`LocalePickerWithRegionActivity`中,当用户点击第一级列表项时,会调用`onListItemClick`方法。2.在`onListItemClick`方法中,会根据当前显示模式(模式分为:选择语言、选择区域点击的项来执行相应操作。在`LocalePickerWithRegionActivity`的`onCreate`方法中,会根据启动参数`EXTARGET_STEP`判断当前是显示语言列表还是区域列表。当用户点击语言项时,会再次启动同一个Activity,但传递参数表示进入区域选择模式,并传递所选语言的信息。####构建子界面列表的关键方法在构建区域列表(子界面)时,会从`LocaleStore`获取该语言下的所有区域(即同一种语言下的不同区域变体)。具体来说,是通过`LocaleStore`的`getLevelLocales`方法获取。###可能的原因en-Qaag没有出现在English子界面中,可能是因为:1.在获取该语言下的区域列表时,en-Qaag没有被正确归类到英语(en)分组下。2.或者,en-Qaag被归类到了英语分组,但是在构建区域列表时被过滤掉了(比如,系统认为它是一个“不完整”的区域变体,因为它没有区域码)。###调试建议1.在`LocaleStore`的`getLevelLocales`方法中,查看当请求英语(en)的区域列表时,返回的列表是否包含en-Qaag。2.检查`LocaleInfo`对象中,en-Qaag的`isTranslated`方法是否返回false(可能因为它没有对应的资源而导致被过滤)?###代码路径我们假设用户使用的是Android11或更高版本的代码(因为用户提到了Android15,不过目前Android15尚未发布,可能是基于较新的AOSP),代码结构可能略有不同,但大体流程一致。####1.点击事件处理在`LocalePickerWithRegionActivity`中:```java@OverrideprotectedvoidonListItemClick(Viewview,intposition,longid){finalLocaleStore.LocaleInfolocale=mAdapter.getLocaleInfo(position);switch(mMode){caseMODE_LANGUAGE://当前是第一级语言列表if(locale.getParent()!=null){//如果点击的项有父项(实际上在语言模式下,每个语言项是一个父项,包含多个子区域)//则进入区域选择模式,显示该语言下的区域showLocale(locale);}else{//如果没有子区域,那么直接选择这个语言returnResultToApp(locale);}break;//...其他模式}}````showLocale`方法会启动一个新的Activity(或者重新加载当前Activity)来显示所选语言下的区域列表:```javaprivatevoidshowLocale(LocaleStore.LocaleInfoparentLocale){Intentintent=newIntent();//设置参数,表明进入区域选择模式intent.putExtra(EXTARGET_STEP,STEP_REGION);//传递父语言(即点击的英语)intent.putExtra(EXTARG_PARENT_LOCALE,parentLocale);//...启动或设置}```####2.构建区域列表当Activity以STEP_REGION模式启动时,会调用`setRegionList`方法:```javaprivatevoidsetRegionList(LocaleStore.LocaleInfoparentLocale){//从LocaleStore中获取该语言下的所有区域List<LocaleStore.LocaleInfo>locales=LocaleStore.getLevelLocales(getApplicationContext(),mSetIgnoreLocale,parentLocale,false/*是否包含子区域*/);//...然后设置适配器}```####3.关键:获取语言下的区域列表在`LocaleStore`的`getLevelLocales`方法中,会获取所有属于该语言的区域。这里我们关注`getLevelLocales`的实现:```javapublicstaticList<LocaleStore.LocaleInfo>getLevelLocales(Contextcontext,booleanincludeTranslationLevel,LocaleStore.LocaleInfoparent,booleanshowCountryOnly){//从缓存中获取所有LocaleInfoLinkedHashSet<LocaleStore.LocaleInfo>allLocales=getSystemAssetLocales(context);//...然后根据parent进行过滤finalList<LocaleStore.LocaleInfo>result=newArrayList<>();for(LocaleStore.LocaleInfoli:allLocales){//检查是否属于同一个语言(即li的父语言是parent)if(li.isTranslated()&&li.getParent().equals(parent)){result.add(li);}}returnresult;}```注意:这里有一个条件`li.getParent().equals(parent)`。因此,问题可能出现在en-Qaag的父语言没有设置为英语(即en),或者它的父语言不是用户点击的那个父语言(即传入的parent)。###为什么en-Qaag的父语言可能不正确?在`LocaleStore`中,`LocaleInfo`的父语言是通过`getParent()`方法获取的,该方法返回的是该语言对应的“语言”级别的LocaleInfo(例如,en-US的父语言是en)。在创建LocaleInfo对象时,父语言是在`fromUlocale`方法中设置的:```javapublicstaticLocaleInfofromUlocale(ULocalelocale){//...从缓存中获取或新建if(cached==null){cached=newLocaleInfo();cached.mId=locale.toLanguageTag();//...设置mParentLocaleif(!TextUtils.isEmpty(locale.getCountry())){//如果存在国家代码,那么父语言就是语言级别的cached.mParent=fromUlocale(getLanguageLocale(locale));}else{//如果没有国家代码,那么它自己就是语言级别的cached.mParent=cached;}}returncached;}```对于en-Qaag(tag为en-Qaag):-在创建时,由于它没有国家代码(Qaag是一个脚本,不是国家代码),所以它会被认为是一个语言级别的LocaleInfo,即它的父语言是自己。因此,在调用`li.getParent()`时返回的是它自己,而不是en(英语)的父语言。这导致在构建区域列表时,我们传入的parent是en(英语)的LocaleInfo对象,而en-Qaag的父语言是自己(cached.mParent=cached),所以不满足`li.getParent().equals(parent)`,因此不会被添加到结果列表中。###解决方案我们需要修改en-Qaag的父语言的设置逻辑,让它属于英语(en)分组。但是,由于`LocaleInfo`的构建是Android系统内部机制,我们需要考虑以下方法:1.**修改LocaleInfo的创建逻辑**,为en-Qaag指定一个正确的父语言(即en)。这需要修改`fromUlocale`方法,对特定标签(如en-Qaag)做特殊处理,将其父语言设置为en的LocaleInfo。2.**修改分组逻辑**,在`getLevelLocales`中,除了比较父语言外,也考虑语言代码(languagecode)相同的情况。由于修改系统核心逻辑可能较为复杂,我们可以考虑第一种方式,即在创建LocaleInfo时,为脚本语言设置父语言为对应的语言。例如,在`LocaleStore`的`fromUlocale`方法中,我们可以这样修改:```javapublicstaticLocaleInfofromUlocale(ULocalelocale){//...原有代码if(cached==null){cached=newLocaleInfo();Stringtag=locale.toLanguageTag();//检查是否为en-Qaagif(tag.equals("en-Qaag")){//对于en-Qaag,我们将其父语言设置为en的LocaleInfocached.mParent=fromUlocale(ULocale.forLanguageTag("en"));}else{//原来的逻辑if(!TextUtils.isEmpty(locale.getCountry())){cached.mParent=fromUlocale(getLanguageLocale(locale));}else{cached.mParent=cached;}}}returncached;}```###测试验证在修改后,当调用`li.getParent()`时,en-Qaag的父语言会是en,这样在点击English时,en-Qaag就会出现在子列表中。###相关代码路径总结1.点击事件:`LocalePickerWithRegionActivity#onListItemClick`2.显示区域列表:`LocalePickerWithRegionActivity#showLocale`3.构建区域列表:`LocalePickerWithRegionActivity#setRegionList`->`LocaleStore.getLevelLocales`4.获取系统Locale列表:`LocaleStore.getSystemAssetLocales`->`LocaleStore.fillCache`5.LocaleInfo创建父语言设置:`LocaleStore.LocaleInfo#fromUlocale`###用户问题解答用户询问的是点击English进入第二项的逻辑位置。逻辑位置主要在:-`LocalePickerWithRegionActivity#onListItemClick`处理点击事件,调用`showLocale`方法。-`showLocale`方法启动区域选择界面,关键数据由`setRegionList`方法构建,其中使用`LocaleStore.getLevelLocales`获取该语言下的区域列表。如果希望en-Qaag出现在English的子界面中,需要确保在`LocaleStore`中en-Qaag的父语言被正确设置为en(英语)的LocaleInfo对象,这可能需要修改`LocaleInfo`的创建逻辑。###相关问题§§相关问题§§1.Android系统中语言区域的分组机制是如何实现的?2.如何为Android系统添加自定义语言变体(如方言)?3.为什么某些语言变体在Android语言选择界面中会被隐藏?</think> ### 分析`LocalePickerWithRegionActivity`中进入English子界面的逻辑路径 根据您描述的Android 15代码结构,点击English后进入第二级界面的核心逻辑路径如下: ```mermaid graph TD A[LocalePickerWithRegionActivity] --> B[onListItemClick] B --> C{判断模式} C -->|MODE_LANGUAGE| D[showLocale] D --> E[setRegionList] E --> F[LocaleStore.getLevelLocales] F --> G[分组过滤逻辑] G --> H[构建区域列表] ``` #### 关键代码位置及调用关系 1. **点击事件入口** 在`LocalePickerWithRegionActivity`中定位`onListItemClick`方法: ```java @Override protected void onListItemClick(View view, int position, long id) { final LocaleStore.LocaleInfo locale = mAdapter.getLocaleInfo(position); switch (mMode) { case MODE_LANGUAGE: // 第一级语言选择模式 if (locale.getParent() != null) { showLocale(locale); // 进入二级区域选择 } break; // ... } } ``` 2. **进入二级界面的核心方法** 跳转到`showLocale()`方法: ```java private void showLocale(LocaleStore.LocaleInfo parentLocale) { setRegionList(parentLocale); // 关键:构建区域列表 // 更新UI显示区域列表 } ``` 3. **构建区域列表的实现** 在`setRegionList()`中: ```java private void setRegionList(LocaleStore.LocaleInfo parentLocale) { // 获取当前语言下的所有区域变体 List<LocaleStore.LocaleInfo> locales = LocaleStore.getLevelLocales( getApplicationContext(), false, parentLocale, true ); // 设置适配器显示列表 } ``` 4. **分组过滤逻辑** 最终需要检查`LocaleStore.getLevelLocales()`中的分组逻辑,特别是以下代码段: ```java public static List<LocaleStore.LocaleInfo> getLevelLocales(...) { // ... for (LocaleStore.LocaleInfo li : locales) { if (li.isTranslated() && li.getParent().equals(parentLocale)) { result.add(li); // 仅添加通过过滤条件的项 } } // ... } ``` --- ### 为什么en-Qaag可能不显示 根据上述逻辑,`en-Qaag`未显示在English子界面的可能原因: 1. **父级关联错误** 在`LocaleInfo`中,`en-Qaag`的父级(`getParent()`)必须正确关联到`en`标识: ```java // 正确的父级关联应类似: en_US.getParent() = en en_GB.getParent() = en en_Qaag.getParent() = en // 必须相同 ``` 2. **过滤条件不满足** 检查`li.isTranslated()`的返回值: ```java if (li.isTranslated() && ...) // 需要返回true才能显示 ``` 该函数检查是否有实际翻译资源,确认: - `res/values-en-rQaag/`目录存在且含有效资源 - 字体配置文件`res/values-en-rQaag/fonts.xml`已正确声明 3. **区域分组逻辑** Android可能将`Qaag`视为特殊脚本而非标准区域: ```java // 某些实现可能排除纯脚本标签 if (locale.getCountry().isEmpty()) { continue; // 可能跳过无国家代码的项 } ``` --- ### 调试建议 在关键位置添加日志验证数据流: ```java // 在setRegionList()中添加: Log.d("RegionList", "Parent: " + parentLocale.toString()); for (LocaleStore.LocaleInfo li : locales) { Log.d("RegionList", "Item: " + li.toString() + " ParentMatch: " + li.getParent().equals(parentLocale) + " Translated: " + li.isTranslated()); } ``` 预期日志中应包含: ``` Item: en-Qaag ParentMatch: true Translated: true ``` --- ### 修复方向 1. **确保父级关联** 在`LocaleInfo`构造器中强制设置父级: ```java public LocaleInfo(ULocale locale) { if (locale.toString().equals("en-Qaag")) { this.mParent = getLocale("en"); // 显式关联到英语 } } ``` 2. **绕过特殊过滤** 修改分组逻辑强制包含脚本语言: ```java // LocaleStore.getLevelLocales中 if (li.getParent().equals(parentLocale) || (li.getLocale().getLanguage().equals("en") && li.getLocale().getScript().equals("Qaag")) { result.add(li); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值