四大组件之Service

     

    学之广在于不倦,不倦在于固志。 ——晋·葛洪­

  (学问的渊博在于学习时不知道厌倦,而学习不知厌倦在于有坚定的目标)

  全面到位的一篇Service------强烈推荐     2018/11/1 更新

   001.基本介绍:

         00a、概念:

                   Service是Android中实现程序后台运行的解决方案,四大组件之一

         00b、适用场景:

                  执行一些不需要和用户交互而且要求长期运行的任务,比如:听音乐&看电子书;检测SD卡的变化;记录你的地理位置变化;

         00c、特点:

                  服务的进程依赖于创建服务时所在的应用程序的进程,服务的运行不依赖于任何界面,

         注意:

                  服务默认在主线程运行,我们需要在服务内部手动创建子线程,并在这里执行具体的任务

 

    002.服务的启动与销毁:

          00a、步骤:

                   --->  创建一个类继承Service,Service是一个抽象类,必须重写onBind()方法

                                --->  清单文件注册对应的Service

 

<service android:name=".service.MyService"/>

                   --->  开启Service,具体区别看代码部分:

 

                         ---> startService();

                         ---> bindService();

                   ---> 销毁Service,具体见代码部分:

                         ---> stopService() / stopSelf()

                         ---> unBindService()

    003.代码实战:

          00a、startService开启服务

                 在MainActivity中添加两个按钮,一个用于开启服务,一个用于销毁服务,添加几个生命周期的打印信息。注意startService()和stopService()方法都是定义在Context类当中的,所以可以在MainActivity中直接调用这两个方法

 

public class MyService extends Service {
    private static final String TAG = "MyService";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return null;
    }

    //创建服务时调用
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: ");
    }

    //在服务执行操作
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    //销毁服务时调用
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy: ");
    }
}
<service android:name=".service.MyService"/>

 

 

public class MainActivity extends AppCompatActivity {

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

        //点击开启服务
        findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //构建出了一个Intent对象,并调用startService()方法来启动MyService
                Intent startIntent = new Intent(MainActivity.this, MyService.class);
                startService(startIntent);
            }
        });

        //点击关闭服务
        findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //构建出了一个Intent对象,并调用stopService()方法来停止MyService
                Intent stopIntent = new Intent(MainActivity.this, MyService.class);
                startService(stopIntent);
            }
        });
    }
}

 

 

 

          点击了Start Service,打印如下,执行了onCreate和onStartCommand

 15555-15555/com.test.okamiy.mythread I/MyService: onCreate:

 15555-15555/com.test.okamiy.mythread I/MyService: onStartCommand:

      我接着连续点击了3下Start Service,打印如下,只执行了onStartCommand

 15555-15555/com.test.okamiy.mythread I/MyService: onStartCommand:

 15555-15555/com.test.okamiy.mythread I/MyService: onStartCommand:

 15555-15555/com.test.okamiy.mythread I/MyService: onStartCommand:

       注意:

              虽然每次调用一次startService()方法,onstartCommand()方法就会以执行一次,但实际上每个服务都只会存在一个实例。所以不管你调用了多少次startService()方法,只需调用一次stopService()或stopself()方法,服务就会停止

       经多次测试得出,onCreate()方法只会在Service第一次被创建的时候调用,而onStartCommand()方法在每次启动服务的时候都会调用

          此时我们可以在手机运行的应用程序查看,我们的服务已经运行起来了

      点击了Stop Service,打印如下,执行了onDestroy,服务已销毁
 15555-15555/com.test.okamiy.mythread I/MyService: onDestroy:

      

      总结:

              ---> startService开启的服务,停止服务有两种方式:

                             1> 在Service的内部任何地方调用stopSelf()即可停止服务

                             2> 在外部调用stopService()即可停止服务

              ---> startService开启服务,就可以在onCreate()或onStartCommand()方法里去执行一些具体的逻辑了,此时Service和Activity的关系并不大,只是Activity通知了Service一下:“你可以启动了。”然后Service就去忙自己的事情了。但Activity并不知道服务到底去做了什么,以及如何完成。

             ---> onStartCommand方法执行时,返回的是一个int类型。这个整型可以有三个返回值:

                             1> START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand方法后,服务被异常kill掉,系统不会自动重启该服务

                              2> START_STICKY:如果Service进程被kill掉,保留Service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建Service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到Service,那么参数Intent将为null。

                              3> START_REDELIVER_INTENT:重传Intent。使用这个返回值时,系统会自动重启该服务,并将Intent的值传入。

          00b、bindService绑定服务

                 基于上面的代码。在MainActivity中再添加2个按钮,bind_service,unbind_service,添加点击事件

 

