小编Ben*_* P.的帖子

在onActivityResult()中提交FragmentTransaction是否安全?

几年前,当我尝试FragmentTransactiononActivityResult()回调中提交内容时,我在我的一个应用程序中遇到了问题.谷歌搜索,我发现这个问题和答案,说

onActivityResult()调用时,活动/片段的状态可能尚未恢复,因此在此期间发生的任何事务都将丢失.

我最终采用了相同答案推荐的解决方案来应用我的应用程序,生活很美好.然而,最近的实验表明,事情可能已经发生了变化,现在从内部投入可能是安全的.FragmentTransactiononActivityResult()

(支持v4)的文档FragmentManager.beginTransaction()将事务的安全窗口定义为:

注意:只能在活动保存其状态之前创建/提交片段事务.如果您尝试在之后FragmentActivity.onSaveInstanceState()(以及之后FragmentActivity.onStart或之前)提交事务FragmentActivity.onResume(),您将收到错误.

阅读文档onActivityResult(),我明白了

您将在onResume()重新启动活动之前立即收到此电话.

这使我相信执行这些事务应该是安全的onActivityResult(),就像onStart()已经被调用的那样,将我置于安全窗口内.

我做了一个应用程序来测试它,我成功地看到了我创建并提交的对话框片段onActivityResult().我有相同的应用程序也记录活动生命周期回调,所以我可以检查他们的订单onStart(),然后onRestoreInstanceState(),我看到,然后onActivityResult()每次.

我错过了什么吗?或者框架已更改,onActivityResult()现在保证是片段交易的安全位置?此行为是否因API级别而异?

我发现了另一个问题和答案似乎与我的文档相同,但两者都超过一年,并没有特别指的是onActivityResult()交易的安全场所.

android android-fragments android-activity android-fragmentactivity fragmentmanager

14
推荐指数
1
解决办法
739
查看次数

来自命令行和来自 Android Studio 的 Android Lint 不匹配

我有一个模块,我知道它包含一些未使用的颜色资源。当我从 Android Studio 运行 lint 时,它包含我期望的输出。但是,当我从命令行运行它时,它没有找到这些未使用的资源。

如何让命令行报告这些未使用的资源(最好作为警告)?


从 Android Studio 运行 lint

按名称运行检查:

在此处输入图片说明

输出:

在此处输入图片说明

从命令行运行 lint(使用 gradle)

我的 build.gradle 配置:

lintOptions {
    check 'UnusedResources'
}
Run Code Online (Sandbox Code Playgroud)

实际运行任务:

$ ./gradlew :lib:lint

> Task :lib:lint
Ran lint on variant release: 0 issues found
Ran lint on variant debug: 0 issues found

BUILD SUCCESSFUL in 2s
Run Code Online (Sandbox Code Playgroud)

我知道 gradle 配置正在“工作”,因为如果我删除该check 'UnusedResources'行,它会发现其他问题(check使其仅运行一次检查)。同样值得注意的是,指定check 'ThisIsObviouslyNonsense'给出了相同的输出(发现零问题的“成功”运行)。


重现问题

我无法提供真正的源代码,但在新项目中重现该问题非常简单。

  1. 使用 Android Studio 向导创建一个新项目。(我选择了“Empty Activity”、Kotlin 和 19 的最小 API。)
  2. 将此添加到您的colors.xml: <color name="unused">#f00</color>
  3. 打开 …

android static-analysis gradle android-studio

9
推荐指数
0
解决办法
984
查看次数

从RecyclerView.Adapter中删除项目后,RecyclerView.ItemDecoration不会更新

我的问题

当我从适配器中删除给定视图然后调用时,如何让我ItemDecoration"更新" 其他视图的项目偏移量notifyItemRemoved()

在我的特殊情况下,我有一个为每个项目ItemDecoration提供少量的顶部偏移量,并且只有最后一个项目的大量底部偏移量.当我删除最后一项时,成为新的最后一项的视图没有任何底部偏移.

之前和之后:

在此输入图像描述 在此输入图像描述

如果我然后滚动列表,当我返回到列表的底部时,我的"新"最后一项具有正确的偏移量.只要"新"最后一项在屏幕上保持可见,这只是一个问题.

我试过的

