目录

一、Activity组件

1、Activity 相关概念介绍

2、Activity生命周期

3、Activity 启动模式

(1)standard模式

(2)singleTop模式 (栈顶复用模式)

(3)singTask 模式(栈内单例模式)

(4) singleInstance模式(堆内单例模式)

4、Activity 之间相互跳转及通信

(1)不带数据跳转

(2)带数据或多个数据跳转

(3)带数据跳转,带数据返回

(4)Intent隐式实现启动其他程序Activity

二、Service组件

1、Service简单介绍

2、Service启动的两种方式

(1)startService()

(2)bindService()绑定服务

(3)实现前台Service

(4)使用IntentService

三、Broadcast Receiver组件

1、简单介绍

2、使用介绍

(1)无序广播的使用

(2)有序广播的使用

(3)常用的系统广播的action 和permission

​​​​​​​四、内容提供者(Content Provider)组件

1、简单介绍

2、使用

(1)使用系统提供的内容提供器

Android四大组件分别为Activity、Service、Broadcast Receiver、Content Provider。

一、Activity组件

1、Activity 相关概念介绍

一个 Activity 包含了用户能够看到的界面,从而于用户进行交互。一个应用程序中可以有零个或者多个Activity。零个 Activity 就表示,这个应用程序不包含与用户交互的界面。

Android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明注册,否则系统将不识别也不执行该Activity。

<activityandroid:name=".LoginActivity"android:exported="true"android:label="@string/title_activity_login"android:launchMode="singleTop"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>

2、Activity生命周期

Android 是使用任务(task)来管理Activity的,一个任务就是一组存放在栈里Activity的集合,这个栈也叫作返回栈。

        Activity的生命周期由以下几个部分组成:

函数

描述

onCreat()

一个Activity启动后第一个被调用的函数,常用来在此方法中进行Activity的一些初始化操作。例如创建View,绑定数据,注册监听,加载参数等。

onStart()

当Activity显示在屏幕上时,此方法被调用但此时还无法进行与用户的交互操作。

onResume()

这个方法在onStart()之后调用,也就是在Activity准备好与用户进行交互的时候调用,此时的Activity一定位于Activity栈顶,处于运行状态。

onPause()

这个方法是在系统准备去启动或者恢复另外一个Activity的时候调用,通常在这个方法中执行一些释放资源的方法,以及保存一些关键数据。

onStop()

这个方法是在Activity完全不可见的时候调用的。

onDestroy()

这个方法在Activity销毁之前调用,之后Activity的状态为销毁状态。

onRestart()

当Activity从停止stop状态恢进入start状态时调用状态。

实际操作过程中,当打开启动Android应用时,MainActivity会经过onCreate -> onStart -> onResume三个阶段,此时若按home键或则back按键,MainActivity会经过onPause -> onStop这两个阶段,再进入此MainActivity时,会再调用onRestart -> onStart -> onResume三个阶段。

  3、Activity 启动模式

启动模式一共有 4 中:standard、singleTop、singTask 和 singleInstance,可以在 AndroidManifest.xml 中通过 标签指定 android:launchMode 属性来选择启动模式。

     (1)standard模式

standard 模式是 Activity 的默认启动模式,在不进行显示指定的情况下,所有 Activity 都会自动使用这种启动模式。对于使用 standard 模式启动的 Activity,系统不会在乎这个 Activity 是否已经存在在栈中了。每次启动的时候都会创建一个新的实例。一般用于打开邮件之类的。

(2)singleTop模式 (栈顶复用模式)

如果 Activity 指定为 singleTop,在启动 Activity 的时候发现返回栈的栈顶已经是该 Activity 了。则认为可以直接使用它,就不会再创建新的 Activity 实例了。因为不会创建新的 Activity 实例,所以 Activity 的生命周期就没有什么变化了。假设你在当前的Activity中又要启动同类型的Activity,此时建议将此类型Activity的启动模式指定为SingleTop,能够降低Activity的创建,节省内存!

一般用于登录页面,新闻详情页等。

(3)singTask 模式(栈内单例模式)

singleTop 很好的解决了重复创建栈顶 Activity 的问题。如果 Activity 没有处于栈顶的位置,还是可能会创建多个 Activity 实例的。那就需要借助 singleTask 了。当 Activity 的启动模式为 singleTask 的时候,每次启动该 Activity 的时候系统会首先在返回栈中检查是否存在该 Activity 的实例,如果发现已经存在则直接使用该实例。并把这个 Activity 之上的所有 Activity 全部出栈,如果没有就会创建一个新的 Activity 实例。

