Android App开发音量调节中实现拖动条和滑动条和音频管理器AudioManager讲解及实战(超详细 附源码和演示视频)

简介: Android App开发音量调节中实现拖动条和滑动条和音频管理器AudioManager讲解及实战(超详细 附源码和演示视频)

需要源码请点赞关注收藏后评论区留下QQ~~~

一、拖动条和滑动条

拖动条SeekBar继承自进度条ProgressBar,它与进度条的不同之处在于,进度条只能在代码中修改进度值,不能由用户改变进度值,拖动条不仅可以在代码中修改进度值,还可以由用户拖动操作改变进度值,在播放音频和视频时,用户通过拖动条控制播放器快进或快退到指定位置,然后从新位置开始播放,除此之外,拖动条还可以调节音量大小,屏幕亮度,字体大小等

尽管拖动条在多数情况下够用了,但它有一个毛病,拖动之后用户不能直观的看到当前进度值是多少,为此Android设计了全新的滑动条空间Slider,首先要增加以下配置

implementaion 'com.google.android.materia:material:1.4.0'

运行效果如下 可以手动点击控制音量

代码如下

Java类

package com.example.audio;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.slider.Slider;
public class SliderActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_slider);
        SeekBar sb_progress = findViewById(R.id.sb_progress);
        sb_progress.setOnSeekBarChangeListener(mSeekListener); // 设置拖动条的拖动监听器
        Slider sl_progress = findViewById(R.id.sl_progress);
        sl_progress.addOnSliderTouchListener(mSliderListener); // 设置滑动条的触摸监听器
    }
    private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
        // 在进度变更时触发。第三个参数为true表示用户拖动,为false表示代码设置进度
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
        // 在开始拖动进度时触发
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {}
        // 在停止拖动进度时触发
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            Toast.makeText(SliderActivity.this, "您选择的进度是"+seekBar.getProgress(),
                    Toast.LENGTH_SHORT).show();
        }
    };
    private Slider.OnSliderTouchListener mSliderListener = new Slider.OnSliderTouchListener() {
        // 在开始滑动进度时触发
        @Override
        public void onStartTrackingTouch(Slider slider) {}
        // 在停止滑动进度时触发
        @Override
        public void onStopTrackingTouch(Slider slider) {
            Toast.makeText(SliderActivity.this, "您选择的进度是"+slider.getValue(),
                    Toast.LENGTH_SHORT).show();
        }
    };
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:gravity="center"
        android:text="下面是拖动条"
        android:textColor="@color/black"
        android:textSize="17sp" />
    <SeekBar
        android:id="@+id/sb_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:max="100"
        android:progress="50"
        android:thumb="@drawable/seekbar_point" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:gravity="center"
        android:text="下面是来自MaterialDesign库的滑动条"
        android:textColor="@color/black"
        android:textSize="17sp" />
    <com.google.android.material.slider.Slider
        android:id="@+id/sl_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:stepSize="1"
        android:valueFrom="0"
        android:valueTo="100"
        android:value="0" />
</LinearLayout>

二、音频管理器

Android只有一个麦克风,却管理着6种铃声,分别是通话音,系统音,铃音,闹钟音,通知音等

管理这些铃声音量的工具是音频管理器AudioManager 下面是它的常用方法

getStreamMaxVolume 获取指定类型铃声的最大音量

getStreamVolume 获取指定类型铃声的当前音量

getRingerMode 获取指定类型铃声的响铃模式

音量调整效果如下 这个设置页面不但允许通过拖动条将音量直接调整到目标值,还允许通过加减按钮逐级调大或者调小音量

可以拖动条也可以点击按钮来调节

代码如下

Java类