如果我将我的notifyItemRemoved()呼叫改为notifyDataSetChanged(),则新的最后一项将应用正确的项目偏移,但是我丢失了我得到的内置动画notifyItemRemoved().

如果我继续使用notifyItemRemoved()另外调用notifyItemChanged()前一个项目,那么我将获得正确的项目偏移,但动画有点janky; 倒数第二个项目(删除前)似乎淡出然后再次出现(在此屏幕截图中,卡片上写着"项目19"刚被删除):

在此输入图像描述

我知道我可以通过在我的<RecyclerView>标签上应用底部填充并指定来在列表末尾创建一个大空间android:clipToPadding="false",但由于各种原因,这个解决方案是不可接受的.

重现

我最初在一个我正在研究的更大的应用程序中遇到了这个问题,但这里有一个很小的应用程序来演示这个问题.

MainActivity.java:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final MyAdapter adapter = new MyAdapter(20);

    Button button = findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            adapter.removeItemAt(adapter.getItemCount() - …
Run Code Online (Sandbox Code Playgroud)

android android-recyclerview

8
推荐指数
3
解决办法
2666
查看次数

当兄弟滚动到达结尾时打开底部?

有没有办法将滚动事件从一个滚动视图"转发"到我的底部工作表,以便在我滚动第一个滚动视图时我的底部工作表开始展开?

考虑这个小应用程序:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int peekHeight = getResources().getDimensionPixelSize(R.dimen.bottom_sheet_peek_height); // 96dp

        View bottomSheet = findViewById(R.id.bottomSheet);
        BottomSheetBehavior<View> behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setPeekHeight(peekHeight);
    }
}
Run Code Online (Sandbox Code Playgroud)
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!-- LinearLayout holding children to scroll through -->

    </android.support.v4.widget.NestedScrollView>

    <View
        android:id="@+id/bottomSheet"
        android:layout_width="300dp"
        android:layout_height="400dp"
        android:layout_gravity="center_horizontal"
        app:layout_behavior="android.support.design.widget.BottomSheetBehavior"/>

</android.support.design.widget.CoordinatorLayout>
Run Code Online (Sandbox Code Playgroud)

开箱即用,这很好用.我看到96pp的底页,我可以照常上下滑动.另外,我可以看到我的滚动内容,我可以像往常一样上下滚动.

在此输入图像描述 在此输入图像描述 在此输入图像描述

让我们假设我处于第二张图片中显示的状态.我NestedScrollView的滚动一直到底部,我的底部工作表已折叠.我想能够向上滑动的上NestedScrollView(在底部片材),由于它不能滚动任何更远,具有扫掠姿态而不是被发送到所述底部片材,使得它开始膨胀.基本上,让应用程序的行为好像我的手势已在底部工作表上执行,而不是滚动视图.

我的第一个想法是看NestedScrollView.OnScrollChangeListener,但我不能让它工作,因为它停止在滚动内容的边界被触发(毕竟,它听取滚动变化,当你在边缘时没有任何变化) .

我还看了一下创建自己的子类BottomSheetBehavior并尝试覆盖onInterceptTouchEvent(),但在两个地方遇到了麻烦.首先,我只想在兄弟滚动视图位于底部时捕获事件,我可以这样做,但我现在正在捕获所有事件(使得无法向后滚动兄弟).其次,内部的 …

java android android-coordinatorlayout bottom-sheet

6
推荐指数
1
解决办法
2090
查看次数

列表&lt;? 生成 extends Something &gt; 而不是 List&lt;Something&gt;

我有一个服务调用,它返回一个 JSON 响应,然后通过数据管理器传递该响应,如果服务成功,则该数据管理器会转换数据;如果调用失败,则创建一个错误正文。

数据管理器是用 kotlin 编写的,我感兴趣的特定代码行是这样的

val mutableList = mutableListOf<Address>()
return Result.error(errorTransformation(serviceErrors, mutableList))
Run Code Online (Sandbox Code Playgroud)

我的 errorTransformation 类基本上是一个 Exception 调用,这是用 java.io.ErrorTransformation 编写的。异常类的构造函数是

ExceptionClass(ServiceErrors serviceError ,List<Address> address){
    // initiialize fields here
}
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试初始化异常类时,它说找到了适当的构造函数,并且向我显示了使用语法生成异常类的建议