一般主页面使用,购物页面,付款页面,浏览器主页等。

(4) singleInstance模式(堆内单例模式)

singleInstance 模式的 Activity 会启用一个新的返回栈来管理这个 Activity 。在这种模式下会有一个单独的返回栈来管理这个 Activity,不管是哪个应用程序来访问这个 Activity,都共用的同一个返回栈,也就解决了共享 Activity 实例的问题。

4、Activity 之间相互跳转及通信

Intent(意图)是应用程序种各个组件联系的桥梁,通信的载体,负责应用程序中数据的传递。

(1)不带数据跳转

 Intent intent = new Intent(this,MainActivity.class);startActivity(intent);

此段代码实现从当前Activity,跳转到MainActivity,不带任何参数。

(2)带数据或多个数据跳转

//带数据跳转
String data = "是我主活动调用了你";
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("ext", data);
startActivity(intent);

(3)带数据跳转,带数据返回

Intent intent = new Intent(LoginActivity.this,RegisterActivity.class);
Bundle bundle = new Bundle() ;
bundle.putString("register","请开始注册!");
intent.putExtras(bundle) ;
startActivityForResult(intent,1);

        在跳转时使用startActivityForResult方法,此方法传入两个参数一个是Intent ,另外一个是给当前请求设置的一个请求ID,此ID在结束数据时辨识是否使当前请求的返回结果。

        同时要在跳转源Activity中实现 onActivityResult 方法来接收处理目的Activity返回的数据。

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode) {case 1:if (resultCode == RESULT_OK) {final EditText loginUsername = findViewById(R.id.username);String returnUsername = data.getStringExtra("userName");//序列化方式取出实体User user = (User)data.getSerializableExtra("user");loginUsername.setText(returnUsername);loginUsername.setSelection(returnUsername.length());}break;default:}
}

(4)Intent隐式实现启动其他程序Activity

在当前Activity中调用百度请求界面。

Uri uri = Uri.parse("https://www.baidu.com");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);

直接调用打电话功能

Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("tel:13207690000"));startActivity(i);

在使用系统电话功能时需要给当前应用程序授权,在AndroidManifest.xml文件中增加

<uses-permission android:name="android.permission.CALL_PHONE" />

         打开地图界面

Uri uri = Uri.parse("geo:38.899533,-77.036476");Intent it = new Intent(Intent.ACTION_VIEW, uri);startActivity(it);

二、Service组件

 1、Service简单介绍

Service它可以在后台执行长时间运行操作而没有用户界面的应用组件,不依赖任何用户界面,例如后台播放音乐,后台下载文件等。

虽然服务是在后台运行的,但是Service和Activity都是运行在当前APP所在的main thread(UI主线程)中的,而耗时操作(如网络请求、拷贝数据、大文件)会阻塞主线程,给用户带来不好的体验。如果需要在服务中进行耗时操作,可以选择 IntentService,IntentService是Service的子类,用来处理异步请求。

 2、Service启动的两种方式

(1)startService()

在Acitivity界面通过显式意图(或隐式意图)的方式来启动服务和关闭服务。

Intent intentService = new Intent(MainActivity.this, AudioServiceOnBind.class);startService(intentService);

生命周期顺序:onCreate->onStartCommand->onDestroy

        onCreate() 当Service第一次被创建时调用。

        onStartCommand() 当startService方法启动Service时,该方法被调用。

        onDestroy() 当Service不再使用时调用。

(2)bindService()绑定服务

当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

首先在我们的服务中创建一个内部类AudioBinder继承Binder来获取当服务实例,然后在onBind方法中返回当前服务的实例。