public class MyService extends Service {
    private static final String TAG = "MyService";
    private DownloadBinder mBinder = new DownloadBinder();

    //和Activity通信
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return mBinder;
    }

    //创建服务时调用
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: ");
    }

    //在服务执行操作
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    //销毁服务时调用
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy: ");
    }

    //Binder类,用于模拟下载,保存进度
    public class DownloadBinder extends Binder {

        public void startDownload() {
            Log.i(TAG, "startDownload: " + "开始下载");
        }

        public int getProgress() {
            Log.i(TAG, "getProgress: " + "获取了下载进度");
            return 0;
        }
    }
}
<service android:name=".service.MyService"/>
public class MainActivity extends AppCompatActivity {
  
 
private boolean mBind = false; //一开始,并没有和Service绑定.这个参数是用来显示绑定状态 

private MyService.DownloadBinder downloadBinder;

//匿名内部类:服务连接对象,有了这个实例我们就和Service联系紧密
//如果当前Activity与服务连接成功后,服务会回调onServiceConnected()方法
 
private ServiceConnection mConnection = new ServiceConnection() {

//和服务绑定成功后,服务会回调该方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();

 
mBind = true;

}

//当服务异常终止时会调用。注意,解除绑定服务时不会调用
@Override
public void onServiceDisconnected(ComponentName name) {

            mBind = false; //服务异常终止时,状态为未绑定

}
};

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

//点击绑定服务:将MainActivity和MyService进行绑定
findViewById(R.id.bind_start).setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MyService.class);
//参数3:标志位,BIND_AUTO_CREATE 表示在Activity和Service建立关联后会自动创建Service
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
});

//点击解绑服务
findViewById(R.id.bind_stop).setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {

              if (mBind) {
                  unbindService(mConnection);
                  mBind = false;
              }

}
});

//点击开启服务
findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
//构建出了一个Intent对象,并调用startService()方法来启动MyService
Intent startIntent = new Intent(MainActivity.this, MyService.class);
startService(startIntent);
}
});

  //点击关闭服务
