JamesMusic浅读--------6,补全欢迎界面,音乐文件数据库

前面我们实现了文件夹的操作,解下来就是从文件夹里面的音乐引入到音乐列表。由于音乐文件搜索在最后一个界面, 那我们就先实现最后一个welcom界面。


public class ReadyToScanFragment extends Fragment {
    private Context mContext;
    private TextView welcomeHeader;
    private TextView welcomeText1;
    private  TextView swipeLeftToContinue;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mContext = getActivity().getApplication();
        View rootView = (View)inflater.inflate(R.layout.fragment_welcome_screen_6,container, false);
        return rootView;
    }
}


将这个类的对象添加到WelcomePagerAdapter,这样我们就可以显示这个界面了。

在WecomActivity中进入这个界面时候,会启用搜索文件的异步任务。

在这之前是一个动画效果,我们先忽略这个效果直接实现文件搜索。通过一个Service实现,并将其设置为前台任务及其后台进程。




/**
 * Created by kankan on 2016/5/29.
 */
public class BuildMusicLibraryService extends Service implements AsyncBuildLibraryTask.OnBuildLibraryProgressUpdate {

    private Context mContext;
    private NotificationCompat.Builder mBuilder;
    private Notification mNotification;
    private NotificationManager mNotifyManager;

    public static int mNotificationId = 92713;


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = this.getApplicationContext();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        /*  */
        mBuilder = new NotificationCompat.Builder(mContext);
        mBuilder.setSmallIcon(android.support.design.R.id.split_action_bar);
        mBuilder.setContentTitle(getResources().getString(R.string.building_music_library));
        mBuilder.setTicker(getResources().getString(R.string.building_music_library));
        mBuilder.setContentText("123");
        mBuilder.setProgress(0, 0, true);

        mNotifyManager =(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        mNotification = mBuilder.build();
        mNotification.flags |= Notification.FLAG_INSISTENT|Notification.FLAG_NO_CLEAR;

        startForeground(mNotificationId, mNotification);

        AsyncBuildLibraryTask task = new AsyncBuildLibraryTask(mContext, this);
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        return START_STICKY;
    }

    @Override
    public void onStartBuildingLibrary() {

    }

    @Override
    public void onProgressUpdate(AsyncBuildLibraryTask task, String mCurrentTask, int overallProgress, int maxProgress, boolean mediaStoreTransferDone) {

    }

    @Override
    public void onFinishBuildingLibrary(AsyncBuildLibraryTask task) {

    }
}
这个服务,第一是把自己变成前台任务,第二启动一个异步任务,用来将音乐文件的信息存入数据库。
我们看一下这个任务。
/**
 * Created by kankan on 2016/5/29.
 */
public class AsyncBuildLibraryTask extends AsyncTask<Void, Void, String>{

    private  String TAG =this.getClass().getSimpleName();
    private Context mContext;
    private Common mApp;
    private BuildMusicLibraryService mService;

    private String mCurrentTask = "";
    private int mOverallProgress = 0;
    private Date date = new Date();

    private String mMediaStoreSelection = null;
    private HashMap<String, String> mGenresHashMap = new HashMap<String, String>();
    private HashMap<String, Integer> mGenresSongCountHashMap = new HashMap<String, Integer>();
    private HashMap<String, Integer> mAlbumsCountMap = new HashMap<String, Integer>();
    private HashMap<String, Integer> mSongsCountMap = new HashMap<String, Integer>();
    private HashMap<String, Uri> mMediaStoreAlbumArtMap = new HashMap<String, Uri>();
    private HashMap<String, String> mFolderArtHashMap = new HashMap<String, String>();
    public AsyncBuildLibraryTask(Context mContext,  BuildMusicLibraryService mService) {
        this.mContext = mContext;
        this.mApp = (Common) mContext;
        this.mService = mService;
        // TODO: 2016/5/29  
    
    }

    /**
     * Provides callback methods that expose this
     * AsyncTask's progress.
     *
     * @author Saravan Pantham
     */
    public interface OnBuildLibraryProgressUpdate {

        /**
         * Called when this AsyncTask begins executing
         * its doInBackground() method.
         */
        public void onStartBuildingLibrary();

        /**
         * Called whenever mOverall Progress has been updated.
         */
        public void onProgressUpdate(AsyncBuildLibraryTask task, String mCurrentTask,
                                     int overallProgress, int maxProgress,
                                     boolean mediaStoreTransferDone);

        /**
         * Called when this AsyncTask finishes executing
         * its onPostExecute() method.
         */
        public void onFinishBuildingLibrary(AsyncBuildLibraryTask task);

    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

    }