public class AudioServiceOnBind extends Service implements MediaPlayer.OnCompletionListener{private final IBinder binder = new AudioBinder();//用于播放音乐等媒体资源private MediaPlayer mediaPlayer;public AudioServiceOnBind() {super();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(AudioServiceOnBind.this.getClass().getName(),"执行onStartCommand()");return 0;}@Overridepublic IBinder onBind(Intent intent) {return binder;}@Overridepublic void onCreate(){super.onCreate();Log.d(AudioServiceOnBind.this.getClass().getName(),"执行onCreate()");if (mediaPlayer==null){mediaPlayer=MediaPlayer.create(this,R.raw.gumeng);mediaPlayer.setOnCompletionListener(this);}mediaPlayer.start();}@Overridepublic void onCompletion(MediaPlayer mp) {stopSelf();}@Overridepublic void onDestroy(){if(mediaPlayer.isPlaying()){mediaPlayer.stop();}mediaPlayer.release();stopForeground(true);Log.d(AudioServiceOnBind.this.getClass().getName(),"执行onDestroy()");}//为了和Activity交互,我们需要定义一个Binder对象class AudioBinder extends Binder {//返回Service对象AudioServiceOnBind getService(){return AudioServiceOnBind.this;}}}

然后在调用的Activity中创建一个ServiceConnection对象重写其中的onServiceConnected方法获取所要绑定的服务。在触发事件的方法中调用bindService实现服务的最终绑定。

public class MainActivity extends AppCompatActivity {private AudioServiceOnBind audioServiceOnBind;//使用ServiceConnection来监听Service状态的变化private ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {audioServiceOnBind = null;}@Overridepublic void onServiceConnected(ComponentName name, IBinder binder) {//这里我们实例化audioService,通过binder来实现audioServiceOnBind = ((AudioServiceOnBind.AudioBinder) binder).getService();}};public void click_music_open(View view) {Intent intentService = new Intent(MainActivity.this, AudioServiceOnBind.class);bindService(intentService, conn, Context.BIND_AUTO_CREATE);}
}

生命周期:onCreate->onBind->onUnBind->onDestroy

        onCreate() 当Service被创建时,由系统调用。

        onBind() 当bindService方法启动Service时,该方法被调用。

        onUnbind() 当unbindService方法解除绑定时,该方法被调用。

        onDestroy() 当Service不再使用时,由系统调用。

(3)实现前台Service

Android 8.0 后系统不允许后台应用创建后台服务。 因此,Android 8.0 引入了一种全新的方法,即 Context.startForegroundService(),以在前台启动新服务。

在service onStartCommand方法中增加以下代码

 @Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(AudioServiceOnBind.this.getClass().getName(),"执行onStartCommand()");Intent nfIntent = new Intent(this, MainActivity.class);Notification.Builder builder = new Notification.Builder(this.getApplicationContext()).setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)).setSmallIcon(R.mipmap.touxiang).setContentTitle("wu").setContentText("Android测试").setWhen(System.currentTimeMillis());String CHANNEL_ONE_ID = "com.wu";String CHANNEL_ONE_NAME = "Channel One";//安卓8.1以上系统NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ONE_ID, CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN);notificationChannel.enableLights(false);notificationChannel.setShowBadge(true);notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);manager.createNotificationChannel(notificationChannel);builder.setChannelId(CHANNEL_ONE_ID);Notification notification = builder.build();startForeground(1, notification);return super.onStartCommand(intent,flags,startId);}

  在调用Activity中调用startForegroundService方法。

 public void click_music_open(View view) {Intent intentService = new Intent(MainActivity.this, AudioServiceOnBind.class);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {startForegroundService(intentService);} else {startService(intentService);}}

(4)使用IntentService

由于Service中的逻辑都是执行在主线程中的,此时如果在Service中处理一下耗时操作可能就会给用户带来不好的体验。所以此时就可以使用Android多线程Service.

本质上IntentService是在Service里开启线程去做任务处理。IntentService会在任务执行完成后自行结束自己,而不需要外部去调用stopService了。

使用IntentService定义的服务,要开启线程,只要重写一个onHandleIntent()方法就可以了,而且在运行完之后会自动停止。

例如数据下载 数据上传等。

public class MyIntentService extends IntentService {private static final String TAG = "MyIntentService";public MyIntentService() {super("MyIntentService");}@Overrideprotected void onHandleIntent(Intent intent) {Log.d(TAG, "当前是子线程: " + Thread.currentThread().getId());//在这里实现异步多线程处理逻辑//例如数据下载 数据上传等。Log.d(TAG, "我在后台默默下载数据中。。。。");}@Overridepublic void onCreate() {Log.d(TAG, "onCreate: ");super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "onStartCommand: ");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.d(TAG, "onDestroy: ");super.onDestroy();}
}

三、Broadcast Receiver组件

1、简单介绍

广播接收器是一个用于接收广播信息,并做出对应处理的组件。比如我们常见的系统广播:通知时区改变、电量低、用户改变了语言选项等。

(1)有序广播

只发送广播到优先级较高的接收者那里,然后由优先级高的接收者决定是继续传播到优先级低的接收者那里还是终止这个广播。

(2)无序广播

对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。是我们使用较多的一种普通广播类型。

(3)生命周期

BroadcastReceiver的生命周期从对象调用它开始,到onReceiver方法执行完成之后结束。每次广播被接收后会重新创建BroadcastReceiver对象,并在onReceiver方法中执行完就销毁,如果BroadcastReceiver的onReceiver方法中不能在10秒内执行完成,Android会出现ANR异常。所以不要在BroadcastReceiver的onReceiver方法中执行耗时的操作。

2、使用介绍

(1)无序广播的使用

