android所有可视控件的主父类是,Android基础小结

Activity

创建:自定义类继承Activity  重写 onCreate 方法

注册:需要在 AndroidManifest.xml 中注册 Activity

跳转:

显示意图跳转:(一般打开自己的Activity)

创建两个类 为FirstActivity 和 SecondActivity 并在清单中声明 不用配置意图过滤器

label 为应用名字 icon 为图标  application 中的label 应用界面中应用名字 icon应用设置界面的图标

通过Intent 带参构造函数 Intent intent = new Intent(this,SecondActivity.class)

若打开其他应用的 需要 new Intent(); intent.setClassName("包名","全类名") 并在清单文件中声明 exported为 true

Intent 可以携带八种基本数据类型:boolean byte char short int float double long String 以及他们的数组形式

隐式意图跳转:(一般让其他应用打开自己的Activity)

将第二个Activity在清单文件中 注册 设置 意图过滤器 intent-filter action"域名倒写"  category 配置为category.DEFAULT 系统默认

Intent intent = new Intent();

intent.setAction(必须和清单文件中的action一样);

intent.setDate(Uri.parse("itheima"+xxx))(与清单文件data scheme 内容相同)

媒体类型 mimeType"父类型/子类型" intent.setType("父类型/子类型") 若既有data也有type 要intent.setDataAndType(data,type)

