Android Util工具类的封装

摘要

本文总结了过往项目和一些资料上的Android 工具类的封装,既当做是总结,也作收集收藏用。感谢网络上诸方资料。

SharedPreferences工具类:SPUtil.java

public class SPUtil {
    public static final String FILE_DEFAULT = "default";

    public static int getInt(String key) {
        SharedPreferences sharedPreferences = getSharePreferences(FILE_DEFAULT);
        return sharedPreferences.getInt(key, 0);
    }

    public static boolean getBoolean(String key) {
        SharedPreferences sharedPreferences = getSharePreferences(FILE_DEFAULT);
        return sharedPreferences.getBoolean(key, false);
    }

    public static float getFloat(String key) {
        SharedPreferences sharedPreferences = getSharePreferences(FILE_DEFAULT);
        return sharedPreferences.getFloat(key, 0);
    }

    public static boolean getBoolean(String key, boolean defValue) {
        SharedPreferences sharedPreferences = getSharePreferences(FILE_DEFAULT);
        return sharedPreferences.getBoolean(key, defValue);
    }

    public static String getString(String key) {
        SharedPreferences sharedPreferences = getSharePreferences(FILE_DEFAULT);
        return sharedPreferences.getString(key,FILE_DEFAULT);
    }

    public static String getStringWithDefault(String key, String defStr) {
        SharedPreferences sharedPreferences = getSharePreferences(FILE_DEFAULT);
        return sharedPreferences.getString(key, defStr);
    }

    public static void putInt(String key, int value) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(FILE_DEFAULT));
        editor.putInt(key, value);
        editor.commit();
    }

    public static void putBoolean(String key, boolean value) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(FILE_DEFAULT));
        editor.putBoolean(key, value);
        editor.commit();
    }

    public static void putString(String key, String value) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(FILE_DEFAULT));
        editor.putString(key, value);
        editor.commit();
    }

    public static void putFloat(String key, float value) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(FILE_DEFAULT));

        editor.putFloat(key, value);
        editor.commit();
    }

    public static void putLong(String key, long value) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(FILE_DEFAULT));

        editor.putLong(key, value);
        editor.commit();
    }


    public static long getLong(String key) {
        SharedPreferences sharedPreferences = getSharePreferences(FILE_DEFAULT);
        return sharedPreferences.getLong(key, 0);
    }

    public static int getInt(String key, int defValue) {
        SharedPreferences sharedPreferences = getSharePreferences(FILE_DEFAULT);
        return sharedPreferences.getInt(key, defValue);
    }

    public static int getInt(String key, String fileName) {

        SharedPreferences sharedPreferences = getSharePreferences(getFileName(fileName));
        return sharedPreferences.getInt(key, 0);
    }

    public static boolean getBoolean(String key, String fileName) {
        SharedPreferences sharedPreferences = getSharePreferences(getFileName(fileName));
        return sharedPreferences.getBoolean(key, false);
    }

    public static String getString(String key, String fileName) {
        SharedPreferences sharedPreferences = getSharePreferences(getFileName(fileName));
        return sharedPreferences.getString(key, null);
    }

    public static float getFloat(String key, String fileName) {
        SharedPreferences sharedPreferences = getSharePreferences(getFileName(fileName));
        return sharedPreferences.getFloat(key, 0);
    }

    public static long getLong(String key, String fileName) {
        SharedPreferences sharedPreferences = getSharePreferences(getFileName(fileName));
        return sharedPreferences.getLong(key, 0);
    }

    public static void putInt(String key, int value, String fileName) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(getFileName(fileName)));
        editor.putInt(key, value);
        editor.commit();

    }

    public static void putBoolean(String key, boolean value, String fileName) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(getFileName(fileName)));

        editor.putBoolean(key, value);
        editor.commit();
    }

    public static void putString(String key, String value, String fileName) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(getFileName(fileName)));

        editor.putString(key, value);
        editor.commit();
    }

    public static void putFloat(String key, float value, String fileName) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(getFileName(fileName)));

        editor.putFloat(key, value);
        editor.commit();
    }

    public static void putLong(String key, long value, String fileName) {
        SharedPreferences.Editor editor = getEditor(getSharePreferences(getFileName(fileName)));

        editor.putLong(key, value);
        editor.commit();
    }

    private static SharedPreferences getSharePreferences(String fileName) {
        return TApplication.getContext().getSharedPreferences(fileName, Context.MODE_PRIVATE);

    }

    private static SharedPreferences.Editor getEditor(SharedPreferences sharedPreferences) {
        return sharedPreferences.edit();
    }

    public static String getFileName(String fileName) {
        if (!TextUtils.isEmpty(fileName)) {
            return fileName;
        } else {
            return FILE_DEFAULT;
        }
    }
}