    @Override
    protected String doInBackground(Void... params) {
        mCurrentTask = mContext.getResources().getString(R.string.building_music_library);
        Cursor mediaStoreCursor = getSongsFromMediaStore();

        if(mediaStoreCursor != null){
            saveMediaStoreDataToDB(mediaStoreCursor);
        }
        return null;
    }

    void saveMediaStoreDataToDB(Cursor mediaStoreCursor ){
        try{
            mApp.getDBAccessHelper().getWritableDatabase().beginTransaction();
            //clear out the table
            mApp.getDBAccessHelper()
                    .getWritableDatabase()
                    .delete(DBAccessHelper.MUSIC_LIBRARY_TABLE, null, null);
            //Tracks the progress of this method.
            int subProgress = 0;
            if(mediaStoreCursor.getCount() !=0){
                subProgress = 250000/(mediaStoreCursor.getCount());
            }else {
                subProgress = 250000/1;
            }
            buildGenresLibrary();
            buildArtistsLibrary();;
            buildAlbumsLibrary();;
            buildMediaStoreAlbumArtHash();

            final  int titleColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
            final int artistColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
            final int albumColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
            final int albumIdColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
            final int durationColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
            final int trackColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.TRACK);
            final int yearColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.YEAR);
            final int dateAddedColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.DATE_ADDED);
            final int dateModifiedColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.DATE_MODIFIED);
            final int filePathColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.DATA);
            final int idColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media._ID);
            int albumArtistColIndex = mediaStoreCursor.getColumnIndex(MediaStoreAccessHelper.ALBUM_ARTIST);

            if(albumArtistColIndex == -1){
                albumArtistColIndex = artistColIndex;
            }

            Log.i(TAG, "media store cursor "+ mediaStoreCursor.getCount());
            for(int i = 0 ;i < mediaStoreCursor.getCount(); i++) {
                mediaStoreCursor.moveToPosition(i);
                mOverallProgress += subProgress;
                publishProgress();
                Log.i(TAG, "progress " +i);

                String songTitle = mediaStoreCursor.getColumnName(titleColIndex);
                String songArtist = mediaStoreCursor.getString(artistColIndex);
                String songAlbum = mediaStoreCursor.getString(albumColIndex);
                String songAlbumId = mediaStoreCursor.getString(albumIdColIndex);
                String songAlbumArtist = mediaStoreCursor.getString(albumArtistColIndex);
                String songFilePath = mediaStoreCursor.getString(filePathColIndex);
                String songGenre = getSongGenre(songFilePath);
                String songDuration = mediaStoreCursor.getString(durationColIndex);
                String songTrackNumber = mediaStoreCursor.getString(trackColIndex);
                String songYear = mediaStoreCursor.getString(yearColIndex);
                String songDateAdded = mediaStoreCursor.getString(dateAddedColIndex);
                String songDateModified = mediaStoreCursor.getString(dateModifiedColIndex);
                String songId = mediaStoreCursor.getString(idColIndex);
                String numberOfAlbums = "" + mAlbumsCountMap.get(songArtist);
                String numberOfTracks = "" + mSongsCountMap.get(songAlbum + songArtist);
                String numberOfSongsInGenre = "" + getGenreSongsCount(songGenre);
                String songSource = DBAccessHelper.LOCAL;
                String songSavedPosition = "-1";

                String songAlbumArtPath = "";

                if (mMediaStoreAlbumArtMap.get(songAlbum) != null) {
                    songAlbumArtPath = mMediaStoreAlbumArtMap.get(songAlbumId).toString();
                }
                if (numberOfAlbums.equals("1"))
                    numberOfAlbums += " " + mContext.getResources().getString(R.string.album_small);
                else
                    numberOfAlbums += " " + mContext.getResources().getString(R.string.albums_small);

                if (numberOfTracks.equals("1"))
                    numberOfTracks += " " + mContext.getResources().getString(R.string.song_small);
                else
                    numberOfTracks += " " + mContext.getResources().getString(R.string.songs_small);

                if (numberOfSongsInGenre.equals("1"))
                    numberOfSongsInGenre += " " + mContext.getResources().getString(R.string.song_small);
                else
                    numberOfSongsInGenre += " " + mContext.getResources().getString(R.string.songs_small);
//Check if any of the other tags were empty/null and set them to "Unknown xxx" values.
                if (songArtist == null || songArtist.isEmpty()) {
                    songArtist = mContext.getResources().getString(R.string.unknown_artist);
                }

                if (songAlbumArtist == null || songAlbumArtist.isEmpty()) {
                    if (songArtist != null && !songArtist.isEmpty()) {
                        songAlbumArtist = songArtist;
                    } else {
                        songAlbumArtist = mContext.getResources().getString(R.string.unknown_album_artist);
                    }

                }

                if (songAlbum == null || songAlbum.isEmpty()) {
                    songAlbum = mContext.getResources().getString(R.string.unknown_album);
                    ;
                }

                if (songGenre == null || songGenre.isEmpty()) {
                    songGenre = mContext.getResources().getString(R.string.unknown_genre);
                }

                //Filter out track numbers and remove any bogus values.
                if (songTrackNumber != null) {
                    if (songTrackNumber.contains("/")) {
                        int index = songTrackNumber.lastIndexOf("/");
                        songTrackNumber = songTrackNumber.substring(0, index);
                    }
                    try {
                        if (Integer.parseInt(songTrackNumber) <= 0) {
                            songTrackNumber = "";
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                        songTrackNumber = "";
                    }

                }

                long durationLong = 0;
                try {
                    durationLong = Long.parseLong(songDuration);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                ContentValues values = new ContentValues();
                values.put(DBAccessHelper.SONG_TITLE, songTitle);
                values.put(DBAccessHelper.SONG_ARTIST, songArtist);
                values.put(DBAccessHelper.SONG_ALBUM, songAlbum);
                values.put(DBAccessHelper.SONG_ALBUM_ARTIST, songAlbumArtist);
                values.put(DBAccessHelper.SONG_DURATION, convertMillisToMinsSecs(durationLong));
                values.put(DBAccessHelper.SONG_FILE_PATH, songFilePath);
                values.put(DBAccessHelper.SONG_TRACK_NUMBER, songTrackNumber);
                values.put(DBAccessHelper.SONG_GENRE, songGenre);
                values.put(DBAccessHelper.SONG_YEAR, songYear);
                values.put(DBAccessHelper.SONG_ALBUM_ART_PATH, songAlbumArtPath);
                values.put(DBAccessHelper.SONG_LAST_MODIFIED, songDateModified);
                values.put(DBAccessHelper.SONG_ALBUM_ART_PATH, songAlbumArtPath);
                values.put(DBAccessHelper.BLACKLIST_STATUS, false);
                values.put(DBAccessHelper.ADDED_TIMESTAMP, date.getTime());
                values.put(DBAccessHelper.RATING, 0);
                values.put(DBAccessHelper.LAST_PLAYED_TIMESTAMP, songDateModified);
                values.put(DBAccessHelper.SONG_SOURCE, songSource);
                values.put(DBAccessHelper.SONG_ID, songId);
                values.put(DBAccessHelper.SAVED_POSITION, songSavedPosition);
                values.put(DBAccessHelper.ALBUMS_COUNT, numberOfAlbums);
                values.put(DBAccessHelper.SONGS_COUNT, numberOfTracks);
                values.put(DBAccessHelper.GENRE_SONG_COUNT, numberOfSongsInGenre);

                //Add all the entries to the database to build the songs library.
                mApp.getDBAccessHelper().getWritableDatabase().insert(DBAccessHelper.MUSIC_LIBRARY_TABLE,
                        null,
                        values);
            }
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            mApp.getDBAccessHelper().getWritableDatabase().setTransactionSuccessful();
            mApp.getDBAccessHelper().getWritableDatabase().endTransaction();
        }
    }

    private String getSongGenre(String filePath){
        if(mGenresHashMap != null){
            return  mGenresHashMap.get(filePath);
        }else {
            return  mContext.getResources().getString(R.string.unknown_genre);
        }
    }

    private  int getGenreSongsCount(String genre){
        if(mGenresSongCountHashMap != null){
            if(genre !=null){
                return mGenresSongCountHashMap.get(genre);
            }else {
                return 0;
            }
        }else{
            if(mGenresSongCountHashMap.get(mContext.getResources().getString(R.string.unknown_genre))!= null)
                return mGenresSongCountHashMap.get(mContext.getResources().getString(R.string.unknown_genre));
            else
                return  0;
        }
    }

    private  void buildGenresLibrary(){
        //Get a cursor of all genres in MediaStore
      //  Cursor generesCursor = mContext.getContentResolver()

        Cursor genersCursor = mContext.getContentResolver().query(MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI,
                new String[] {MediaStore.Audio.Genres._ID, MediaStore.Audio.Genres.NAME},
                null,
                null,
                null);
        //Iterate thru  all  generes in MediaStore
        for(genersCursor.moveToFirst(); !genersCursor.isAfterLast(); genersCursor.moveToNext()){
            String genreId = genersCursor.getString(0);
            String genreName = genersCursor.getString(1);
            Log.i(TAG, "genresId "+genreId+"genreName "+ genreName);
            if (genreName==null || genreName.isEmpty() ||
                    genreName.equals(" ") || genreName.equals("   ") ||
                    genreName.equals("    "))
                genreName = mContext.getResources().getString(R.string.unknown_genre);

            Cursor cursor = mContext.getContentResolver().query(makeGenreUri(genreId),
                                                                    new String[]{MediaStore.Audio.Media.DATA},
                                                                            mMediaStoreSelection,
                                                                            null,
                                                                            null);
            if(cursor != null){
                for(int i= 0; i< cursor.getCount() ; i++){
                    cursor.moveToPosition(i);
                    mGenresHashMap.put(cursor.getString(0), genreName);
                    mGenresSongCountHashMap.put(genreName, cursor.getCount());
                }
                cursor.close();
            }


        }
        if(genersCursor != null){
            genersCursor.close();
        }
    }

    private  Uri makeGenreUri(String genreId){
        String CONTENTDIR = MediaStore.Audio.Genres.Members.CONTENT_DIRECTORY;
        return  Uri.parse(new StringBuilder().append(MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI.toString())
                .append("/")
                .append(genreId)
                .append("/")
                .append(CONTENTDIR)
                .toString());
    }
    /**
     * ""
     *
     **/
    private Cursor getSongsFromMediaStore(){
        Cursor musicFolderCursor = mApp.getDBAccessHelper().getAllMusicFolderPaths();
        Cursor mediaStoreCursor = null;
        String sortOrder = null;
        String projection[]={
                MediaStore.Audio.Media.TITLE,
                MediaStore.Audio.Media.ARTIST,
                MediaStore.Audio.Media.ALBUM,
                MediaStore.Audio.Media.ALBUM_ID,
                MediaStore.Audio.Media.DURATION,
                MediaStore.Audio.Media.TRACK,
                MediaStore.Audio.Media.YEAR,
                MediaStore.Audio.Media.DATA,
                MediaStore.Audio.Media.DATE_ADDED,
                MediaStore.Audio.Media.DATE_MODIFIED,
                MediaStore.Audio.Media._ID,
                MediaStoreAccessHelper.ALBUM_ARTIST
        };
        if(musicFolderCursor == null || musicFolderCursor.getCount() <1){
            // TODO: 2016/5/29
        }else{
            mMediaStoreSelection = buildMusicFoldersSelection(musicFolderCursor);
            mediaStoreCursor = MediaStoreAccessHelper.getAllSongsWithSelection(mContext,
                    mMediaStoreSelection,
                    projection,
                    sortOrder);
            musicFolderCursor.close();
        }
        return  mediaStoreCursor;
    }

    /***
     *
     */
    private String buildMusicFoldersSelection(Cursor musicFoldersCursor){
        String mediaStoreSelection  = MediaStore.Audio.Media.IS_MUSIC+ "!=0 AND (";
        int folderPathColIndex = musicFoldersCursor.getColumnIndex(DBAccessHelper.FOLDER_PATH);
        int includeColIndex = musicFoldersCursor.getColumnIndex(DBAccessHelper.INCLUDE);

        for(int i =0; i<musicFoldersCursor.getCount(); i++){
            musicFoldersCursor.moveToPosition(i);
            boolean include = musicFoldersCursor.getInt(includeColIndex) > 0;
            String likeClause;
            if(include)
                likeClause = " LIKE";
            else
                likeClause = " NOT LIKE";

            if(i != 0 && !include)
                mediaStoreSelection +=" AND ";
            else if (i!=0 && include )
                mediaStoreSelection += " OR ";

            mediaStoreSelection += MediaStore.Audio.Media.DATA + likeClause
                    + "'%" + musicFoldersCursor.getString(folderPathColIndex)
                    +"/%'";
        }

        mediaStoreSelection +=")";

        Log.i(TAG, "mediaStoreSelection is :" + mediaStoreSelection);
        return  mediaStoreSelection;
    }

    /**
     * Builds a HashMap of all songs and their genres.
     */
    private void buildArtistsLibrary(){
        Cursor artistsCursor = mContext.getContentResolver().query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
                new String[]{MediaStore.Audio.Artists.ARTIST, MediaStore.Audio.Artists.NUMBER_OF_ALBUMS},
                null, null, null);
        if(artistsCursor == null){
            return;
        }

        for(int i= 0; i< artistsCursor.getCount(); i++){
            artistsCursor.moveToPosition(i);
            mAlbumsCountMap.put(artistsCursor.getString(0), artistsCursor
            .getInt(1));
        }
        artistsCursor.close();
    }

    private void buildAlbumsLibrary(){
        Cursor albumsCursor = mContext. getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
                new String[]{MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.ARTIST, MediaStore.Audio.Albums.NUMBER_OF_SONGS},
                null, null, null);

        if(albumsCursor == null){
            return;
        }

        for(int i=0; i < albumsCursor.getCount(); i++){
            albumsCursor.moveToPosition(i);
            mSongsCountMap.put(albumsCursor.getString(0)+albumsCursor.getString(1), albumsCursor.getInt(2));

        }
        albumsCursor.close();
    }

    private  void buildMediaStoreAlbumArtHash(){
        Cursor albumsCursor = mContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                new String[]{MediaStore.Audio.Media.ALBUM_ID},
                MediaStore.Audio.Media.IS_ALARM+"=1",
                null, null);
        final  Uri ART_CONTENT_URI = Uri.parse("content://media/external/audio/albumart");
        if(albumsCursor == null){
            return;
        }
        for (int i = 0; i< albumsCursor.getCount(); i++){
            albumsCursor.moveToPosition(i);
            Uri albumArtUri = ContentUris.withAppendedId(ART_CONTENT_URI, albumsCursor.getLong(0));
            mMediaStoreAlbumArtMap.put(albumsCursor.getString(0), albumArtUri);
        }
        albumsCursor.close();
    }

    /**
     * Convert millisseconds to hh:mm:ss format.
     *
     * @param milliseconds The input time in milliseconds to format.
     * @return The formatted time string.
     */
    private String convertMillisToMinsSecs(long milliseconds) {

        int secondsValue = (int) (milliseconds / 1000) % 60;
        int minutesValue = (int) ((milliseconds / (1000*60)) % 60);
        int hoursValue  = (int) ((milliseconds / (1000*60*60)) % 24);

        String seconds = "";
        String minutes = "";
        String hours = "";

        if (secondsValue < 10) {
            seconds = "0" + secondsValue;
        } else {
            seconds = "" + secondsValue;
        }

        minutes = "" + minutesValue;
        hours = "" + hoursValue;

        String output = "";
        if (hoursValue!=0) {
            minutes = "0" + minutesValue;
            hours = "" + hoursValue;
            output = hours + ":" + minutes + ":" + seconds;
        } else {
            minutes = "" + minutesValue;
            hours = "" + hoursValue;
            output = minutes + ":" + seconds;
        }

        return output;
    }


}