或者 intent.setAction(Intent.ACTION_CALL) intent.setDate(Uri.parse("tel:"+110);设置一个动作 携带数据

startActivity(intent);

生命周期:

foreground 前台状态  执行onResume(刷新数据)后 onstart()

paused 暂停状态      若有透明应用覆盖或者有对话框应用 覆盖的时候onPause 恢复的时候onResume

stopped 停止状态     onStop(停止刷新界面) 不可见而且不可以操作 按home键之后

simple 销毁状态onDestroy(释放资源)

onCreate

界面的初始化 setcontentView  findviewbyid

数据的初始化 文件/数据库/网络/其它的组件/sp

开启其它的组件(开启服务,注册广播接收者)

动态注册广播接收者(onCreate注册 onDestroy注销 onstart注册的onStop注销 onResume注册 onPause注销)

onstart

onResume 刷新界面

onPause    停止刷新界面

onStop

onDestroy 释放资源 数据库的链接 cursor sqlitedatabase bind的服务 广播接收者注销 退出线程

onRestart

创建 onCreate onstart onResume 按返回键后 onPause onStop onDestroy

按Home键 onPause onStop按home键返回 onRestart onstart onResume

startActivityForResult(intent,requestCode); (开启另外一个Activity)

onActivityResult(int requestCode, int resultCode, Intent data);

setResult(resultCode, intent data); finish(); (返回数据的activity)

屏幕旋转时生命周期:

onPause onStop onDestroy onCreate onstart onResum

1.默认:Activity会销毁 屏幕旋转后会创建新的Activity

2.写死屏幕方向  在清单文件中screenOrientation landscape 水平 portrait 竖直

3.configChanges orientation|screenSize 随着方向改变 不会销毁生命周期

重写onConfigurationChanged 屏幕旋转生命周期方法 处理相关业务逻辑

Activity任务栈(启动模式):

standard 默认情况 只要调用startActivity就会创建新的实例

singleTop 栈顶只有一个实例 如果当前的activity在任务栈的栈顶那么 不会创建新的实例 除此之外 不会影响实例的创建

(一系列调用的最后一个页面 为了避免在这个页面上再创建新的实例可以配置为singleTop)

singleTask 一个任务栈中只有一个实例 如果这个activity在栈顶 再次调用startactivity不会创建新的 实例 如果不在栈顶 并且实例存在

会把活着的实例上面的所有activity销毁 把这个对象露出来 (应用 的主界面可以配置为singleTask)

singleInstance 独占一个任务栈 这个任务栈中只有一个实例 而且整个手机只有一个实例(慎用 打电 话的界面可以配置为singleInstance)

fragment

1.fragment入门

①创建一个java类 继承Fragment重写oncreateView方法

fragment 也会对应一个布局文件  这个布局文件可以通过传入的LayoutInflater加载到界面上 作为oncreateview的返回值

②在布局文件中声明相应的fragment节点

注意在声明fragment节点时  fragment首字母小写  name 必须制定 内容是要显示的Fragment的全类名

2.动态替换fragment(常用)

1.创建FirstFramment和second类继承 重写 oncreateView 创建布局 更改最小版本为11

在onCreateView 中 inflater.inflate(R.layout.first,null);  将返回值作为方法的返回值

2.在Activity布局文件中 创建 ViewGroup(LinearLayout)为fragment容器 id为fragment_container

3在activity当中 找到控件 获取getfragmentManager 通过 fragmentManager 开启事物 fragmentTransaction

4.通过事务调用.replace();传入 android.R.id.content,new First 或者 R.id.fragment_container  再提交.commit

5.getWindManager.GetDefaultDisplay().getWidth /getHeight 如果宽大于高 是横屏 加载第二个 否则加载第一个

3.兼容低版本的写法(classMainActivityextendsFragmentActivity)

所有的跟fragement相关的api Fragment FragmentManager v4包中获取FragmentManager

要使用getSupportFragmentManager 这个方法在 FragmantActivity中才有

FragmentTransaction 都要使用android.support.v4包中的相关类

3.fragment的生命周期

oncreate 当fragment被创建的时候 调用oncreate oncreateView 在这个方法当中加载fragment的布局文件

onpause onStop 处理界面需要显示的东西 状态的保存

ondestory 资源的释放

4.fragment之间的通信

1.新建LeftF与rigntF 重写..创建布局文件 在LeftF添加按钮(调用方法) 在rightF添加一个TextView 在主界面中 创建两个线性布局 权重为1 宽度为0 高速为m并指定id

2.编写 onCreateView中的返回值 在Activity中getFramentManageer() 再开启事务.beginTranssaction 调用两次replace .commit

3.(在Activity中 创建按钮点击 弹吐司方法(这里不适宜点击事件的第四种写法)) 在leftF中 view.find 设置点击事件 弹吐司

4.在rightF中 view.find找到text控件 创建修改文字方法 给控件传文字  在Activity中的.replace 中添加 第三个属性为标签  在leftF中getFM.gFBt(标签)得到对象后 调用修改文字的方法

Service

特点:

Service 在 Android 中是一种长生命周期的组件,它不实现任何用户界面,是一个没有界面的 Activity

Service 和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的操作 如果要执行耗时操作 需要 在里边开一个子线程 new Thread(){}.start();

进程特点: 哪个进程被关闭是由安卓系统衡量对用户相对的重要程度,更容易杀死看不到界面的进程,试图维持每个进程尽可能的活着,有重要性层级结构.

Foreground process 前台进程 有Activity正在与用户交互 service在执行生命周期方法 广播接收者在执行onreceiver 优先级最高

visible preocess 可视进程 有一个Activity处于可见但不可操作的状态 比如有个透明应用盖在上面 处于onPause状态

Service preocess 服务进程 后台运行着用startService开启的服务 没有组件属于前两种情况

Background process 后台进程 有Activity 处于onStop但是没有销毁 没有其他组件属于前三种情况 后来进程比较多

哪个先杀死 用LRU算法 最近使用的最后杀 最少使用最先杀

Empty process 空进程

开启方式:

startService:

startService(Intent) 通过这种方式开启的服务 执行的声明周期方法: 第一次调用startService的时候 onCreate()->onStartCommand

再次调用startService ->onstartCommand

想停止用startservice开启的服务 stopService(intent); stopService 执行之后 service会走 onDestroy()方法 执行之后service销毁 再次调用stopService没有反应

如果在activity中通过startService方法开启一个服务 当activity退出的时候service不会销毁 依然在后 台运行

只有手动调用stopService 或者在应用管理器中关闭service 服务才会销毁

通过startservice可以提高应用的优先级

bindService:(可以调用接口中的方法)

① bindService  unbindService

② bindservice之后 生命周期  onCreate->onBind 多次调用bindService onBind只会执行一次

③ activity退出的时候 必须解除跟service的绑定  在ondestroy 的时候调用 unbindService

④ unbindService多次调用会抛异常 只能调用一次

⑤ bindservice的时候传入第二个参数 是ServiceConnection  只有当 onBind方法返回不为空的时候 才会调用 onServiceConnected

可以将返回值 service 强转为 MyBinder 类型(这个类是自己写的 是 onBind的返回值类) 通过这个对象可以调用接口中的方法

AIDL:

让其它应用可以调用当前应用service中的方法

RPC remote procedure call 远程过程调用  AIDL 解决就是rpc的问题

IPC inter process communication 进程间通信 每一个android应用都运行在独立的进程中 所以 应用之间的通信就是进程间通信

Activity intent BroadCastReceiver 通过onReceive方法 可以处理其他应用发来的广播 通过Intent 携带数据

AIDL实现的过程 :

提供远程服务方法的应用 :

① 创建一个Service 重写onBind方法 在onBinder中返回一个Binder对象 需要远程调用的放发放到 这个Binder对象中

②在清单文件中声明对应的service 需要添加一个intent-filter 可以通过隐式意图调用service

③ 创建一个接口 需要暴露给其它应用调用的方法都声明在这个接口中

④把接口文件的扩展名修改为 .aidl 需要注意 aidl文件不支持public 关键字

⑤修改service的代码 让MyBinder继承Stub

远程调用服务的应用

①用过隐式意图以及bindService方式 开启远程的服务

② 创建ServiceConnection的实现类

③在当前应用中创建一个目录 目录结构跟提供远程服务的应用aidl所在目录结构保持一致, 把aidl文 件copy过来 如果没有问题 会在gen目录下生成一个 Iservice.java文件 包名跟aidl文件的包名一致

④在onserviceConnected方法中 通过 把当前的Ibinder对象转化成远程服务中的接口类型 最终通过这个对象实现调用远程方法

LRU 刚用过的最后回收 最早用过的最先回收

BroadcastRecevier

特点:一对多 单向传递消息 不需要在清单文件中注册(动态注册)

开发过程:

①写一个类继承BroadcastReceiver

②重写onReceive方法

③清单文件注册(有的时候不能这么搞,需要通过代码动态注册) 动态的要求控件活着 才能接收到广播

④可选 有的广播接收者需要权限 如果需要权限还得在清单文件中声明权限

有序广播和无序广播的区别:

有序广播可以被中断  有序广播的内容可以被修改  abordBroadCast(); 如果调用这个方法之后 广播 中断了说明是有序广播

接收有序广播的时候 声明priority可以确定接收等级 范围是0-1000

publicvoidsend(Viewv){

Intentintent=newIntent();

intent.setAction("com.it.sendrice");

//收到广播时需要的权限

StringreceiverPermission=null;

//作为最终的广播接受者

BroadcastReceiverresultReceiver=newFinalReceiver();

//最终的广播接收者 传null在主线程处理

Handlerscheduler=null;

//数据

StringinitialData="皇帝发放赈灾粮 每人一百斤";

sendOrderedBroadcast(intent,receiverPermission,resultReceiver,scheduler,Activity.RESULT_OK,initialData,null);

}

无序广播不能被中断  无序广播内容不可以修改     abordBroadCast(); 如果调用之后报红色日志

publicvoidsendbroadcast(Viewv){

Intentintent=newIntent();

intent.setAction("com.it.broadcast");  //接收广播程序中注册的action与这个相同

intent.putExtra("key","hello");

sendBroadcast(intent);

}

广播携带的数据类型:Boolean     Bundle     byte     char    CharSequce   double     float     int     long    short    string   Serializable    Parcelable 和其数组

动态注册广播接收者:通过在activity 或者 service中调用 registerReceiver方法 注册广播接收者

BroadcastReceiverreceiver=newScreenLightRecriver();//这个类为自己创建的

//意图过滤器

IntentFilterfilter=newIntentFilter();

//意图过滤器添加ACTION

filter.addAction("android.intent.action.SCREEN_OFF");

filter.addAction("android.intent.action.SCREEN_ON");

//动态注册一个广播

registerReceiver(receiver,filter);

动态注册的广播接收者:只有调用了注册的方法之后才能够收到广播 静态注册广播接受者 在清单文件中声明一个receiver节点

除了一些特殊的广播接收者必须通过 动态方式注册 只要在清单文件中声明了对应的receiver 不管应用是否在运行都可以收到广播

动态注册的广播接收者通过当前Activity销毁的时候需要注销掉

contentprovider/ contentresolver

内容提供者,内容解析者

意义:跨应用提供数据 让其他应用访问本应用数据库中的内容

实现步骤:

① 创建一个类 继承ContentProvider 重写里面方法

② 在清单文件中注册相应provider  必须指定authorities 属性 还要添加一个属性 exported = true

③ 在provider中处理uri匹配相关内容

创建URI匹配器 在provider 中搞静态代码块 在static代码块中添加 uri匹配的规则

根据业务逻辑 在不同的数据库操作方法中 处理uri匹配的流程

④ 其他应用访问contentprovider方法

获得contentresolver内容解析者对象 getContentResolver

通过contentresolver调用 增删改查 方法访问contentprovider

需要注意 uri 要以content://开头  具体的路径 要跟contentprovider中 定义的uri匹配规则匹配上

contentObserver内容观察者:

在数据内容发生改变的地方通过contentResolver发送数据变化的通知 notifyChange

在需要接受变化的地方 注册一个内容观察者(可以在同一个应用中 也可以是在不同的应用中)

①写一个类继承ContentObserver 重写onChange方法

②通过contentResolver 调用registerObserver方法注册内容观察者

resolver.registerContentObserver(uri, false, new MyObserver(new Handler()) );

//第一个参数 uri 把内容观察者注册到这个uri上 如果有通知 说明这个uri对应的 内容发生改变 内容观察者就会收到通知

//第二个参数 路径匹配的规则 如果传入true 路径前部分匹配上就可以收到通知 如 果传false只有整个路径都匹配上才能收到通知

//第三个参数 内容观察者

文件的存储

SharedPrefenrences

可以保存的数据类型比较少 所以 用sp来保存一些简单的配置信息boolean string int long float Set

①获取sp的实例 getSharedPreferences("文件名",Mode_private);

②读内容 getXXXX(key,默认值); 获取 SharedPreferences的Editor edit(); editor.putXXXX(key,value); commit();提交 只有调用了这个方法 保存的内容才会存到本地

保存位置为包名文件下 一个文件 保存格式为xml格式

上下文获取(context)

上下文 描述了当前应用的环境

是一个接口 可以通过上下文访问到跟当前应用相关的资源 资源包括系统的资源(getsystemservice

获取系统的服务 getwallpaper 获取壁纸) 也包括应用的私有的资源  getAssets 获取assets目录下的内容

getResource() 获取res目录对应的api 也可以做应用级别的调用 开启一个activity startActivity  开启服务 startService

getFileDir 获取与应用相关的私有路径getAbsolutePath()返回抽象路径名的绝对路径名字符串

getPackageManags 获取应用包管理器 getPackageName获取应用包名

//通过上下文获取应用相关的私有路径 不要用写死路径的方式

//File file = new File(context.getFilesDir().getAbsolutePath()+"/info.txt");FileOutputStream fos = new FileOutputStream(file);

可以通过这行取代上边两行 FileOutputStream fos = context.openFileOutput("info2.txt", Context.MODE_PRIVATE);

//通过上下文的api 获取到data/data/包名/files目录下对应文件的 输入流

FileInputStream fis = context.openFileInput("info2.txt");

sd卡

API=Environment环境 getExternalStprageState 获取外部存储器的状态 MEDIA_MOUNTED 存在并且可读写

getExternalStorageDirectory 获取sD卡的路径

通过这个api就可以在存储的时候 Environment.getExternalStorageDirectory(),"info2.txt"

数据库

第一步: 创建一个类继承 SQLiteOpenHelper  并实现父类的构造

第二步  从写onCreate 方法 和onUpgrade 方法

第三步  在Activity中 创建MySQLOpenHelper对象( 注意 !!!! 至此并没有创建数据库)

第四部  调用 MySQLOpenHelper的getReadableDatabase或getWriteableDatabase方法获 取SQLiteDataBase对象

增加 删除 改变 使用 execSQL

查询使用 rawQuery 得到curor 后遍历

curor相关方法 moveToNext() 移动到下一行    getCount() 返回查询到的结果一共有多少行

getColumnCount()返回一条结果中有多少列

getString(index), getInt(index) 根据列序号返回相应记录(序号从0开始)

或者   使用封装好的api     ①insert方法                ②delete方法                ③update方法                ④query方法

访问网络

获取&提交数据

servlet 是运行在 Web 服务器中的小型 Java 程序。servlet 通常通过 HTTP(超文本传输 协议)接收和响应来自 Web 客户端的请求。

①创建一个类 继承HttpServlet ②重写两个方法 doGet  doPost 这两个方法都接受相同的参数

http协议

HTTP,HyperText Transfer Protocol

超文本传输协议 目前使用的版本 1.1  每次链接之后可以保持链接不断  直到所有数据加载完毕之后 再断开链接

之前老版本 1.0 每次连接之后 必须断开链接 内容没请求完 下次请求还需要创建新的tcp链接

http 请求 比如 在浏览器中输入地址 回车 向服务端请求数据 这个操作就是一个http请求

响应 服务端给浏览器返回数据就是http响应

请求方式

常用的有两种  put head trace delete

get       ①url后面 url和具体的参数用? 不同的提交参数之间 &隔开 key=value

②get方式提交所有的参数都在地址栏中显示 没有post安全

③ 浏览器对地址栏接受参数的长度有限制 所以get方式不能提交大量数据 (2k~8k) get方式提交参数的长 度<2k 的

post    ① 参数的提交是放到请求体中

② 比get方式更安全

③ 提交参数的长度不受限制  文件上传这样的操作一定要使用post

Handler原理

Handler  Message  MessageQueue  Looper

①Looper 轮询器 通过Looper去消息队列取消息 当主线程创建的时候 就会创建一个looper looper在new的时候 会创建一个MessageQueue 所以 一个线程对应一个Looper一个Looper对应一个MessageQueueLooper 创建之后 必须调用loop方法 loop方法中 有一个死循环 这个死循环会不断去消息队列里取 消息 取出消息之后 就会调用 handler的handlemessage方法处理消息

②MessageQueue 通过消息队列 把消息进行排序 排序的依据就是消息要执行的时间

③Handler 用来发送消息 sendMessage->sendMessageAtTime(Message, long uptimeMillis) 第一个参数 要发送的消息 第二个参数 消息要执行的而时间  这个时间就是消息在消息队列中排序的依据sendMessage 最终会调用MessageQueue 的enqueueMessage方法 把消息放到消息队列进行排序      handler 处理消息 handlerMessage

需要记忆的 刻骨铭心的  联网必须开线程  子线程不能更新UIANR 应用没有响应

(① handler  ② runOnUIThread())

联网① 需要权限 android.permission.INTERNET

② 用到的基类 HttpURLConnection  URL url= new URL(String);

url.openConnection();

HttpURLConnection .setRequestMethod()设置请求方法

setConnectTimeOut 设置超时时间

getResponseCode 获取响应码

getInputStream 获取返回的输入流

handler  Message msg = Message.obtain(); 获取消息

msg.obj 通过这个属性携带数据

msg.what 通过这个int变量区分不同消息

handler.sendMessage(Message)

handler.sendEmptyMessage(int what); 发送空消息 runOnUIThread(Runnable );

Bitmap bm =BitmapFactory.decodestream(inputstream)  从流解析一张图片

BitmapFactory.decodefile(String path) 从路径解析图片

ImageView.setImageBitmap(Bitmap bm ) 给imageview设置图片

使用httpurlconnection 把数据提交到服务器

get方式提交 跟直接获取数据不提交参数的时候 区别很小 唯一有不同的地方是 参数要拼接到URL的后面 拼接的时候需要注意 如果有中文的参数 需要进行URL编码 URLencoder.encode();

post方式提交 需要设置请求头 Content-Type Content-Length 请求的参数是通过请求体以流的方式提交到服务端的 打开输出流 setDoOutput(true) 获取输出流  getOutputStream();

需要注意 请求的参数中如果包含中文内容也需要进行URL编码

以httpclient方式把数据提交到服务器

①获取HttpClient 接口  找到实现类 Default  Simple   Basic Base 找到 无参构造函数 DefaultHttpClient();

②通过请求获取响应   execute(HttpRequest);->httpresponse

③HttpRequest也是接口 发现根据不同的请求方式有对应的实现类 HttpGet HttpPost

多线程下载

①多下程下载的好处 可以突破服务端对单一线程的速度限制

②多线程下载的原理 2.1服务端得支持多线程读取数据 可以通过Range头来通知服务端 当前线程请求的数据范围 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);