ToastUtil.java

    public class ToastUtils {


    private static Toast mToast ;
    private static Handler mHandler = new Handler();
    private static Runnable r = new Runnable() {
        @Override
        public void run() {
            mToast.cancel();
        }
    } ;

    /**
     * 自定义toast,重复点击时,会直接替换文本,不会重新创建新的Toast并加入队列中一条条显示
     * @param context
     * @param text
     * @param duration
     */
    public static void showToast(Context context,String text,int duration) {
        mHandler.removeCallbacks(r);
        if (mToast != null) {
            mToast.setText(text);
        } else {
            mToast = Toast.makeText(context,text,Toast.LENGTH_SHORT);
        }
        mHandler.postDelayed(r,duration) ;
        mToast.show();
    }

    /**
     * 防重复点击的toast,即便是帕金森患者也不会导致toast一直显示着
     * @param text
     */
    public static void showToast(String text) {
        showToast(TApplication.getContext(),text,1000);
    }

    public static void showToast(Context context,int resId,int duration) {
        showToast(context,context.getResources().getString(resId),duration);
    }


    public static void show(CharSequence text) {
        Toast.makeText(TApplication.getContext(), text, Toast.LENGTH_SHORT).show();
    }

    /**
     * 显示土司的工具类,安全的工具类可以在任意线程里面显示
     * @param activity
     * @param text
     */
    public static void show(final Activity activity, final CharSequence text) {
        if ("main".equalsIgnoreCase(Thread.currentThread().getName())) {
            if (activity == null){
                return;
            }
            Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
        } else {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    /**
     * 显示土司的工具类,安全的工具类可以在任意线程里面显示
     * @param activity
     * @param text
     * @param length 显示的时常
     */
    public static void show(final Activity activity, final CharSequence text, final int length) {
        if ("main".equalsIgnoreCase(Thread.currentThread().getName())) {
            Toast.makeText(activity, text, length).show();
        } else {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(activity, text, length).show();
                }
            });
        }
    }
}

DensityUtils.java

public class DensityUtils  {  

    private DensityUtils()  
    {  
        /* cannot be instantiated */  
        throw new UnsupportedOperationException("cannot be instantiated");  
    }  

    /** 
     * dp转px 
     *  
     * @param context 
     * @param val 
     * @return 
     */  
    public static int dp2px(Context context, float dpVal)  
    {  
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  
                dpVal, context.getResources().getDisplayMetrics());  
    }  

    /** 
     * sp转px 
     *  
     * @param context 
     * @param val 
     * @return 
     */  
    public static int sp2px(Context context, float spVal)  
    {  
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,  
                spVal, context.getResources().getDisplayMetrics());  
    }  

    /** 
     * px转dp 
     *  
     * @param context 
     * @param pxVal 
     * @return 
     */  
    public static float px2dp(Context context, float pxVal)  
    {  
        final float scale = context.getResources().getDisplayMetrics().density;  
        return (pxVal / scale);  
    }  

    /** 
     * px转sp 
     *  
     * @param fontScale 
     * @param pxVal 
     * @return 
     */  
    public static float px2sp(Context context, float pxVal)  
    {  
        return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);  
    }  

}

SDCardUtils.java

public class SDCardUtils  {  

    private SDCardUtils()  
    {  
        /* cannot be instantiated */  
        throw new UnsupportedOperationException("cannot be instantiated");  
    }  

    /** 
     * 判断SDCard是否可用 
     *  
     * @return 
     */  
    public static boolean isSDCardEnable()  
    {  
        return Environment.getExternalStorageState().equals(  
                Environment.MEDIA_MOUNTED);  

    }  

    /** 
     * 获取SD卡路径 
     *  
     * @return 
     */  
    public static String getSDCardPath()  
    {  
        return Environment.getExternalStorageDirectory().getAbsolutePath()  
                + File.separator;  
    }  