        1、创建BreadcastReceiver的子类

        2、注册BroadcastReceiver

静态注册

<!-- 在配置文件中注册BroadcastReceiver能够匹配的Intent -->

<receiverandroid:name=".MyReceiver"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.intent.action.MyReceiver"></action><category android:name="android.intent.category.DEFAULT"></category></intent-filter>
</receiver>

  动态注册​​​​​​​

MyReceiver receiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.MyReceiver");
registerReceiver(receiver, filter);

​​​​​​​(2)序广播的使用

接收者的创建和普通广播一样。有序和无序广播区别在于可以实现广播的拦截,高优先级的接收者可以通过abortBroadcast()终止广播。比如系统的接收短信广播就是一个有序广播,可以通过自定义的广播进行拦截,只要设置的android:priority属性,越大优先级越高。这个值介于[-1000,1000]。

(2)有序广播的使用
<receiverandroid:name="com.example.myapplication.MySecondReceiver"android:exported="true"><intent-filter android:priority="100"><action android:name="MY_BROADCAST"/></intent-filter>
</receiver>

注册完广播接收器后简单实现一个广播的发送器。 调用sendOrderedBroadcast方法进行有序广播的发送。

Intent intent = new Intent();
intent.setAction("MY_BROADCAST");
intent.putExtra("msg", "你好广播接收器,我是有序广播");
intent.setPackage("com.example.myapplication");
sendOrderedBroadcast(intent, null);

发送完有序广播后我们在自己定义的MySecondReceiver中实现接收到广播的处理。

public class MySecondReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Log.i(MySecondReceiver.class.getName(),"我收到了广播:" + intent.getStringExtra("msg"));Toast t = Toast.makeText(context,intent.getStringExtra("msg"),Toast.LENGTH_LONG);t.setGravity(Gravity.TOP,0,0);t.show();//可以选择是否继续广播abortBroadcast();}
}

​​​​​​​(3)常用的系统广播的action 和permission

        开机启动

//开机启动对应的Action
<action android:name="android.intent.action.BOOT_COMPLETED"/> //开机启动需要的授权
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

        网络状态变化广播

<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 

        电量变化广播

<action android:name="android.intent.action.BATTERY_CHANGED"/>  

​​​​​​​四、内容提供者(Content Provider)组件

1、简单介绍

Content Provider属于Android应用程序的组件之一,作为应用程序之间唯一的共享数据的途径,Content Provider主要的功能就是存储并检索数据以及向其他应用程序提供访问数据的接口。

Android内置的许多数据都是使用Content Provider形式,供开发者调用的(如视频,音频,图片,通讯录等)。

2、使用

(1)使用系统提供的内容提供器

Android系统中自带的电话簿、短信、媒体库等程序都提供了这样的内容提供器供外界访问。

每个应用程序要想访问内容提供器中的数据,就一定要借助ContentResolver类,可以通过Context中的getContentResolver方法来获取。ContentResolver类提供了一系列方法用于对数据进行CRUD操作,insert方法用于添加数据,update方法用于更新数据,delete方法用于删除数据,query方法用于查询数据。它和SQLiteDatabase很像,只不过它不接收表名,而是换成了Uri参数。

Uri包括两部分:authority和path。authority命名为 包名.provider,path命名为 表名 ,所以一个标准的Uri可以为content://com.example.testspecial.provider/table1/1

  获取系统的手机联系人

public class SecondActivity extends AppCompatActivity {private static final String TAG = "SecondActivity";private ContentResolver contentResolver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Objects.requireNonNull(getSupportActionBar()).hide();setContentView(R.layout.activity_second);Button bt_getPhone = (Button) findViewById(R.id.bt_getPhone);bt_getPhone.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {contentResolver = getContentResolver();if(ContextCompat.checkSelfPermission(SecondActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},1);}Cursor cursor=contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);while (cursor.moveToNext()){//获得联系人的idint _id=cursor.getInt(cursor.getColumnIndex("_id"));//获得联系人姓名String display_name=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));Log.i(TAG,"当前手机里的联系人:" + _id+" 姓名:"+display_name + "电话号码 "+number );}}});}
}