findViewById(R.id.bt_stop).setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
//构建出了一个Intent对象,并调用stopService()方法来停止MyService
Intent stopIntent = new Intent(MainActivity.this, MyService.class);
stopService(stopIntent);
}
});
}
}          

 

          点击bind Service,打印如下,执行了onCreateonBind,并执行了startDownloadgetProgress方法,说明我们在Activity里面已经调用了Service的方法

 21456-21456/com.test.okamiy.mythread I/MyService: onCreate:
 21456-21456/com.test.okamiy.mythread I/MyService: onBind:
 21456-21456/com.test.okamiy.mythread I/MyService: startDownload: 开始下载
 21456-21456/com.test.okamiy.mythread I/MyService: getProgress: 获取了下载进度

          点击unbind Service,打印如下,执行了onDestory,解绑了Service

 21456-21456/com.test.okamiy.mythread I/MyService: onDestroy:

          总结:

                  ---> bindService绑定的服务,需要UnbindService解除绑定

                  --->bindService绑定服务,首先需要创建ServiceConnection的匿名类,重写了onServiceConnected()方法和onServiceDisconnected()方法,这两个方法分别会在Activity与Service建立关联和解除关联的时候调用;在onServiceConnected()方法中,我们又通过向下转型得到了MyBinder的实例,有了这个实例,我们就实现了Activity指挥Service干什么Service就去干什么的功能

                   ---> Service服务在整个应用程序范围内都是通用的,即MyService不仅可以和MainActivity建立关联,还可以和任何一个Activity建立关联,而且在绑定完成后它们都可以获取到相同的DownloadBinder实例

               

           注意:

                   ---> 在我们点击了bind Service,同时也点击了startService,我们需要分别点击unbindService和stopService才能销毁Service,没有先后顺序,说明,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁(点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联)

                    ---> 记得在Service的onDestroy()方法里去清理掉那些不再使用的资源,防止在Service被销毁后还会有一些不再使用的对象仍占用着内存

 

         startService和bindService区别

                ---> 生命周期:

                               1> 通过started方式开启的服务会一直运行在后台,需要由Service组件本身(stopSelf)或外部组件(stopService)来停止服务,service才会结束运行

                               2>  bind方式绑定的服务,生命周期就要依赖绑定的组件

                 --->参数传递:

                               1> started服务可以给启动的服务对象传递参数,但无法获取服务中方法的返回值

                               2> bind服务可以给启动的服务对象传递参数,也可以通过绑定的业务对象获取返回结果

                         所以,更多的时候是2种方式配合使用:第一次先使用started方式来启动一个服务,之后可以使用bind的方式绑定服务,从而可以直接调用业务方法获取返回值

 

          00c、创建前台服务:

                如果你希望Service可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service。前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果

               比如:墨迹天气,它的Service在后台更新天气数据的同时,还会在系统状态栏一直显示当前天气的信息

       只需要修改上面MyService里面的onCreate方法即可,添加如下代码即可变成前台service点击startService或者bindService就会在通知栏出现我们的通知

 

//创建服务时调用
@Override
public void onCreate() {
    super.onCreate();

    //创建通知
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    builder.setSmallIcon(R.mipmap.ic_launcher);
    builder.setContentTitle("Notification comes");
    builder.setContentText("Okamiy send message");
    Notification notification = builder.build();

    //让MyService变成前台Service,并在系统状态栏显示 参数1:通知的id,参数2:notification对象
    startForeground(1, notification);
    Log.i(TAG, "onCreate: ");
}

 

 

 

          00d、IntentService:

                一个服务中的代码默认运行在主线程中,如果直接在服务里执行一些耗时操作,容易造成ANR异常,所以就需要用到多线程的知识了,因此一个标准的服务如下:

 

public class MyService extends Service {
    private static final String TAG = "MyService";
    //和Activity通信
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
    }

    //创建服务时调用
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: ");
    }

    //在服务执行操作
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        new Thread(new Runnable() {
            @Override
            public void run() {
                //处理具体的逻辑
... stopSelf(); //服务执行完毕后自动停止 

  }
}).start();
return super.onStartCommand(intent, flags, startId);
}

  //销毁服务时调用
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
}
 

 

         虽说上面的这种写法并不复杂,但总会有一些程序猿忘记开启线程,或者忘记调用stopSelf()方法。为了可以简单地创建一个异步的、会自动停止的服务,Android专门提供了一个IntentService类,这个类就很好的解决了上面所提到的两种尴尬。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent()回调方法中执行,并且每次只会执行一个工作线程,执行完第一个后,再执行第二个,以此类推。

 

public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";

    public MyIntentService() {
        //调用父类的有参构造,这里我们手动给服务起个名字为:MyIntentService
        super("MyIntentService");
    }

    /**
     * 该方法执行在子线程,可以进行耗时操作和处理一些逻辑
     *
     * @param intent
     */
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        for (int i = 0; i < 3; i++) {
            try {
                Log.i(TAG, "onHandleIntent: " + "IntentService的线程: " + Thread.currentThread().getId());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy: ");
    }
}
<service android:name=".service.MyIntentService"/>
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

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

        //点击启动IntentService
        findViewById(R.id.start_IntentService).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i(TAG, "onClick: " + "MainActivity的线程:" + Thread.currentThread().getId());
                Intent intent = new Intent(MainActivity.this, MyIntentService.class);
                startService(intent);
            }
        });
   }
}

        

 

         点击IntentService,打印信息如下,说明:MyIntentService是运行在子线程的,并且在执行完耗时操作或者相应的逻辑之后自动执行了Service的销毁,集开启线程和自动停止于一身