    /** 
     * 获取SD卡的剩余容量 单位byte 
     *  
     * @return 
     */  
    public static long getSDCardAllSize()  
    {  
        if (isSDCardEnable())  
        {  
            StatFs stat = new StatFs(getSDCardPath());  
            // 获取空闲的数据块的数量  
            long availableBlocks = (long) stat.getAvailableBlocks() - 4;  
            // 获取单个数据块的大小(byte)  
            long freeBlocks = stat.getAvailableBlocks();  
            return freeBlocks * availableBlocks;  
        }  
        return 0;  
    }  

    /** 
     * 获取指定路径所在空间的剩余可用容量字节数,单位byte 
     *  
     * @param filePath 
     * @return 容量字节 SDCard可用空间,内部存储可用空间 
     */  
    public static long getFreeBytes(String filePath)  
    {  
        // 如果是sd卡的下的路径,则获取sd卡可用容量  
        if (filePath.startsWith(getSDCardPath()))  
        {  
            filePath = getSDCardPath();  
        } else  
        {// 如果是内部存储的路径,则获取内存存储的可用容量  
            filePath = Environment.getDataDirectory().getAbsolutePath();  
        }  
        StatFs stat = new StatFs(filePath);  
        long availableBlocks = (long) stat.getAvailableBlocks() - 4;  
        return stat.getBlockSize() * availableBlocks;  
    }  

    /** 
     * 获取系统存储路径 
     *  
     * @return 
     */  
    public static String getRootDirectoryPath()  
    {  
        return Environment.getRootDirectory().getAbsolutePath();  
    }  

}

屏幕辅助类ScreenUtils.java

public class ScreenUtils  {  

    private ScreenUtils()  
    {  
        /* cannot be instantiated */  
        throw new UnsupportedOperationException("cannot be instantiated");  
    }  

    /** 
     * 获得屏幕高度 
     *  
     * @param context 
     * @return 
     */  
    public static int getScreenWidth(Context context)  
    {  
        WindowManager wm = (WindowManager) context  
                .getSystemService(Context.WINDOW_SERVICE);  
        DisplayMetrics outMetrics = new DisplayMetrics();  
        wm.getDefaultDisplay().getMetrics(outMetrics);  
        return outMetrics.widthPixels;  
    }  

    /** 
     * 获得屏幕宽度 
     *  
     * @param context 
     * @return 
     */  
    public static int getScreenHeight(Context context)  
    {  
        WindowManager wm = (WindowManager) context  
                .getSystemService(Context.WINDOW_SERVICE);  
        DisplayMetrics outMetrics = new DisplayMetrics();  
        wm.getDefaultDisplay().getMetrics(outMetrics);  
        return outMetrics.heightPixels;  
    }  

    /** 
     * 获得状态栏的高度 
     *  
     * @param context 
     * @return 
     */  
    public static int getStatusHeight(Context context)  
    {  

        int statusHeight = -1;  
        try  
        {  
            Class<?> clazz = Class.forName("com.android.internal.R$dimen");  
            Object object = clazz.newInstance();  
            int height = Integer.parseInt(clazz.getField("status_bar_height")  
                    .get(object).toString());  
            statusHeight = context.getResources().getDimensionPixelSize(height);  
        } catch (Exception e)  
        {  
            e.printStackTrace();  
        }  
        return statusHeight;  
    }  

    /** 
     * 获取当前屏幕截图,包含状态栏 
     *  
     * @param activity 
     * @return 
     */  
    public static Bitmap snapShotWithStatusBar(Activity activity)  
    {  
        View view = activity.getWindow().getDecorView();  
        view.setDrawingCacheEnabled(true);  
        view.buildDrawingCache();  
        Bitmap bmp = view.getDrawingCache();  
        int width = getScreenWidth(activity);  
        int height = getScreenHeight(activity);  
        Bitmap bp = null;  
        bp = Bitmap.createBitmap(bmp, 0, 0, width, height);  
        view.destroyDrawingCache();  
        return bp;  

    }  

    /** 
     * 获取当前屏幕截图,不包含状态栏 
     *  
     * @param activity 
     * @return 
     */  
    public static Bitmap snapShotWithoutStatusBar(Activity activity)  
    {  
        View view = activity.getWindow().getDecorView();  
        view.setDrawingCacheEnabled(true);  
        view.buildDrawingCache();  
        Bitmap bmp = view.getDrawingCache();  
        Rect frame = new Rect();  
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);  
        int statusBarHeight = frame.top;  