Android 四大开发组件相关推荐

  1. Android四大基本组件介绍与生命周期

    Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. 一:了解四大基本组件 Activity ...

  2. Android四大基本组件和生命周期的介绍

    Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. 一:了解四大基本组件 Activity ...

  3. Android四大基本组件

    Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. Activity 概念: 应用程序中, ...

  4. 马小妹的Android之旅——Android四大基本组件之Activity

    Android的四大基本组件分别是:Activity.Service服务.Context Provider内容提供者.BroadcastReceiver广播. 这篇主要写Activity. 什么是Ac ...

  5. Android四大基本组件详解-Activity,BroadcastReceiver,Service及ContentProvicer

    文章目录 一,活动(Activity) 1.简介 2.任务栈 3.Activity的4种状态 4. 7种生命周期方法 5.Activity的四种启动模式 (1)Standard 标准模式(默认启动模式 ...

  6. android游戏开发组件,Android实现疯狂连连看游戏之开发游戏界面(二)

    连连看的游戏界面十分简单,大致可以分为两个区域: --游戏主界面区 --控制按钮和数据显示区 1.开发界面布局 本程序使用一个RelativeLayout作为整体的界面布局元素,界面布局上面是一个自定 ...

  7. Android基础_1 四大基本组件介绍与生命周期

    Android四大基本组件分别是Activity,Service(服务),Content Provider(内容提供者),BroadcastReceiver(广播接收器). 一.四大基本组件 Acti ...

  8. Android四大组件---BroadcastReceiver

    前言: BroadcastReceiver(广播接收器),属于 Android 四大组件之一 在 Android 开发中,BroadcastReceiver 的应用场景非常多 今天,我将详细讲解关于B ...

  9. Android 四大组件(Activity、Service、BroadCastReceiver、ContentProvider)

    Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. 一.了解四大基本组件 Activity ...

  10. Part3.Android基础知识 - 四大基本组件与常用控件完全解析

    1.概要 1).Android四大基本组件 Activity Service Broadcast Receiver Content Provider 2).Android应用核心Intent Inte ...

最新文章

  1. 实现搜索框记录搜索历史_三个案例告诉你:“搜索框”该如何设计?
  2. 关于nil和 null和NSNull的相关问题
  3. js input 自动换行_深入Slate.js - 拯救 ContentEditble
  4. 将Application按钮从任务栏中去掉
  5. jsp页面路径问题(404)
  6. [matlab]斜阶梯式长条引起的重力异常计算
  7. JEECG ——11月份版本即将发布功能点
  8. js实现点击按钮复制文本功能
  9. C语言线性表怎么输入字符串,用c语言创建一个线性表输入元素求直接后继
  10. 插桩 java_Javassist进行方法插桩
  11. 如何寻找计算机领域的英文文献?
  12. 百度世界2020再曝语义理解领域新进展:文心ERNIE全景图亮相
  13. 最新县及县以上行政区划代码(截止2016年7月31日)
  14. uniapp+uniCloud实现批量上传图片到云端(解决h5端跨域问题)
  15. 研华webaccess与西门子PLC以太网通讯配置
  16. Flutter 无埋点SDK实现
  17. 关于VSCode调试无法支持中文路径的曲线救国方法
  18. 图解|什么是缓存系统三座大山
  19. 捕获了一只发生概率小于万分之一的Bug
  20. 顺序表实现图书信息管理系统

热门文章

  1. 学习矩阵分析与应用过程中的点滴记录(一)
  2. 使用DirectX播放wav声音文件
  3. CTFmisc常见音频隐写总结
  4. bigemap功能介绍,视频教程
  5. 软考软件设计师中级考试免费视频教程汇总
  6. 局域网限制网速软件_五款大学生小众有用软件,学长亲荐
  7. 计算机一级考试广告,2013年计算机一级考试MsOffice备考题及答案(21)
  8. 2020年中国洪涝受灾人口数、死亡失踪人口数、倒塌房屋数量及造成的直接经济损失分析[图]
  9. 火狐扩展插件开发者模式_使用插件扩展您的开发人员社区
  10. 最近游戏更新 未整理 无图片 续