package com.example.audio;
import android.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import androidx.appcompat.app.AppCompatActivity;
public class AudioManagerActivity extends AppCompatActivity implements OnSeekBarChangeListener, OnClickListener {
    private static final String TAG = "VolumeManagerActivity";
    private SeekBar sb_voice, sb_system, sb_ring, sb_music, sb_alarm, sb_notify;
    private ImageView iv_volumn_up, iv_system_up, iv_ring_up, iv_music_up, iv_alarm_up, iv_notify_up;
    private ImageView iv_volumn_down, iv_system_down, iv_ring_down, iv_music_down, iv_alarm_down, iv_notify_down;
    private int[] mStreamType = { // 音频流类型数组
            AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_SYSTEM,
            AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
            AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION};
    private int[] mMaxVolume = {0, 0, 0, 0, 0, 0}; // 最大音量数组
    private int[] mNowVolume = {0, 0, 0, 0, 0, 0}; // 当前音量数组
    private SeekBar[] mSeekBar = { // 拖动条的控件数组
            sb_voice, sb_system, sb_ring,
            sb_music, sb_alarm, sb_notify};
    private int[] mStreamRes = { // 拖动条的资源编号数组
            R.id.sb_voice, R.id.sb_system, R.id.sb_ring,
            R.id.sb_music, R.id.sb_alarm, R.id.sb_notify};
    private ImageView[] mAddView = { // 增大音量按钮的控件数组
            iv_volumn_up, iv_system_up, iv_ring_up,
            iv_music_up, iv_alarm_up, iv_notify_up};
    private int[] mAddRes = { // 增大音量按钮的资源编号数组
            R.id.iv_volumn_up, R.id.iv_system_up, R.id.iv_ring_up,
            R.id.iv_music_up, R.id.iv_alarm_up, R.id.iv_notify_up};
    private ImageView[] mDelView = { // 减小音量按钮的控件数组
            iv_volumn_down, iv_system_down, iv_ring_down,
            iv_music_down, iv_alarm_down, iv_notify_down};
    private int[] mDelRes = { // 减小音量按钮的资源编号数组
            R.id.iv_volumn_down, R.id.iv_system_down, R.id.iv_ring_down,
            R.id.iv_music_down, R.id.iv_alarm_down, R.id.iv_notify_down};
    private int SEEK_BAR = 1, ADD_VIEW = 2, DEL_VIEW = 3;
    private AudioManager mAudioMgr; // 声明一个音频管理器对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_audio_manager);
        // 从布局文件中依次获取各音量类型的拖动条、增大音量按钮、减小音量按钮
        for (int i = 0; i < mStreamType.length; i++) {
            mSeekBar[i] = findViewById(mStreamRes[i]);
            mAddView[i] = findViewById(mAddRes[i]);
            mDelView[i] = findViewById(mDelRes[i]);
        }
        setStreamVolume(); // 设置各音量类型的拖动条进度
        for (int i = 0; i < mStreamType.length; i++) {
            // 给各音量类型的拖动条设置拖动变更监听器
            mSeekBar[i].setOnSeekBarChangeListener(this);
            // 给各音量类型的增大音量按钮设置点击监听器
            mAddView[i].setOnClickListener(this);
            // 给各音量类型的减小音量按钮设置点击监听器
            mDelView[i].setOnClickListener(this);
        }
    }
    // 设置各音量类型的拖动条进度
    void setStreamVolume() {
        // 从系统服务中获取音频管理器
        mAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        for (int i = 0; i < mStreamType.length; i++) {
            int type = mStreamType[i];
            // 获取指定音频类型的最大音量
            mMaxVolume[i] = mAudioMgr.getStreamMaxVolume(type);
            // 获取指定音频类型的当前音量
            mNowVolume[i] = mAudioMgr.getStreamVolume(type);
            // 设置拖动条的音量大小进度
            mSeekBar[i].setProgress(mSeekBar[i].getMax() * mNowVolume[i] / mMaxVolume[i]);
        }
    }
    // 在进度变更时触发。第三个参数为true表示用户拖动,为false表示代码设置进度
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
    // 在开始拖动进度时触发
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {}
    // 在停止拖动进度时触发
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        Log.d(TAG, "当前进度为:" + seekBar.getProgress() + ", 最大进度为" + seekBar.getMax());
        int index = getArrayIndex(seekBar.getId(), SEEK_BAR);
        int type = mStreamType[index];
        int volume = mMaxVolume[index] * seekBar.getProgress() / seekBar.getMax();
        Log.d(TAG, "volume=" + volume + ", last volume=" + mNowVolume[index] + ", max volume=" + mMaxVolume[index]);
        if (volume != mNowVolume[index]) {
            mNowVolume[index] = volume;
            // 根据拖动位置,计算并设置拖动条的当前进度
            seekBar.setProgress(seekBar.getMax() * mNowVolume[index] / mMaxVolume[index]);
        }
        // 设置该音频类型的当前音量
        mAudioMgr.setStreamVolume(type, volume, AudioManager.FLAG_PLAY_SOUND);
    }
    @Override
    public void onClick(View v) {
        int add_index = getArrayIndex(v.getId(), ADD_VIEW);
        int del_index = getArrayIndex(v.getId(), DEL_VIEW);
        if (add_index != -1) { // 点击了增大音量按钮
            SeekBar seekBar = mSeekBar[add_index];
            if (mNowVolume[add_index] < mMaxVolume[add_index]) {
                mNowVolume[add_index] = mNowVolume[add_index] + 1;
                // 设置拖动条的音量大小进度
                seekBar.setProgress(seekBar.getMax() * mNowVolume[add_index] / mMaxVolume[add_index]);
                // 把该音频类型的当前音量调大一级
                mAudioMgr.adjustStreamVolume(mStreamType[add_index], AudioManager.ADJUST_RAISE, AudioManager.FLAG_PLAY_SOUND);
            }
        } else if (del_index != -1) { // 点击了减小音量按钮
            SeekBar seekBar = mSeekBar[del_index];
            if (mNowVolume[del_index] > 0) {
                mNowVolume[del_index] = mNowVolume[del_index] - 1;
                // 设置拖动条的音量大小进度
                seekBar.setProgress(seekBar.getMax() * mNowVolume[del_index] / mMaxVolume[del_index]);
                // 把该音频类型的当前音量调小一级
                mAudioMgr.adjustStreamVolume(mStreamType[del_index], AudioManager.ADJUST_LOWER, AudioManager.FLAG_PLAY_SOUND);
            }
        }
    }
    // 根据资源编号与类型寻找它在对应数组中的位置
    private int getArrayIndex(int resid, int type) {
        int index = -1;
        if (type == SEEK_BAR) { // 这是拖动条
            for (int i = 0; i < mSeekBar.length; i++) {
                if (mSeekBar[i].getId() == resid) {
                    index = i;
                    break;
                }
            }
        } else if (type == ADD_VIEW) { // 这是增大音量按钮
            for (int i = 0; i < mAddView.length; i++) {
                if (mAddView[i].getId() == resid) {
                    index = i;
                    break;
                }
            }
        } else if (type == DEL_VIEW) { // 这是减小音量按钮
            for (int i = 0; i < mDelView.length; i++) {
                if (mDelView[i].getId() == resid) {
                    index = i;
                    break;
                }
            }
        }
        return index;
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:orientation="horizontal" >
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="bottom|center_horizontal"
                    android:text="调节通话音量"
                    android:textColor="#000000"
                    android:textSize="17sp" />
                <ImageView
                    android:id="@+id/iv_volumn_down"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="30dp"
                    android:src="@drawable/volumn_down" />
                <ImageView
                    android:id="@+id/iv_volumn_up"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="50dp"
                    android:src="@drawable/volumn_up" />
            </LinearLayout>
            <SeekBar
                android:id="@+id/sb_voice"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:thumb="@drawable/seekbar_point" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:orientation="horizontal" >
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="bottom|center_horizontal"
                    android:text="调节系统音量"
                    android:textColor="#000000"
                    android:textSize="17sp" />
                <ImageView
                    android:id="@+id/iv_system_down"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="30dp"
                    android:src="@drawable/volumn_down" />
                <ImageView
                    android:id="@+id/iv_system_up"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="50dp"
                    android:src="@drawable/volumn_up" />
            </LinearLayout>
            <SeekBar
                android:id="@+id/sb_system"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:thumb="@drawable/seekbar_point" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:orientation="horizontal" >
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="bottom|center_horizontal"
                    android:text="调节铃声音量"
                    android:textColor="#000000"
                    android:textSize="17sp" />
                <ImageView
                    android:id="@+id/iv_ring_down"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="30dp"
                    android:src="@drawable/volumn_down" />
                <ImageView
                    android:id="@+id/iv_ring_up"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="50dp"
                    android:src="@drawable/volumn_up" />
            </LinearLayout>
            <SeekBar
                android:id="@+id/sb_ring"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:thumb="@drawable/seekbar_point" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:orientation="horizontal" >
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="bottom|center_horizontal"
                    android:text="调节音乐音量"
                    android:textColor="#000000"
                    android:textSize="17sp" />
                <ImageView
                    android:id="@+id/iv_music_down"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="30dp"
                    android:src="@drawable/volumn_down" />
                <ImageView
                    android:id="@+id/iv_music_up"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="50dp"
                    android:src="@drawable/volumn_up" />
            </LinearLayout>
            <SeekBar
                android:id="@+id/sb_music"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:thumb="@drawable/seekbar_point" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:orientation="horizontal" >
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="bottom|center_horizontal"
                    android:text="调节闹钟音量"
                    android:textColor="#000000"
                    android:textSize="17sp" />
                <ImageView
                    android:id="@+id/iv_alarm_down"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="30dp"
                    android:src="@drawable/volumn_down" />
                <ImageView
                    android:id="@+id/iv_alarm_up"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="50dp"
                    android:src="@drawable/volumn_up" />
            </LinearLayout>
            <SeekBar
                android:id="@+id/sb_alarm"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:thumb="@drawable/seekbar_point" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:orientation="horizontal" >
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="bottom|center_horizontal"
                    android:text="调节通知音量"
                    android:textColor="#000000"
                    android:textSize="17sp" />
                <ImageView
                    android:id="@+id/iv_notify_down"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="30dp"
                    android:src="@drawable/volumn_down" />
                <ImageView
                    android:id="@+id/iv_notify_up"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="50dp"
                    android:src="@drawable/volumn_up" />
            </LinearLayout>
            <SeekBar
                android:id="@+id/sb_notify"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:thumb="@drawable/seekbar_point" />
        </LinearLayout>
    </ScrollView>
</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
4天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
6天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
8天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
6天前
|
存储 API 开发工具
探索安卓开发:从基础到进阶
【10月更文挑战第37天】在这篇文章中,我们将一起探索安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和建议。我们将从安卓开发的基础开始,逐步深入到更复杂的主题,如自定义组件、性能优化等。最后,我们将通过一个代码示例来展示如何实现一个简单的安卓应用。让我们一起开始吧!
|
7天前
|
存储 XML JSON
探索安卓开发:从新手到专家的旅程
【10月更文挑战第36天】在这篇文章中,我们将一起踏上一段激动人心的旅程,从零基础开始,逐步深入安卓开发的奥秘。无论你是编程新手,还是希望扩展技能的老手,这里都有适合你的知识宝藏等待发掘。通过实际的代码示例和深入浅出的解释,我们将解锁安卓开发的关键技能,让你能够构建自己的应用程序,甚至贡献于开源社区。准备好了吗?让我们开始吧!
19 2
|
8天前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
16天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
14天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
28 5
|
13天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
14天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
33 3

热门文章

最新文章