        int width = getScreenWidth(activity);  
        int height = getScreenHeight(activity);  
        Bitmap bp = null;  
        bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height  
                - statusBarHeight);  
        view.destroyDrawingCache();  
        return bp;  

    }  

}

AppUtils

public class AppUtils  {  

    private AppUtils()  
    {  
        /* cannot be instantiated */  
        throw new UnsupportedOperationException("cannot be instantiated");  
    }  

    /** 
     * 获取应用程序名称 
     */  
    public static String getAppName(Context context)  
    {  
        try  
        {  
            PackageManager packageManager = context.getPackageManager();  
            PackageInfo packageInfo = packageManager.getPackageInfo(  
                    context.getPackageName(), 0);  
            int labelRes = packageInfo.applicationInfo.labelRes;  
            return context.getResources().getString(labelRes);  
        } catch (NameNotFoundException e)  
        {  
            e.printStackTrace();  
        }  
        return null;  
    }  

    /** 
     * [获取应用程序版本名称信息] 
     *  
     * @param context 
     * @return 当前应用的版本名称 
     */  
    public static String getVersionName(Context context)  
    {  
        try  
        {  
            PackageManager packageManager = context.getPackageManager();  
            PackageInfo packageInfo = packageManager.getPackageInfo(  
                    context.getPackageName(), 0);  
            return packageInfo.versionName;  

        } catch (NameNotFoundException e)  
        {  
            e.printStackTrace();  
        }  
        return null;  
    }  

}

NetUtils.java

public class NetUtils {  

    public static final int NO_NETWORK = 0;
    public static final int NETWORK_WIFI = 1;
    public static final int NETWORK_MOBILE = 2;

    private NetUtils()  
    {  
        /* cannot be instantiated */  
        throw new UnsupportedOperationException("cannot be instantiated");  
    }  

    /** 
     * 判断网络是否连接 
     */  
    public static boolean isConnected(Context context)  
    {  
        ConnectivityManager connectivity = (ConnectivityManager) context  
                .getSystemService(Context.CONNECTIVITY_SERVICE);  

        if (null != connectivity)  
        {  
            NetworkInfo info = connectivity.getActiveNetworkInfo();  
            if (null != info && info.isConnected())  
            {  
                if (info.getState() == NetworkInfo.State.CONNECTED)  
                {  
                    return true;  
                }  
            }  
        }  
        return false;  
    }  

    /** 
     * 判断是否是wifi连接 
     */  
    public static boolean isWifi(Context context)  
    {  
        ConnectivityManager cm = (ConnectivityManager) context  
                .getSystemService(Context.CONNECTIVITY_SERVICE);  

        if (cm == null)  
            return false;  
        return cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI;  

    }  

    /** 
     * 打开网络设置界面 
     */  
    public static void openSetting(Activity activity)  
    {  
        Intent intent = new Intent("/");  
        ComponentName cm = new ComponentName("com.android.settings",  
                "com.android.settings.WirelessSettings");  
        intent.setComponent(cm);  
        intent.setAction("android.intent.action.VIEW");  
        activity.startActivityForResult(intent, 0);  
    }  

    /**
     * 检查网络连接
     *
     * @param context
     * @return 0为无网络状态,1为wifi连接状态,2为移动网络连接状态
     */
    public static int checkNetwork(Context context) {
        if (context == null) {
            return NETWORK_WIFI;

        }
        ConnectivityManager cm = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo wifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        if (wifi != null && wifi.isConnected()) {
            return NETWORK_WIFI;
        }
        NetworkInfo mobile = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        if (mobile != null && mobile.isConnected()) {
            return NETWORK_MOBILE;
        }
        return NO_NETWORK;
    }

}

其他

ToolUtils.java
/**
 * 判断输入文本是否含有emoji
 * @param string
 * @return
 */