range头成功返回数据 响应码是206 2.2客户端通过RandomAccessFile 进行多线程写 写的时候调用RandomAccessFile的seek方法

不 同线程移动到不同的位置开始写文件

①联网 获取要下载文件的大小 ②本地创建一个相同大小的文件 ③根据线程的数量和要下载文件的大小计算每个线程要下载的数据范围

④开启线程 联网 拿着计算好的数据范围到服务端请求数据  响应码206 ⑤通过RandomAccessFile保存文件 调用seek方法

UI相关

listview

ListView 入门

这个控件是用垂直滚动的列表展示条目.由ListAdapter(列表适配器)提供条目.

1.在xml文件中添加ListView控件 添加id 找到控件 设置一个适配器 写一个类 实现BaseAdapter(接口的抽象类) 重写4个方法

2.getView方法 通过这个方法创建条目的界面 决定了每一个条目长成什么样子 新建TextView 设置数据

ListView 优化

1.getCount 方法决定要展示多少条目; convertview 为空表示目前没有view对象被移出屏幕

2.判断convertview== null 创建TextView对象展示条目  如果不为空 tv_text=()covertView ;

fastScrollEnabled 允许快速滚动

ListView展示数据的原理(MVC)

view 视图    controller 控制器   model 数据模型

ListView     baseAdapter         Arraylist

