开发者控制台

通过性能和稳定性实现应用质量

Moses Roth Mar 13, 2025
Share:
Best practices
Blog_Header_Post_Img

在您为亚马逊Fire设备构建应用时,让您的功能始终正常运作无疑非常重要。构建优秀的应用也意味着要创造一种流畅可靠的用户体验。崩溃、延迟和糟糕的用户界面交互会导致负面评价,甚至导致用户卸载应用。没有开发者希望看到这种事情发生。

因此,解决性能问题并保持应用稳定是应用开发者使命当中非常重要的部分。这两个方面是让用户满意并确保应用成功的关键。值得庆幸的是,借助亚马逊开发者控制台中的工具(例如应用运行状况洞察控制面板),可以更轻松地发现问题并进行正确的修复。

本指南将引导您了解如何理解控制面板以及需要注意的方面。您会收获许多提高应用性能和稳定性的技巧。您准备好确保应用在每个Fire设备上都有上佳表现了吗?那么我们开始吧!

应用运行状况洞察控制面板简介

应用运行状况洞察控制面板是一种强大的工具,可帮助您了解应用的表现。它提供关键指标和有用见解,让您可以专注于解决最重要的问题。

要访问它,您需要有上线应用。要开始使用,请执行以下操作:

  1. 转到开发者控制台主信息页面
  2. 在顶部导航栏中,单击应用与服务
  3. 打开您的应用的“操作”菜单
  4. 单击“应用运行状况洞察”

控制面板概览

控制面板分为两个主要部分:性能控制面板和稳定性控制面板。每个部分都侧重于应用运行状况的一个特定方面。

  • 性能控制面板:此区域可跟踪应用启动时间和帧速率等指标,帮助您了解应用的运行流畅度以及它对用户交互的响应速度。
  • 稳定性控制面板: 在这里,您可以找到有关崩溃率、应用无响应 (ANR) 错误和其他可能让用户感到懊恼的稳定性相关问题的数据。

有了此类数据,您不必再为寻找问题根源而烦恼,可以清楚地看到问题所在并立即解决问题。
 

为什么控制面板很有用

对于开发者而言,时间很宝贵。控制面板让您无需在数量庞大的日志中挖掘有用信息或被动等待用户投诉。它能够突显应用中最关键的问题,让您优先考虑对用户体验影响最大的修复措施。通过尽早解决这些问题,您可以减少负面评价并提高留存率。

性能控制面板指标

性能控制面板可帮助您衡量应用的效率。通过关注数项关键指标,您可以发现和解决影响用户体验的瓶颈。

应用延迟指标

应用延迟指标跟踪应用启动方式的两个关键方面:应用启动时间和准备就绪时间。

Amazon developer security profiles menu image

这两个指标都至关重要,因为它们会影响用户对速度和响应能力的感知。超出这些基准可能会让人感觉应用速度缓慢,并导致用户懊恼。

要缩短应用的启动时间和准备就绪时间,您可以采取以下措施:

  • 实现延迟加载:仅在实际需要资源时才加载资源。禁用非关键库的自动初始化。使用Android Studio性能分析器来确定哪些资源加载所需时间最长。利用此技巧可以显著减少应用启动期间的初始数据和资源开销。
  • 优化初始用户界面:从可以快速绘制的简单、静态用户界面开始。将占位符用于视图而不是复杂的布局,并将密集的动画和绘图操作推迟到调用reportFullyDrawn()之后。这种方法有助于让用户立即看到一些内容,而应用的其余部分同时继续在后台加载。
  • 改进数据管理效率:使用文件系统操作而不是数据库进行初始数据加载,这有助于显著加快应用的启动速度。考虑将相关数据直接序列化到文件系统,以便更快地进行检索。以下示例实现了初始呈现给用户的数据的快速序列化和反序列化:

Copied to clipboard
public void serialize(Context context, String filename, 
                      Serializable object) throws Exception {
  FileOutputStream fOut = 
    context.openFileOutput(filename, Context.MODE_PRIVATE);
  ObjectOutputStream oOut = new ObjectOutputStream(fOut);
  oOut.writeObject(object);
  oOut.close();
}

public Object deserialize(Context context, 
                          String filename) throws Exception {
  FileInputStream fIn = context.openFileInput(filename);
  ObjectInputStream oIn = new ObjectInputStream(fIn);
  Object result = oIn.readObject();
  oIn.close();

  return result;
}
Copied to clipboard
private val executor = Executors.newSingleThreadExecutor()

fun <T : Serializable> serialize(context: Context, filename: String, data: T) {
    executor.execute {
        try {
            context.openFileOutput(filename, Context.MODE_PRIVATE).use { fileOut ->
                ObjectOutputStream(fileOut).use { objOut ->
                    objOut.writeObject(data)
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

fun <T : Serializable> deserialize(context: Context, filename: String, callback: (T?) -> Unit) {
    executor.execute {
        val result: T? = try {
            context.openFileInput(filename).use { fileIn ->
                ObjectInputStream(fileIn).use { objIn ->
                    @Suppress("UNCHECKED_CAST")
                    objIn.readObject() as? T
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
        callback(result)
    }
}

作为上述传统序列化方法的替代方案,可考虑使用Flatbuffers来实现灵活且高效使用内存的方法。

  • 使用后台线程:在加载应用时,利用后台线程执行任务。这样可以从主线程移走资源密集的操作,有助于减少用户等待应用变得可供使用的时间。
  • 衡量和迭代:使用Android性能工具来采集宏基准指标。在多次衡量后计算平均启动时间,以了解应用的性能并确定需要改进的方面。

有关这些建议的更多详细信息和代码示例,请查看如何衡量和改进Fire OS中的应用启动时间

内存使用方面的前台低内存终止事件

前台低内存终止事件 (LME) 指标衡量的是导致设备上应用终止的前台低内存事件的每日平均实例数。如果即使系统终止了所有非持久性后台应用或服务,仍然内存不足,就会发生前台LME。此指标有助于您了解应用遭遇严重内存限制的频率,这类限制会导致强制关闭应用。

Amazon developer security profiles menu image

能否尽量减少这类事件取决于应用的内存使用情况。当然,这也取决于您应用的复杂度。然而,作为一种基本基准,应尽量将游戏应用的前台内存消耗限制在1000MB以下,将非游戏应用应限制在600MB以下。过度使用内存会触发频繁的LME,这可能导致应用不稳定或崩溃,尤其是在资源有限的设备上。

有关管理应用内存的综合指南,请参阅有关减少应用内存使用量的Android开发者页面。以下策略归纳了该资源中的关键要点,帮助您减少内存使用量并提高应用的性能:

  • 实现内存监控:使用Android Studio中的内存分析器来跟踪您的应用如何分配和使用内存。此工具可帮助您发现内存密集型代码段,并了解应用随时间推移的内存消耗模式。
  • 优化内存回调:实现ComponentCallbacks2接口以主动管理内存使用情况。这样可让您的应用在系统内存不足时智能地进行响应。示例如下:

Copied to clipboard
public class MainActivity extends AppCompatActivity
  implements ComponentCallbacks2 {

  // Other activity code.

  /**
   * Release memory when the UI becomes hidden or when system
   * resources become low.
   * @param level the memory-related event that is raised.
   */
  public void onTrimMemory(int level) {

    if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
      // Release memory related to UI elements, such as bitmap caches.
    }
    if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
      // Release memory related to background processing, such as by
      // closing a database connection.
    }
  }
}
Copied to clipboard
import android.app.Activity
import android.content.ComponentCallbacks2
import android.content.res.Configuration
import android.os.Bundle
import android.util.Log

class MainActivity : Activity(), ComponentCallbacks2 {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        registerComponentCallbacks(this)
    }

    override fun onTrimMemory(level: Int) {
        when {
            level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN -> {
                // Release memory related to UI elements, such as bitmap caches
                Log.d("MemoryTrim", "UI is hidden. Freeing up UI-related resources.")
            }
            level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> {
                // Release memory related to background processing, such as closing a database connection
                Log.d("MemoryTrim", "App in background. Releasing background resources.")
            }
        }
    }

    override fun onLowMemory() {
        // Handle extreme low-memory situations
        Log.w("MemoryTrim", "System is running low on memory!")
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        // Required override but not used for memory management
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterComponentCallbacks(this)
    }
}

  • 高效使用内存的编码:避免在性能关键区域创建不必要的对象。使用对象池来减少分配开销,并特别注意内部循环或绘制方法中的对象创建。

  • 资源和库管理:删除不必要的库并减小APK大小。使用代码缩减工具消除未使用的代码并优化应用的内存占用量。

  • 服务管理:谨慎使用服务,并在服务完成任务后立即将服务停止。避免不必要的服务在后台运行,这样会消耗内存。

  • 主动的内存检查:在执行内存密集型操作之前,请检查设备内存状态。这有助于防止您的应用在系统资源受限时运行操作:

     

Copied to clipboard
public void doSomethingMemoryIntensive() {

  // Before doing something that requires a lot of memory,
  // check whether the device is in a low memory state.
  ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();
    if (!memoryInfo.lowMemory) {
      // Do memory intensive work.
  }
}

// Get a MemoryInfo object for the device's current memory status.
private ActivityManager.MemoryInfo getAvailableMemory() {
  ActivityManager activityManager =
    (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
  ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
  activityManager.getMemoryInfo(memoryInfo);
  return memoryInfo;
}
Copied to clipboard
import android.content.Context

fun Context.isMemoryLow(): Boolean {
    val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val memoryInfo = ActivityManager.MemoryInfo()
    activityManager.getMemoryInfo(memoryInfo)
    return memoryInfo.lowMemory
}

fun doSomethingMemoryIntensive(context: Context) {
    if (!context.isMemoryLow()) {
        // Perform memory-intensive operation
    }
}

  • 依赖项注入:考虑使用依赖项注入框架,这样有助于更有效地管理对象创建和生命周期。这类框架可以通过提供一种更可控的对象依赖项创建和管理方式来减少内存开销。
     
与掉帧率有关的流畅度

流畅度通过跟踪掉帧率来衡量动画和过渡的平滑度。此指标突显渲染过程中跳过帧的频率,这种情况会使您的应用显得不稳定,响应速度较慢。

亚马逊应用商店应用的测试标准中规定:

应用应保持高帧速率,在较长时间内帧速率不会降至25fps以下。建议的平均帧速率为55-60fps,特别是存在快速移动图形对象的应用。

为了获得流畅的体验,应用的掉帧率应低于5%。掉帧率如果超过10%,会显著降低用户体验,使应用显得反应迟缓和质量低下。

要提高流畅度,应简化复杂的动画并减少同时渲染的对象数量。通过确保GPU的高效使用,以及在过渡期间最大限度减少不必要的计算,优化渲染任务。Android Studio Performance Profiler(性能分析器)中的工具Jank Detection(卡顿检测)(仅提供英文版),以及Profile GPU Rendering(GPU渲染分析)等工具可以帮助您有效地查明和解决渲染问题。


稳定性控制面板指标

稳定性控制面板可帮助您发现和解决可能导致应用崩溃、挂起或以其他方式困扰用户的问题。通过监控数项关键指标,您可以主动提高应用的可靠性和用户体验。

Amazon developer security profiles menu image

崩溃率

崩溃率衡量应用相对于用户会话数崩溃的频率。这一指标至关重要,因为频繁的崩溃会很快导致差评和卸载。

对于良好的应用而言,崩溃率应保持在1%以下。崩溃率超过这一基准的应用存在让用户感觉不友好和降低信任度的风险。要降低崩溃率,开发者应该实施以下推荐Android开发者使用的策略

  • 进行彻底的null检查,以防止NullPointerException的实例,这是应用崩溃的常见原因。

  • 用@Nullable和@NonNull来注释方法参数和返回值,以在编译时捕捉潜在的与null相关的问题。

  • 使用特定的catch块而不是一般的异常处理来小心地处理异常。

  • 对不同型号的Fire平板电脑进行综合测试。

  • 实现适当的日志记录以捕获详细的错误信息。

通过系统地做到上述几点,开发者可以显著降低崩溃率,提高Fire平板电脑上应用的整体稳定性。

应用没有响应 (ANR) 错误

如果应用的主线程长时间没有响应,导致系统通知用户应用无法运行,就会发生ANR错误。这通常会导致用户强制退出您的应用。

良好的应用应达到低于0.47%的ANR率。如果比率高于上述数值,则表示您的应用可能存在性能瓶颈或主线程上的操作受到阻碍。

要解决ANR问题,请实现以下建议的修复措施

Copied to clipboard
// Bad example: Performing time-consuming task on the main thread
public void onClick(View v) {
  // This will block the UI and potentially cause an ANR
  Bitmap bitmap = processBitMap("image.png");
  imageView.setImageBitmap(bitmap);
}

// Good example: Moving time-consuming task to a background thread
public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      // A potentially time-consuming task performed off the main thread
      final Bitmap bitmap = processBitMap("image.png");


      // Use post() to update UI safely from the main thread
      imageView.post(new Runnable() {
        public void run() {
          imageView.setImageBitmap(bitmap);
        }
      });
    }
  }).start();
}
Copied to clipboard
import android.graphics.Bitmap
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.ImageView
import java.util.concurrent.Executors

class MyActivity {

    private val executor = Executors.newSingleThreadExecutor()
    private val mainHandler = Handler(Looper.getMainLooper())

    fun onClick(view: View, imageView: ImageView) {
        executor.execute {
            // Perform time-consuming task in background thread
            val bitmap = processBitmap("image.png")

            // Update UI safely on the main thread
            mainHandler.post {
                imageView.setImageBitmap(bitmap)
            }
        }
    }

    private fun processBitmap(filename: String): Bitmap {
        // Simulate bitmap processing (e.g., decoding an image)
        Thread.sleep(2000) // Simulate delay
        return Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
    }
}

  • 避免主线程上发生同时进行的I/O操作。
  • 将冗长计算分解为更小、更易于管理的块。
  • 防止主线程和工作线程之间发生锁争用。
  • 在开发过程中使用StrictMode来检测意外的主线程I/O。
  • 对于广播接收器,对长时间运行的操作使用IntentServicegoAsync()
  • 使用Android Studio CPU Profiler等工具,定期分析您的应用,以确定性能瓶颈。

 

其他注意事项

除了性能和稳定性控制面板,还有其他因素需要牢记,以确保您的应用尽可能提供最佳体验:

  • 电池效率:通过优化后台流程和减少资源密集型任务,最大限度地减少电池消耗。
  • 网路使用:通过在适当的情况下缓存数据并优化API调用,限制过度的数据使用。
  • 设备兼容性:在各种Fire平板电脑型号上测试您的应用,以确保一致的性能和功能。
  • 可用性:注重直观的设计和直观的导航,以提升用户满意度。
  • 内容质量:提供与用户相关、引人入胜且针对Fire平板电脑显示屏进行了优化的高质量内容。
  • 无障碍功能:整合无障碍功能,如屏幕阅读器支持、高对比度模式和触摸友好界面,让您的应用具有包容性。

结论

要为Fire设备创建高质量应用需要注重性能和稳定性。借助应用运行状况洞察控制面板,开发者可以专注于关键指标,以确保自己所提供的应用具有流畅可靠的体验,让用户不断使用应用。

有兴趣进一步探索? 以下资源将在您不断提高应用质量的旅程中提供帮助:

相关文章

最新文章

 

查看有关亚马逊应用商店、应用开发与盈利、亚马逊服务以及更多主题的最新消息。