public static boolean isEmoji(String string) {
    Pattern p = Pattern.compile("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(string);
    return m.find();
}

/*public static boolean isEmoji1(String string) {
    Pattern p = Pattern.compile("/[\u1F60-\u1F64]|[\u2702-\u27B0]|[\u1F68-\u1F6C]|[\u1F30-\u1F70]|[\u2600-\u26ff]/g");
    Matcher m = p.matcher(string);
    return m.matches();
}*/

/**
 * 判断是不是emoji字符
 * @param codePoint
 * @return
 */
private static boolean isEmojiCharacter(char codePoint) {
    return (codePoint == 0x0) ||
            (codePoint == 0x9) ||
            (codePoint == 0xA) ||
            (codePoint == 0xD) ||
            ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
            ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
            ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
}

/**
 * 过滤emoji 或者 其他非文字类型的字符
 * @param source
 * @return
 */
public static String filterEmoji(String source) {

    if (!isEmoji(source)) {
        return source;//如果不包含,直接返回
    }
    //到这里铁定包含
    StringBuilder buf = null;

    int len = source.length();

    for (int i = 0; i < len; i++) {
        char codePoint = source.charAt(i);

        if (isEmojiCharacter(codePoint)) {
            if (buf == null) {
                buf = new StringBuilder(source.length());
            }

            buf.append(codePoint);
        } else {
        }
    }
    if (buf == null) {
        return source;//如果没有找到 emoji表情,则返回源字符串
    } else {
        if (buf.length() == len) {//这里的意义在于尽可能少的toString,因为会重新生成字符串
            buf = null;
            return source;
        } else {
            return buf.toString();
        }
    }

}
 /**
 * 显示一个进度条
 * @param activity
 * @param customIndeterminateDrawable 自定义进度条加载图片
 * @return
 */
public static ProgressBar createProgressBar(Activity activity, Drawable customIndeterminateDrawable) {
    // activity根部的ViewGroup,其实是一个FrameLayout
    FrameLayout rootContainer = (FrameLayout) activity.findViewById(android.R.id.content);
    // 给progressbar准备一个FrameLayout的LayoutParams
    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);
    // 设置对其方式为:屏幕居中对其
    lp.gravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL;

    ProgressBar progressBar = new ProgressBar(activity);
    progressBar.setVisibility(View.GONE);
    progressBar.setLayoutParams(lp);
    // 自定义小菊花
    if (customIndeterminateDrawable != null) {
        progressBar.setIndeterminateDrawable(customIndeterminateDrawable);
    }
    // 将菊花添加到FrameLayout中
    rootContainer.addView(progressBar);
    return progressBar;
}

权限相关 PermissionUtils.java

public static boolean checkPermission(String[] permissions,Activity activity,int requestCode){
    List<String> needRequestPermissionList = ToolUtil.findDeniedPermissions(permissions,activity);
    if (needRequestPermissionList != null && needRequestPermissionList.size() > 0){
        ActivityCompat.requestPermissions(activity,needRequestPermissionList.toArray
                (new String[needRequestPermissionList.size()]), PERMISSION_REQUESTCODE);
        return true;
    }
    else return false;
}

public static boolean checkPermission(String[] permissions,Activity activity){
    List<String> needRequestPermissionList = ToolUtil.findDeniedPermissions(permissions,activity);
    if (needRequestPermissionList != null && needRequestPermissionList.size() > 0){
        ActivityCompat.requestPermissions(activity,needRequestPermissionList.toArray
                (new String[needRequestPermissionList.size()]), PERMISSION_REQUESTCODE);
        return true;
    }
    else return false;
}

/**
 *获取权限集中需要申请权限的列表
 * @param permissions
 * @param activity
 * @return
 */
public static List<String> findDeniedPermissions(String[] permissions,Activity activity) {
    List<String> needRequestPermissionList = new ArrayList<>();
    for (String perm : permissions){
        if (ContextCompat.checkSelfPermission(TApplication.getContext(),perm) != PackageManager.PERMISSION_GRANTED){
            needRequestPermissionList.add(perm);
        }else{
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity,perm)){
                  needRequestPermissionList.add(perm);
            }
        }
    }
    return needRequestPermissionList;
}

/**
 * 检测是否说有的权限都有了
 * @param grantResults
 * @return
 */
public static boolean verifyPermission(int[] grantResults){
     for (int result : grantResults){
         if (result != PackageManager.PERMISSION_GRANTED){
             return false;
         }
     }
    return true;
}


public static void showMissingPermissionDialog(final Activity activity) {
    android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(activity);
    builder.setTitle(R.string.notifyMsg);

    builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            activity.finish();
        }
    });

    builder.setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            startAppSetting(activity);
        }
    });
    builder.setCancelable(false);
    builder.show();
}

public static void startAppSetting(Activity activity) {
    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    intent.setData(Uri.parse("package:"+activity.getPackageName()));
    activity.startActivity(intent);
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值