TextView 文本展示

EditText 文本输入框

Button 按钮

Imageview 图片

ImageButton 图片按钮

RadioGroup  与单选按钮有关

CheckBox  勾选框booleanchecked =cb.isChecked()if(checked) {}else{} 可根据勾选状态做响应的操作

progressbar  进度条style="@android:style/Widget.ProgressBar.Horizontal"可设置为横向的

seekbar可拖动的进度条

AlertDialog 对话框

progressDialog  进度条

AutocompleteTextView  自动补全的TextView

Menu 菜单

Surfaceview 视频

VideoView 视频

多媒体

图片处理

通过Matrix 矩阵rotate 旋转Translate 平移 Scale缩放

每次set后图片都会恢复 如果想在set基础上操作 需用post方法

大图加载:

通过比较图片分辨率和屏幕分辨率 如果图片分辨率大 需要进行压缩,压缩的大小就是 图片分辨率和屏幕分辨率宽度和高度的比例

如果inJustDecodeBounds设置为true那么再调用BitmapFactory.decodeXXX方法的时候只会读取图片的宽度和高度

//取宽度和高度计算出来的比例的最大值 作为压缩的大小

option.inSampleSize = Math.max(Math.round(heightIndex), Math.round(widthIndex));

option.inJustDecodeBounds = false;

创建图片副本:

//通过BitmapFactory加载图片

//创建出一张跟原图一样大的空白图片 这个图片可以修改  mutable

Bitmap bm = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

//通过canvas画图canvas.drawBitmap(bitmap, matrix, paint);

音频视频的播放

MediaPlayer播放:

new MediaPlayer();

player.setDataSource("mnt/sdcard/xpg.mp3");//设置数据源

player.prepare();player.start();

Surfaceview播放

VideoView 播放

Vitamio播放动画:导入开源项目

动画

Animation and Graphics Overview 通过安卓提供的api让ui动起来 也可以画 2d或者3D动画 3.0之后加入了属性动画

帧动画 Drawable Animation

补间动画view Animation

使用xml方式定义补间动画 ①在res目录下创建一个anim目录 在里面声明xml文件

②在代码中使用animationUtils.loadAnimation加载需要注意 补间动画/view动画 不会改变控件的位置

属性动画property Animation (android 3.0之后加入)

属性动画 确实修改了控件的属性 如果使用的属性动画 看到控件位置改变了 实际的位置也改变了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值