小编and*_*per的帖子

将应用程序上下文保存到Android中的静态变量是否安全?

我知道在Android上使用静态变量是非常危险的,特别是如果你将它们引用到活动中.但是,如果我有一个扩展Application的类(让我们称这个类为"App"),引用这个类的实例是否安全?

如果是这样,任何其他类是否也可以安全地对应用程序上下文进行任何类型的引用?我的意思是,如果我在任何类中引用应用程序上下文,是否会出现内存泄漏?

目的是无论我在哪个范围内,我总能得到对应用程序上下文的引用.我认为这是安全的,因为如果系统关闭了应用程序,静态变量也会消失,直到下次应用程序再次启动时,这将再次初始化静态变量.

此外,并不重要,但如果我使用多个进程,我会在每个进程上获得完全不同的App类引用吗?

作为代码的一个例子,这是我在想的:

public class App extends Application
{
    private static Context _appContext;

    @Override
    public void onCreate()
    {
        super.onCreate();
        _appContext = this;
    }

    public static Context getAppContext()
    {
        return _appContext;
    }
}
Run Code Online (Sandbox Code Playgroud)

static android process android-context

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

在我使用适配器设置后,RecyclerView何时完成显示项目是否有回调?

背景

我已经创建了一个库,显示了RecyclerView的快速滚动条(这里,如果有人想要),我想决定何时显示以及何时隐藏快速滚动条.

我认为一个好的决定是,如果屏幕上没有显示的项目(或者有很多项目没有出现),在RecyclerView完成布局过程后,我会将快速滚动条设置为可见,如果所有项目都已显示,则无需显示.

问题

我找不到RecyclerView的监听器/回调,告诉我它何时完成显示项目,以便我可以检查显示的项目数与项目数量相比.

在键盘出现时,recyclerView也可能会改变其大小并隐藏自己.

我试过的

滚动侦听器可能没有帮助,因为它"一直"发生,我只需要检查RecyclerView何时更改其大小或项目计数(或数据)已更改.

我可以换用通知我的大小的变化,就像一个布局RecyclerView 这一个,我做了,但我不认为它会工作作为RecyclerView大概不会准备好,告诉多少项目都可见.

检查显示的项目数量的方法可以这样使用:

    final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
    mRecyclerView.setLayoutManager(layoutManager);
    ...
    Log.d("AppLog", "visible items count:" + (layoutManager.findLastVisibleItemPosition() -layoutManager.findFirstVisibleItemPosition()+1));
Run Code Online (Sandbox Code Playgroud)

这个问题

如何在recyclerView显示其子视图时收到通知,以便我可以根据当前显示的内容来决定显示/隐藏快速滚动条?

android scrollbar android-recyclerview fast-scroller

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

在Android中使用新的"manifestmerger"属性

在最新版本的ADT(版本20预览版3)中,他们说可以使库的清单文件与使用它们的项目合并:

将库项目清单文件自动合并到包含项目的清单中.使用manifestmerger.enabled属性启用.

我如何以及在何处使用它?我无法在任何地方看到内容帮助我.

android adt android-manifest android-library

43
推荐指数
3
解决办法
2万
查看次数

在活动之上创建透明对话框

背景

我试图在当前活动的基础上放置一个图层,该图层将解释当前屏幕上发生的情况,类似于contact + app上发生的情况.

我知道有一些解决方案(比如showCase库和superToolTips库),我也知道我可以通过将它添加到活动窗口来创建一个视图并将其设置在顶部,但我需要放一个整体顶部的对话框层.

问题

无论我尝试什么,每个解决方案都不能像我需要的那样工作.

简而言之,我需要的是:

  • 全屏对话框.

  • 操作栏,通知栏和后面活动的内容没有变化(不是视觉和非逻辑),这意味着对话框后面的所有内容都与显示对话框之前显示的内容保持一致.

  • 除了我用于对话框的视图外,它应该是透明的,应该正常显示.

我试过的

可悲的是,我总是只得到我需要的一部分东西.

这是我的代码:

styles.xml:

<style name="full_screen_dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
        <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
    </style>
Run Code Online (Sandbox Code Playgroud)

MainActivity.java:

...
final Dialog dialog = new Dialog(this, R.style.full_screen_dialog);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.floating_tutorial);
dialog.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
dialog.getWindow().setFormat(PixelFormat.TRANSLUCENT);
dialog.show();
Run Code Online (Sandbox Code Playgroud)

此代码将布局放在活动的顶部,但遗憾的是它没有任何透明度,即使我已经设置了它.我使用的布局非常简单,这就是我不发布的原因.

我错过了什么?应该怎么做来修复代码?

如何使对话框既透明又全屏,并且不会更改操作栏和通知栏.


工作方案

编辑:找到一个好的解决方案后,这是工作代码:

@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final Dialog dialog = new Dialog(this);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(R.layout.floating_tutorial);
    final Window window = dialog.getWindow();
    window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
    window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); …
Run Code Online (Sandbox Code Playgroud)

android dialog transparent android-fullscreen

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

如何模仿Material-design凸起的按钮样式,即使对于前Lollipop(减去特殊效果)?

谷歌已经展示了一些很好的方式,按钮在这里显示在棒棒糖上.

我在谈论凸起和平面按钮.

除了特殊效果(波纹等......)之外,我怎样才能在Lollipop前版本上模仿它们?

我在说这个这个.

当然,在棒棒糖及以上,我想使用特效.

我知道有很多(甚至很多)关于这个的帖子,但我没有看到任何试图完全模仿它.

android android-button material-design android-5.0-lollipop

42
推荐指数
3
解决办法
4万
查看次数

如何在Android内部共享使用即时运行时创建的拆分APK?

背景

我有一个应用程序(这里),除了其他功能,允许共享APK文件.

为了做到这一点,它通过访问packageInfo.applicationInfo.sourceDir(这里是 docs链接)的路径到达文件,并且只是共享文件(在需要时使用ContentProvider,就像我在这里使用的那样).

问题

这在大多数情况下都可以正常工作,尤其是从Play商店或独立的APK文件安装APK文件时,但是当我使用Android-Studio本身安装应用程序时,我在此路径上看到多个APK文件,而且没有一个是有效的,可以安装和运行没有任何问题.

这是从"Alerter"github repo中试用样本后该文件夹内容的屏幕截图 :

在此输入图像描述

我不确定这个问题何时开始,但至少在我的Nexus 5x和Android 7.1.2上确实发生过.也许甚至以前.

我发现了什么

这似乎只是因为在IDE上启用了即时运行这一事实,因此它可以帮助更新应用程序,而无需一起重新构建它:

在此输入图像描述

禁用它后,我可以看到有一个APK,就像过去一样:

在此输入图像描述

您可以在正确的APK和分割的APK之间看到文件大小的差异.

此外,似乎有一个API来获取所有分裂的APK的路径:

https://developer.android.com/reference/android/content/pm/ApplicationInfo.html#splitPublicSourceDirs

这个问题

什么应该是最简单的方式来共享一个被分成多个的APK?

真的需要以某种方式合并它们吗?

根据文档似乎有可能:

零或更多拆分APK的完整路径,当与sourceDir中定义的基本APK结合使用时,形成一个完整的应用程序.

但是这样做的正确方法是什么,并且有一种快速有效的方法吗?也许没有真正创建文件?

是否有一个API可以从所有拆分的APK中获得合并的APK?或者也许这样的APK已经存在于其他路径中,并且不需要合并?

编辑:刚刚注意到,我尝试过的所有第三方应用程序都应该共享已安装的应用程序的APK,在这种情况下无法执行此操作.

android apk android-instant-run

42
推荐指数
1
解决办法
5602
查看次数

setExpedited 是如何工作的?它是否与前台服务一样好且可靠?

背景

以前我都是用一个前台的IntentService来处理纷至沓来的各种事件。然后当 Android 11 到来时(Android R,API 30)它就被弃用了,据说更喜欢使用使用setForegroundAsync 的Worker ,所以我就这么做了。