ExceptionClass(ServiceErrors serviceError ,List<? extends Address> address){
    // initiialize fields here
}
Run Code Online (Sandbox Code Playgroud)

为什么会发生这种情况?我只想要List<Address>,不想要List<? extends Address>

java generics android kotlin rx-java2

6
推荐指数
1
解决办法
448
查看次数

未显示 Android Studio 预览

无法实例化以下类:( androidx.fragment.app.FragmentContainerView打开类、显示异常、清除缓存)

提示:View.isInEditMode()在您的自定义视图中使用以在 IDE 中显示时跳过代码或显示示例数据。如果这是意外错误,您也可以尝试构建项目,然后手动刷新布局。

异常详情:

java.lang.UnsupportedOperationException: FragmentContainerView must be within a FragmentActivity to be instantiated from XML. 
    at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:117) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) 
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)  
    at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:1123)  
    at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:72)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:1097)  
    at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:682)  
    at android.view.LayoutInflater.inflate(LayoutInflater.java:501)
Run Code Online (Sandbox Code Playgroud)

显示此消息并且布局预览未显示在基本活动或其他模板接受空活动中。

在此消息之前,显示了一条关于将片段标记替换为 的消息fragmentcontainerview。我解决了这个问题,然后显示了上面的消息。我尝试过已知的解决方案,例如重建、刷新布局和使缓存/重启无效等,但他们没有成功。

android android-layout android-fragments android-studio android-studio-3.6.1

6
推荐指数
1
解决办法
1117
查看次数

正确使用WindowManager.removeViewImmediate()

的文档WindowManager.removeViewImmediate()包含警告(重点为我):

它的特殊变体在返回之前ViewManager.removeView(View)立即调用给定视图层次结构的View.onDetachedFromWindow()方法。这不是正常应用;正确使用它需要非常小心。

我很好奇“精心护理”在这里意味着什么。大概这表明除非我知道如何处理使用该方法的所有副作用,否则我不应该调用此方法……但是我什至不知道这些副作用可能是什么。


考虑以下活动,我尽可能将其制成。没有遗漏的代码(除了导入),并且Activity的主题只是一个普通的AppCompat主题:

public class MainActivity extends AppCompatActivity {