/com.test.okamiy.mythread I/MainActivity: onClick: MainActivity的线程:1

/com.test.okamiy.mythread I/MyIntentService: onHandleIntent: IntentService的线程: 3503 /com.test.okamiy.mythread I/MyIntentService: onHandleIntent: IntentService的线程: 3503
/com.test.okamiy.mythread I/MyIntentService: onHandleIntent: IntentService的线程: 3503 /com.test.okamiy.mythread I/MyIntentService: onDestroy:

           

         00e、Service和Thread:

              ---> Service和Thread之间没有任何关系

                     1> Thread我们大家都知道,是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行

                     2> 而Service我们最初理解的时候,总会觉得它是用来处理一些后台任务的,一些比较耗时的操作也可以放在这里运行。但是,Service默认是运行在主线程的,可以自行打印测试;

                     3> Android中的后台就是指,它的运行是完全不依赖UI的,即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现,

                     4> 在Service里面执行耗时操作,是指在Service里面起一个线程Thread执行的耗时操作。

                          在Service里面起线程执行耗时操作的原因:

                                  这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况

               ---> 基于上述一个比较标准的Service就产生了:

 

public class MyService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 开始执行后台任务  
                ...
                stopSelf();//任务完成之后销毁服务
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

    class MyBinder extends Binder {

        public void startDownload() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 执行具体的下载任务  
                    ...
                    stopSelf();//任务完成之后销毁服务
                }
            }).start();
        }
    }
}

 

 

 

    004.个人总结可能有误,欢迎指正,参考篇:

          00a.郭霖大神(基础到进阶): 传送门---郭霖大神 

          00b.这篇是博客园的(全面而细致):传送门---细致入微

 

          Last:欢迎探讨学习          