val builder = NotificationCompat.Builder(context,...)...
setForegroundAsync(ForegroundInfo(notificationId, builder.build()))
Run Code Online (Sandbox Code Playgroud)

问题

随着 Android 12 的到来(Android S,API 31),仅在之后的一个版本,现在setForegroundAsync被标记为已弃用,并且我被告知要使用setExpedited来代替:

* @deprecated Use {@link WorkRequest.Builder#setExpedited(OutOfQuotaPolicy)} and
* {@link ListenableWorker#getForegroundInfoAsync()} instead.
Run Code Online (Sandbox Code Playgroud)

问题是,我不确定它到底是如何工作的。之前,我们有一个通知,当用户使用前台服务时应该向用户显示该通知(至少对于“旧”Android 版本)。现在看来getForegroundInfoAsync用于它,但我认为它不会用于 Android 12 :

在 Android S 之前,WorkManager 代表您管理和运行前台服务来执行 WorkRequest,显示 ForegroundInfo 中提供的通知。要随后更新此通知,应用程序可以使用NotificationManager。

从 Android S 及更高版本开始,WorkManager 使用即时作业来管理此 WorkRequest。

关于它的另一个线索是(这里):

从 WorkManager 2.7.0 开始,您的应用程序可以调用 setExpedited() 来声明 Worker 应使用加急作业。这个新 API 在 Android 12 上运行时使用加急作业,并且该 API 使用以前版本的 Android …

android android-workmanager android-12

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

是否有其他方法可以使用Google的应用内结算功能,以避免发布私人信息?

背景

从今年9月30日(本月底)开始,Google不允许销售使用应用内结算的应用和开发者的开发者展示他们的应用,而不会显示他们的地址.这是他们写的:

添加实际联系地址从2014年9月30日开始,您需要在"设置"页面中添加实际地址.添加地址后,您可以在应用的详细信息页面上向Google Play上的所有用户显示该地址.如果您的实际地址发生变化,请务必在"设置"页面上更新您的信息.

如果您通过应用内购买付费应用或应用,则必须提供实际地址,以便您可以与该内容的销售商联系,以遵守消费者保护法.如果您未在自己的帐户中提供实际地址,则可能会导致您的应用从Play商店中移除.

有很多关于这个新要求的文章:

甚至有请愿反对它,在这里:

我已经要求在这里找到解决方案.

问题

由于我没有真正的公司,我不喜欢我实际需要发布我的家庭住址的事实.

对我来说,这是一个隐私问题,因为我并不总是在家里使用应用程序(加上它更像是一种爱好).

我的应用程序是免费使用的,它的应用内结算仅用于删除广告.而已.

在使用应用内结算时,它不会添加任何功能,用户可以自由支付任何他想要的费用作为捐赠.

我不想发布我的地址,根据我读过的内容,你甚至不能使用邮政信箱(无论如何要花钱),因为他们特别要求"实际地址"而不是"邮政地址".

这个问题

由于我可能无法使用Google的应用内结算并避免使用我的家庭住址,因此使用其他公司的其他服务是否可行(并且合法且根据Google规则)?

如果是这样,哪些公司提供类似的服务?

如果没有,是否有任何替代方案或解决方案?

可能有一个解决方法或漏洞,允许我发布这样的应用程序,但没有理由发布我的家庭地址?

android ads in-app-billing google-play

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

如何检查是否给出了"android.permission.PACKAGE_USAGE_STATS"权限?

背景

我正在尝试获取应用程序启动的统计信息,并且在Lollipop上可以通过使用UsageStatsManager类来实现(原始帖子在这里):

表现:

<uses-permission
    android:name="android.permission.PACKAGE_USAGE_STATS"
    tools:ignore="ProtectedPermissions"/>
Run Code Online (Sandbox Code Playgroud)

打开活动,让用户确认给您这个权限:

startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
Run Code Online (Sandbox Code Playgroud)

获取统计数据,汇总:

 private static final String USAGE_STATS_SERVICE ="usagestats"; // Context.USAGE_STATS_SERVICE);
 ...
 final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService(USAGE_STATS_SERVICE);
 final Map<String,UsageStats> queryUsageStats=usageStatsManager.queryAndAggregateUsageStats(fromTime,toTime);
Run Code Online (Sandbox Code Playgroud)

问题

我似乎无法检查是否授予您所需的权限("android.permission.PACKAGE_USAGE_STATS").到目前为止我所做的一切总是会让人感到被拒绝.

代码有效,但权限检查不起作用.

我试过的

您可以使用以下任一方法检查是否授予了权限:

String permission = "android.permission.PACKAGE_USAGE_STATS";
boolean granted=getContext().checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;   
Run Code Online (Sandbox Code Playgroud)

或这个:

String permission = "android.permission.PACKAGE_USAGE_STATS";
boolean granted=getPackageManager().checkPermission(permission,getPackageName())== PackageManager.PERMISSION_GRANTED;   
Run Code Online (Sandbox Code Playgroud)

两者总是返回它被拒绝(即使我已经授予用户权限).

看看UsageStatsManager的代码,我试图想出这个解决方法:

      UsageStatsManager usm=(UsageStatsManager)getSystemService("usagestats");
      Calendar calendar=Calendar.getInstance();
      long toTime=calendar.getTimeInMillis();
      calendar.add(Calendar.YEAR,-1);
      long fromTime=calendar.getTimeInMillis();
      final List<UsageStats> queryUsageStats=usm.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,fromTime,toTime);
      boolean granted=queryUsageStats!=null&&queryUsageStats!=Collections.EMPTY_LIST;
Run Code Online (Sandbox Code Playgroud)

它工作,但它仍然是一个解决方法.

这个问题

为什么我没有得到权限检查的正确结果?

应该怎么做才能更好地检查?

permissions android usage-statistics android-recents usagestatsmanager

40
推荐指数
2
解决办法
2万
查看次数

如何使用Android API记录屏幕并截取屏幕截图?

背景

Android在Kitkat和Lollipop上获得了新的API,用于视频捕获屏幕.您可以通过ADB工具或通过代码(从Lollipop开始)来完成.

自新API发布以来,许多应用程序都使用此功能,允许记录屏幕,微软甚至制作了自己的Google-Now-On-tap竞争对手应用程序.

使用ADB,您可以使用:

adb shell screenrecord /sdcard/video.mp4 
Run Code Online (Sandbox Code Playgroud)

您甚至可以在Android Studio内部执行此操作.

问题

我找不到任何有关如何使用API​​的教程或解释,这在代码中是有意义的.

我发现了什么

我找到的唯一的地方是文件(这里,在"屏幕截图和分享"下),告诉我这个:

Android 5.0允许您使用新的android.media.projection API为您的应用添加屏幕捕获和屏幕共享功能.例如,如果要在视频会议应用中启用屏幕共享,此功能很有用.

createVirtualDisplay()方法允许您的应用程序将主屏幕的内容(默认显示)捕获到Surface对象中,然后您的应用可以通过网络发送该对象.API仅允许捕获非安全屏幕内容,而不是系统音频.要开始屏幕捕获,您的应用必须首先通过使用通过该createScreenCaptureIntent()方法获得的Intent启动屏幕捕获对话框来请求用户的许可.

有关如何使用新API的示例,请参阅示例项目中的MediaProjectionDemo类.

事实是,我找不到任何"MediaProjectionDemo"样本.相反,我发现了"屏幕截图"样本,但我不明白它是如何工作的,因为当我运行它时,我所看到的只是一个闪烁的屏幕,我不认为它将视频保存到一份文件.样本看起来非常错.

问题

如何使用新API执行这些操作:

  1. 开始录音,可选择包括音频(麦克风/扬声器/两者).
  2. 停止录音
  3. 截取屏幕截图而不是视频.

另外,我如何自定义它(分辨率,请求的fps,颜色,时间......)?

android screenshot screen-recording android-4.4-kitkat android-5.0-lollipop

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