    private View overlay;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getWindow().getDecorView().post(() -> {
            overlay = new View(this);
            overlay.setBackgroundColor(Color.RED);

            WindowManager.LayoutParams params =
                    new WindowManager.LayoutParams(WindowManager.LayoutParams.FLAG_FULLSCREEN);

            getWindowManager().addView(overlay, params);
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getWindowManager().removeView(overlay);
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行我的应用程序并将设备从纵向旋转到横向(或导致其被破坏和重新创建的任何其他方式)时,这将显示在日志中:

2018-10-09 13:58:02.162 11270-11270/com.example.stackoverflow E/WindowManager: android.view.WindowLeaked: Activity com.example.stackoverflow.MainActivity has leaked window android.view.View{e99861 V.ED..... ........ 0,0-1080,1920} that was originally added here
        at android.view.ViewRootImpl.<init>(ViewRootImpl.java:511)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:346)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
        at …
Run Code Online (Sandbox Code Playgroud)

android android-windowmanager

5
推荐指数
1
解决办法
460
查看次数

使用 Android UI Automator 测试辅助显示器上的内容

我有一个准系统应用程序来测试对多个显示器的支持。我的设置是运行 Android 8.1.0(“主显示器”)的定制 Android 平板电脑,通过 HDMI(提供视频信号)和 USB(提供触摸事件)连接到触摸屏(“辅助显示器”)。

该应用程序包含一个活动,显示“Hello World!” 在主显示器上,但也利用DisplayManager并在辅助显示器WindowManager上添加一个计数器和两个+/-按钮:

正常运行应用程序并与辅助显示器上的按钮交互按预期工作。

现在,我想使用UI Automator来单击+按钮并验证计数器是否记录了正确的值。这似乎是不可能的。有谁知道我怎么能做到这一点?

或者,如果 UI Automator 不是适合这项工作的工具,但还有其他一些工具可以让我为在辅助显示器上显示内容的应用程序编写端到端的黑盒式测试,我很高兴得到建议。


我调查过的一些事情

我已经使用该uiautomatorviewer工具来检查我的应用程序的布局层次结构。使用此工具只能看到主显示器上的内容:

在此处输入图片说明

我习惯于UiDevice.dumpWindowHierarchy()获取设备上所有内容的文本转储。仅转储主设备上的内容,尽管包括有关系统窗口(如状态栏和导航栏)的信息。

我已经使用过adb shell dumpsys window(同时使用tokenswindows命令)。将显示有关我在辅助显示器上创建的窗口的信息,但我似乎无法通过 Ui Automator 访问此窗口:

Display #1
WindowToken{551f82f android.os.BinderProxy@87f65ac}:
  windows=[Window{e40e275 u0 com.example.stackoverflow}]
  windowType=2038 hidden=false hasVisible=true
Run Code Online (Sandbox Code Playgroud)
Window #10 Window{20ac4ce u0 com.example.stackoverflow}:
  mDisplayId=1 mSession=Session{91fdd93 8079:u0a10089} mClient=android.os.BinderProxy@a3e65c9
  mOwnerUid=10089 mShowToOwnerOnly=true package=com.example.stackoverflow appop=SYSTEM_ALERT_WINDOW
  mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#20 …
Run Code Online (Sandbox Code Playgroud)

android ui-automation android-uiautomator

5
推荐指数
1
解决办法
720
查看次数

通过Intent发送Arraylist

如何ArrayList通过其他活动收到自定义Intent?例如,我ArrayList在活动A中有这个:

ArrayList<Song> songs;
Run Code Online (Sandbox Code Playgroud)

我如何在活动B中获得此列表?

android android-intent

4
推荐指数
1
解决办法
5198
查看次数

super.onCreate(savedInstanceState)中savedInstanceState有什么用?

所以,我试图了解 Android 的内部工作原理,但我还没有找到我正在寻找的内容的深入解释。对于我的简单程序:

public class MainActivity extends AppCompatActivity {

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
Run Code Online (Sandbox Code Playgroud)

nullusing和savedInstanceStatein有什么区别super.onCreate()?我已经尝试过这两种方法,但我的程序没有任何区别。

如果存在差异,savedInstanceState与使用 相比,使用 会以哪些方式影响我的程序null

android android-activity

3
推荐指数
1
解决办法
3230
查看次数

片段单元测试:launchFragment 抛出 ClassCastException

我试图在我的单元测试中调用 Fragment 类中的方法,但我不断收到错误消息 java.lang.ClassCastException: androidx.fragment.app.testing.FragmentScenario$EmptyFragmentActivity cannot be cast to com.nu.rms.inspections.ui.activity.InspectionActivity

我正在关注 Google 的文档。我很困惑为什么空片段活动有一个演员试图成为我的检查活动(片段所在的父活动),也许这是预期的?

我可以做些什么来缓解 CastClassException 并在我的单元测试中使用我的片段方法?(相关问题不能解决我的问题

测试

@RunWith(AndroidJUnit4::class)
class ExampleUnitTest {
    @Test
    fun `inspection failure point to location mapping is correct`() {
        val scenario = launchFragment<ContentFragment>()
        scenario.onFragment { fragment ->
            //TODO: test logic
        }
    }
...
}
Run Code Online (Sandbox Code Playgroud)

片段类

import androidx.fragment.app.Fragment
...
class ContentFragment : Fragment() {...}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪

java.lang.ClassCastException: androidx.fragment.app.testing.FragmentScenario$EmptyFragmentActivity cannot be cast to com.nu.rms.inspections.ui.activity.InspectionActivity
    at com.nu.rms.inspections.ui.fragment.ContentFragment.clearRFIDCache(ContentFragment.kt:565)
    at com.nu.rms.inspections.ui.fragment.ContentFragment.showStep1(ContentFragment.kt:222)
    at com.nu.rms.inspections.ui.fragment.ContentFragment.access$showStep1(ContentFragment.kt:37)
    at com.nu.rms.inspections.ui.fragment.ContentFragment$onViewCreated$1.onChanged(ContentFragment.kt:77)
    at com.nu.rms.inspections.ui.fragment.ContentFragment$onViewCreated$1.onChanged(ContentFragment.kt:37)
    at androidx.lifecycle.LiveData.considerNotify(LiveData.java:113) …
Run Code Online (Sandbox Code Playgroud)

testing android unit-testing android-fragments android-fragmentactivity

2
推荐指数
1
解决办法
2492
查看次数