本 PPT 介绍了制药厂房中供配电系统的总体概念与设计要点,内容包括: 洁净厂房的特点及其对供配电系统的特殊要求; 供配电设计的一般原则与依据的国家/行业标准; 从上级电网到工厂变电所、终端配电的总体结构与模块化设计思路; 供配电范围:动力配电、照明、通讯、接地、防雷与消防等; 动力配电中电压等级、接地系统形式(如 TN-S)、负荷等级与可靠性、UPS 配置等; 照明的电源方式、光源选择、安装方式、应急与备用照明要求; 通讯系统、监控系统在生产管理与消防中的作用; 接地与等电位连接、防雷等级与防雷措施; 消防设施及其专用供电(消防泵、排烟风机、消防控制室、应急照明等); 常见高压柜、动力柜、照明箱等配电设备案例及部分设计图纸示意; 公司已完成的典型项目案例。 1. 工程背景与总体框架 所属领域:制药厂房工程的公用工程系统,其中本 PPT 聚焦于供配电系统。 放在整个公用工程中的位置:与给排水、纯化水/注射用水、气体与热力、暖通空调、自动化控制等系统并列。 2. Part 01 供配电概述 2.1 洁净厂房的特点 空间密闭,结构复杂、走向曲折; 单相设备、仪器种类多,工艺设备昂贵、精密; 装修材料与工艺材料种类多,对尘埃、静电等更敏感。 这些特点决定了:供配电系统要安全可靠、减少积尘、便于清洁和维护。 2.2 供配电总则 供配电设计应满足: 可靠、经济、适用; 保障人身与财产安全; 便于安装与维护; 采用技术先进的设备与方案。 2.3 设计依据与规范 引用了大量俄语标准(ГОСТ、СНиП、SanPiN 等)以及国家、行业和地方规范,作为设计的法规基础文件,包括: 电气设备、接线、接地、电气安全; 建筑物电气装置、照明标准; 卫生与安全相关规范等。 3. Part 02 供配电总览 从电源系统整体结构进行总览: 上级:地方电网; 工厂变电所(10kV 配电装置、变压
### Service 的作用 Service 是 Android 四大组件之一,其主要作用是在后台执行长时间运行的任务,而不需要与用户进行交互。它没有界面,适用于执行如网络请求、播放音乐、文件 I/O 等需要在后台持续运行的操作。Service 可以独立于 Activity 运行,即使用户切换到其他应用,Service 仍然可以在后台继续运行 [^1]。 此外,Service 也可以被其他应用调用,从而提供一些特定的功能,例如后台数据处理或资源共享 [^2]。 ### Service 的生命周期 Service 的生命周期相对简单,主要包含以下几个关键方法: - `onCreate()`:当 Service 第一次被创建时调用,用于执行一次性初始化操作。 - `onStartCommand(Intent intent, int flags, int startId)`:当通过 `startService()` 启动 Service 时调用,用于处理传入的 Intent 请求。 - `onBind(Intent intent)`:当通过 `bindService()` 绑定 Service 时调用,返回一个 `IBinder` 对象用于实现组件间的通信。 - `onUnbind(Intent intent)`:当解除绑定时调用。 - `onDestroy()`:当 Service 被销毁时调用,用于释放资源。 根据启动方式的不同,Service 的生命周期会有所不同。 ### Service 的启动方式 Service 可以通过两种方式启动: 1. **通过 `startService()` 启动** - 使用 `startService()` 启动的 Service 会独立运行,与启动它的组件没有直接的绑定关系。 - 一旦启动,Service 会一直运行直到调用 `stopSelf()` 或外部调用 `stopService()`。 - 适用于执行一次性任务,例如下载文件或播放音乐。 2. **通过 `bindService()` 启动** - 使用 `bindService()` 启动的 Service 会与调用者(例如 Activity)建立绑定关系。 - 通过 `onBind()` 方法返回的 `IBinder` 对象,调用者可以与 Service 进行交互。 - 当调用者解除绑定时,Service 不会立即停止,只有当所有绑定都解除后,才会调用 `onUnbind()` 并最终调用 `onDestroy()` [^4]。 ### Service 的使用示例 #### 启动 Service ```java Intent serviceIntent = new Intent(context, MyService.class); context.startService(serviceIntent); ``` #### 停止 Service ```java Intent serviceIntent = new Intent(context, MyService.class); context.stopService(serviceIntent); ``` #### 绑定 Service ```java Intent serviceIntent = new Intent(context, MyService.class); context.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE); ``` 其中,`serviceConnection` 是一个实现了 `ServiceConnection` 接口的对象,用于接收 Service 绑定后的回调。 #### 解除绑定 ```java context.unbindService(serviceConnection); ``` ### Service 的声明 每个 Service 都需要在 `AndroidManifest.xml` 文件中进行声明,否则无法正常运行。声明方式如下: ```xml <service android:name=".MyService" /> ``` ### 前台 Service 如果需要让 Service前台运行,以避免被系统优先级机制杀死,可以使用 `startForegroundService()` 方法启动 Service,并在 Service 中调用 `startForeground()` 方法,将 Service 提升为前台服务 [^3]。 ```java Intent serviceIntent = new Intent(context, MyForegroundService.class); context.startForegroundService(serviceIntent); ``` 在 Service 的 `onStartCommand()` 方法中: ```java Notification notification = new Notification.Builder(this, "channel_id") .setContentTitle("Foreground Service") .setSmallIcon(R.drawable.ic_notification) .build(); startForeground(1, notification); ``` ### 注意事项 - **资源管理**:由于 Service后台运行,需要注意资源的合理使用,避免过度消耗系统资源。 - **生命周期管理**:使用 `bindService()` 启动的 Service 必须通过 `unbindService()` 解除绑定,否则可能导致内存泄漏。 - **权限声明**:某些特殊用途的 Service(例如前台服务)可能需要在清单文件中声明额外的权限。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值