这个类很大,但做的事情却不多,就是将文件夹中的音乐文件从AudioStore里面读取信息,这里面有ContentProvider来提供。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
旅游社交小程序功能有管理员和用户。管理员有个人中心,用户管理,每日签到管理,景点推荐管理,景点分类管理,防疫查询管理,美食推荐管理,酒店推荐管理,周边推荐管理,分享圈管理,我的收藏管理,系统管理。用户可以在微信小程序上注册登录,进行每日签到,防疫查询,可以在分享圈里面进行分享自己想要分享的内容,查看和收藏景点以及美食的推荐等操作。因而具有一定的实用性。 本站后台采用Java的SSM框架进行后台管理开发,可以在浏览器上登录进行后台数据方面的管理,MySQL作为本地数据库,微信小程序用到了微信开发者工具,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得旅游社交小程序管理工作系统化、规范化。 管理员可以管理用户信息,可以对用户信息添加修改删除。管理员可以对景点推荐信息进行添加修改删除操作。管理员可以对分享圈信息进行添加,修改,删除操作。管理员可以对美食推荐信息进行添加,修改,删除操作。管理员可以对酒店推荐信息进行添加,修改,删除操作。管理员可以对周边推荐信息进行添加,修改,删除操作。 小程序用户是需要注册才可以进行登录的,登录后在首页可以查看相关信息,并且下面导航可以点击到其他功能模块。在小程序里点击我的,会出现关于我的界面,在这里可以修改个人信息,以及可以点击其他功能模块。用户想要把一些信息分享到分享圈的时候,可以点击新增,然后输入自己想要分享的信息就可以进行分享圈的操作。用户可以在景点推荐里面进行收藏和评论等操作。用户可以在美食推荐模块搜索和查看美食推荐的相关信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值