音乐播放器

上代码,功能简单,界面也比较简单
public class LocalMusicActivity extends Activity {
	private int[] _ids;
	private String[] _artists;
	private String[] _titles;
	private ListView listview;
	private ScanSDCardReceiver receiver = null;
	private static final int SCAN = Menu.FIRST;
	private static final int ABOUT = Menu.FIRST + 1;
	
	String[] media_info = new String[] { MediaStore.Audio.Media.TITLE,
			MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.ARTIST,
			MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DISPLAY_NAME,
			MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.ALBUM_ID };

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.localmusic);
		listview = (ListView) findViewById(R.id.music_list);
		listview.setOnItemClickListener(new MusicListOnClickListener());
		ShowMp3List();

	}

	

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == SCAN) {
			IntentFilter filter = new IntentFilter(
					Intent.ACTION_MEDIA_SCANNER_STARTED);
			filter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
			receiver = new ScanSDCardReceiver();
			filter.addDataScheme("file");
			registerReceiver(receiver, filter);
			sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
					Uri.parse("file://"
							+ Environment.getExternalStorageDirectory()
									.getAbsolutePath())));
		}
		return true;
	}
	

	public class ScanSDCardReceiver extends BroadcastReceiver {
		private AlertDialog.Builder  builder = null;
		private AlertDialog ad = null;
		@Override
		public void onReceive(Context context, Intent intent) {
			String action=intent.getAction();
			if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)){
				System.out.println("......");
				builder = new AlertDialog.Builder(context);
				builder.setMessage("绛夊緟涓�..");
				ad = builder.create();
				ad.show();
				
			}else if(Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)){
				ad.cancel();
			}

		}

	}
	
	private void ShowMp3List() {
		Cursor cursor = getContentResolver().query(
				MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, media_info, null,
				null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
		cursor.moveToFirst();
		_ids = new int[cursor.getCount()];
		_artists = new String[cursor.getCount()];
		_titles = new String[cursor.getCount()];
		for (int i = 0; i < cursor.getCount(); i++) {
			_ids[i] = cursor.getInt(3);
			_titles[i] = cursor.getString(0);
			_artists[i] = cursor.getString(2);
			cursor.moveToNext();
		}
		listview.setAdapter(new MusicListAdapter(this, cursor));
	}

	
	public class MusicListOnClickListener implements OnItemClickListener {

		public void onItemClick(AdapterView
   
    arg0, View arg1, int position,
				long id) {
			playMusic(position);

		}

	}


	public void playMusic(int position) {
		Intent intent = new Intent(LocalMusicActivity.this,
				PlayMusicActivity.class);
		intent.putExtra("_ids", _ids);
		intent.putExtra("_titles", _titles);
		intent.putExtra("_artists", _artists);
		intent.putExtra("position", position);
		startActivity(intent);
		finish();

	}




	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
           AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setTitle("退出软件");
			builder.setMessage("确实要退出程序吗?")
					.setPositiveButton("确定",
							new DialogInterface.OnClickListener() {

								public void onClick(DialogInterface dialog,
										int which) {
									Intent intent=new Intent(LocalMusicActivity.this, LocalMusicService.class);
									stopService(intent);
									finish();
									
								}
							}).setNegativeButton("取消", null).show();
			
			
		}
		
		return false;
		
	}
	
}
public class PlayMusicActivity extends Activity {
	private int[] _ids;
	private String _titles[] = null;
	private String _artists[] = null;
	private int position;
	private ImageButton playbtn = null;
	private ImageButton latestBtn = null;
	private ImageButton nextBtn = null;
	private TextView playtime = null;
	private TextView durationTime = null;
	private SeekBar seekbar = null;
	private int currentPosition;
	private int duration;
	private TextView name = null;
	private TextView artist = null;
	private TextView lrcText = null;
	private static final String MUSIC_CURRENT = "com.music.currentTime";
	private static final String MUSIC_DURATION = "com.music.duration";
	private static final String MUSIC_NEXT = "com.music.next";
	private static final String MUSIC_UPDATE = "com.music.update";
	private static final int PLAY = 1;
	private static final int PAUSE = 2;
	private static final int STOP = 3;// ֹͣ
	private static final int PROGRESS_CHANGE = 4;

	private static final int STATE_PLAY = 1;
	private static final int STATE_PAUSE = 2;
	private int flag;
	private Cursor cursor;
	private TreeMap
   
   
    
     lrc_map = new TreeMap
    
    
     
     ();
	private ImageView albumpic;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.playmusic);
		Intent intent = this.getIntent();
		Bundle bundle = intent.getExtras();
		_ids = bundle.getIntArray("_ids");
		position = bundle.getInt("position");
		_titles = bundle.getStringArray("_titles");
		_artists = bundle.getStringArray("_artists");
		name = (TextView) findViewById(R.id.name);
		artist = (TextView) findViewById(R.id.singer);
		lrcText = (TextView) findViewById(R.id.lrc);
		playtime = (TextView) findViewById(R.id.playtime);
		durationTime = (TextView) findViewById(R.id.duration);
		albumpic = (ImageView) findViewById(R.id.albumPic);
		ShowPlayBtn();
		ShowLastBtn();
		ShowNextBtn();
		ShowSeekBar();

	}
    
	private void ShowPlayBtn() {
		playbtn = (ImageButton) findViewById(R.id.playBtn);
		playbtn.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {
				switch (flag) {
				case STATE_PLAY:
					pause();
					break;

				case STATE_PAUSE:
					play();
					break;
				}

			}
		});

	}

	private void ShowSeekBar() {
		seekbar = (SeekBar) findViewById(R.id.seekbar);
		seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			
			public void onStopTrackingTouch(SeekBar seekBar) {
				play();

			}

			
			public void onStartTrackingTouch(SeekBar seekBar) {
				pause();

			}

			
			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				if (fromUser) {
					seekbar_change(progress);
				}

			}
		});

	}

	private void ShowNextBtn() {
		nextBtn = (ImageButton) findViewById(R.id.nextBtn);
		nextBtn.setOnClickListener(new OnClickListener() {

			
			public void onClick(View v) {
				nextOne();

			}
		});

	}

	private void ShowLastBtn() {
		latestBtn = (ImageButton) findViewById(R.id.lastBtn);
		latestBtn.setOnClickListener(new View.OnClickListener() {

			
			public void onClick(View v) {
				latestOne();
			}
		});

	}

	@Override
	protected void onStart() {
		super.onStart();
		setup();
		play();
	}

	
	protected void onStop() {
		super.onStop();
		unregisterReceiver(musicreceiver);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			Intent intent = new Intent(PlayMusicActivity.this,
					LocalMusicActivity.class);
			startActivity(intent);
			finish();
		}
		return true;
	}


	protected void play() {
		flag = PLAY;
		playbtn.setImageResource(R.drawable.pause_button);
		Intent intent = new Intent(this,LocalMusicService.class);
//		intent.setAction("com.example.music.LocalMusicService");
		intent.putExtra("op", PLAY);
		startService(intent);

	}


	protected void pause() {
		flag = PAUSE;
		playbtn.setImageResource(R.drawable.play_button);
		Intent intent = new Intent(this,LocalMusicService.class);
//		intent.setAction("com.example.music.LocalMusicService");
		intent.putExtra("op", PAUSE);
		startService(intent);

	}


	protected void latestOne() {
		if (position == 0) {
			position = _ids.length - 1;
		} else if (position > 0) {
			position--;
		}
		stop();
		setup();
		play();

	}


	private void stop() {
		Intent intent = new Intent(this,LocalMusicService.class);
//		intent.setAction("com.example.music.LocalMusicService");
		intent.putExtra("op", STOP);
		startService(intent);
	}


	protected void nextOne() {
		if (position == _ids.length - 1) {
			position = 0;
		} else if (position < _ids.length - 1) {
			position++;
		}
		stop();
		
		setup();
		play();

	}


	

	protected void seekbar_change(int progress) {
		Intent intent = new Intent(this,LocalMusicService.class);
//		intent.setAction("com.example.music.LocalMusicService");
		intent.putExtra("op", PROGRESS_CHANGE);
		intent.putExtra("progress", progress);
		startService(intent);

	}


	private void setup() {
		loadclip();
		init();
		ReadSDLrc();

	}


	private void ReadSDLrc() {
		cursor = getContentResolver().query(
				MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
				new String[] { MediaStore.Audio.Media.TITLE,
						MediaStore.Audio.Media.DURATION,
						MediaStore.Audio.Media.ARTIST,
						MediaStore.Audio.Media.ALBUM,
						MediaStore.Audio.Media.DISPLAY_NAME,
						MediaStore.Audio.Media.ALBUM_ID }, "_id=?",
				new String[] { _ids[position] + "" }, null);
		cursor.moveToFirst();
		String name = cursor.getString(4);
		read("/sdcard/" + name.substring(0, name.indexOf(".")) + ".lrc");
		System.out.println(cursor.getString(4));

	}


	private void init() {
		IntentFilter filter = new IntentFilter();
		filter.addAction(MUSIC_CURRENT);
		filter.addAction(MUSIC_DURATION);
		filter.addAction(MUSIC_NEXT);
		filter.addAction(MUSIC_UPDATE);
		registerReceiver(musicreceiver, filter);

	}


	private void loadclip() {
		seekbar.setProgress(0);
		int pos = _ids[position];
		name.setText(_titles[position]);
		artist.setText(_artists[position]);
		Intent intent = new Intent(this,LocalMusicService.class);
		intent.putExtra("_id", pos);
		intent.putExtra("_titles", _titles);
		intent.putExtra("position", position);
//		intent.setAction("com.example.music.LocalMusicService");
		startService(intent);

	}


	private BroadcastReceiver musicreceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (action.equals(MUSIC_CURRENT)) {
				currentPosition = intent.getExtras().getInt("currentTime");
				playtime.setText(toTime(currentPosition));
				seekbar.setProgress(currentPosition);
				Iterator
     
     
      
       iterator = lrc_map.keySet().iterator();
				while (iterator.hasNext()) {
					Object o = iterator.next();
					LRCbean val = lrc_map.get(o);
					if (val != null) {

						if (currentPosition > val.getBeginTime()
								&& currentPosition < val.getBeginTime()
										+ val.getLineTime()) {
							lrcText.setText(val.getLrcBody());
							break;
						}
					}
				}

			} else if (action.equals(MUSIC_DURATION)) {
				duration = intent.getExtras().getInt("duration");
				seekbar.setMax(duration);
				durationTime.setText(toTime(duration));
			} else if (action.equals(MUSIC_NEXT)) {
				System.out.println("中国好歌曲");
				nextOne();
			} else if (action.equals(MUSIC_UPDATE)) {
				position = intent.getExtras().getInt("position");
				setup();
			}

		}
	};

	
	public String toTime(int time) {

		time /= 1000;
		int minute = time / 60;
		int second = time % 60;
		minute %= 60;
		return String.format("%02d:%02d", minute, second);
	}

	
	private void read(String path) {
		lrc_map.clear();
		TreeMap
      
      
       
        lrc_read = new TreeMap
       
       
         (); String data = ""; BufferedReader br = null; File file = new File(path); System.out.println(path); if (!file.exists()) { lrcText.setText("加载中..."); return; } FileInputStream stream = null; try { stream = new FileInputStream(file); br = new BufferedReader(new InputStreamReader(stream, "UTF-8")); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } try { while ((data = br.readLine()) != null) { if (data.length() > 6) { if (data.charAt(3) == ':' && data.charAt(6) == '.') { data = data.replace("[", ""); data = data.replace("]", "@"); data = data.replace(".", ":"); String lrc[] = data.split("@"); String lrcContent = null; if (lrc.length == 2) { lrcContent = lrc[lrc.length - 1]; } else { lrcContent = ""; } for (int i = 0; i < lrc.length - 1; i++) { String lrcTime[] = lrc[0].split(":"); int m = Integer.parseInt(lrcTime[0]); int s = Integer.parseInt(lrcTime[1]); int ms = Integer.parseInt(lrcTime[2]); int begintime = (m * 60 + s) * 1000 + ms; LRCbean lrcbean = new LRCbean(); lrcbean.setBeginTime(begintime); lrcbean.setLrcBody(lrcContent); lrc_read.put(begintime, lrcbean); } } } } stream.close(); } catch (IOException e) { e.printStackTrace(); } lrc_map.clear(); data = ""; Iterator 
        
          iterator = lrc_read.keySet().iterator(); LRCbean oldval = null; int i = 0; while (iterator.hasNext()) { Object ob = iterator.next(); LRCbean val = lrc_read.get(ob); if (oldval == null) { oldval = val; } else { LRCbean item1 = new LRCbean(); item1 = oldval; item1.setLineTime(val.getBeginTime() - oldval.getBeginTime()); lrc_map.put(new Integer(i), item1); i++; oldval = val; } } } public static Bitmap getArtwork(Context context, long song_id, long album_id, boolean allowdefault) { if (album_id < 0) { if (song_id >= 0) { Bitmap bm = getArtworkFromFile(context, song_id, -1); if (bm != null) { return bm; } } if (allowdefault) { return getDefaultArtwork(context); } return null; } ContentResolver res = context.getContentResolver(); Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id); if (uri != null) { InputStream in = null; try { in = res.openInputStream(uri); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 1; options.inJustDecodeBounds = true; BitmapFactory.decodeStream(in, null, options); options.inSampleSize = computeSampleSize(options, 200); options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; in = res.openInputStream(uri); return BitmapFactory.decodeStream(in, null, sBitmapOptions); } catch (FileNotFoundException ex) { Bitmap bm = getArtworkFromFile(context, song_id, album_id); if (bm != null) { if (bm.getConfig() == null) { bm = bm.copy(Bitmap.Config.RGB_565, false); if (bm == null && allowdefault) { return getDefaultArtwork(context); } } } else if (allowdefault) { bm = getDefaultArtwork(context); } return bm; } finally { try { if (in != null) { in.close(); } } catch (IOException ex) { } } } return null; } static int computeSampleSize(BitmapFactory.Options options, int target) { int w = options.outWidth; int h = options.outHeight; int candidateW = w / target; int candidateH = h / target; int candidate = Math.max(candidateW, candidateH); if (candidate == 0) return 1; if (candidate > 1) { if ((w > target) && (w / candidate) < target) candidate -= 1; } if (candidate > 1) { if ((h > target) && (h / candidate) < target) candidate -= 1; } Log.v("ADW", "candidate:" + candidate); return candidate; } private static Bitmap getArtworkFromFile(Context context, long songid, long albumid) { Bitmap bm = null; if (albumid < 0 && songid < 0) { throw new IllegalArgumentException( "Must specify an album or a song id"); } try { BitmapFactory.Options options = new BitmapFactory.Options(); FileDescriptor fd = null; if (albumid < 0) { Uri uri = Uri.parse("content://media/external/audio/media/" + songid + "/albumart"); ParcelFileDescriptor pfd = context.getContentResolver() .openFileDescriptor(uri, "r"); if (pfd != null) { fd = pfd.getFileDescriptor(); } } else { Uri uri = ContentUris.withAppendedId(sArtworkUri, albumid); ParcelFileDescriptor pfd = context.getContentResolver() .openFileDescriptor(uri, "r"); if (pfd != null) { fd = pfd.getFileDescriptor(); } } options.inSampleSize = 1; options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fd, null, options); options.inSampleSize = 200; options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; bm = BitmapFactory.decodeFileDescriptor(fd, null, options); } catch (FileNotFoundException ex) { } if (bm != null) { } return bm; } private static Bitmap getDefaultArtwork(Context context) { BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inPreferredConfig = Bitmap.Config.RGB_565; return BitmapFactory.decodeStream(context.getResources() .openRawResource(R.drawable.music), null, opts); } private static final Uri sArtworkUri = Uri .parse("content://media/external/audio/albumart"); private static final BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options(); } public class MusicListAdapter extends BaseAdapter { private Context mcontext; private Cursor mcursor; public MusicListAdapter(Context context, Cursor cursor) { mcontext = context; mcursor = cursor; } public int getCount() { return mcursor.getCount(); } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { convertView = LayoutInflater.from(mcontext).inflate( R.layout.musiclist_item, null); mcursor.moveToPosition(position); // ImageView images = (ImageView) convertView.findViewById(R.id.listitem); // images.setImageResource(R.drawable.music); TextView music_title = (TextView) convertView .findViewById(R.id.musicname); music_title.setText(mcursor.getString(0)); TextView music_singer = (TextView) convertView .findViewById(R.id.singer); music_singer.setText(mcursor.getString(2)); TextView music_time = (TextView) convertView.findViewById(R.id.time); music_time.setText(toTime(mcursor.getInt(1))); return convertView; } public String toTime(int time) { time /= 1000; int minute = time / 60; int second = time % 60; minute %= 60; return String.format("%02d:%02d", minute, second); } } package com.example.music; import java.io.IOException; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnPreparedListener; import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.provider.MediaStore; /** * 通过播放界面发送的数据,由服务接收并对音乐进行操作。如播放,暂停,停止等等。如果要显示艺术家,歌名什么的则需要传递数据 */ public class LocalMusicService extends Service implements OnCompletionListener { private static final int PLAYING = 1;// 定义该怎么对音乐操作的常量,如播放是1 private static final int PAUSE = 2;// 暂停事件是2 private static final int STOP = 3;// 停止事件是3 private static final int PROGRESS_CHANGE = 4;// 进度条改变事件设为4 private static final String MUSIC_CURRENT = "com.music.currentTime"; private static final String MUSIC_DURATION = "com.music.duration"; private static final String MUSIC_NEXT = "com.music.next"; private MediaPlayer mp;// MediaPlayer对象 private Handler handler;// handler对象 private Uri uri = null;// 路径地址 private int id = 10000; private int currentTime;// 当前时间 private int duration;// 总时间 @Override public void onCreate() { if (mp != null) { mp.reset(); mp.release(); } mp = new MediaPlayer();// 实例化MediaPlayer对象 mp.setOnCompletionListener(this);// 设置下一首的监听 } @Override public void onDestroy() { if (mp != null) { stop(); } if (handler != null) { handler.removeMessages(1); handler = null; } } /** * 开启服务的方法 */ @Override public void onStart(Intent intent, int startId) { // 播放,暂停,前,后一首 int _id = intent.getIntExtra("_id", -1);// 获取ID的数据 if (_id != -1) { if (id != _id) { id = _id; uri = Uri.withAppendedPath( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, "" + _id); try { mp.reset();// 媒体对象重置 mp.setDataSource(this, uri);// 设置媒体资源 } catch (Exception e) { e.printStackTrace(); } } } setup(); init(); /** * 开始播放/暂停、停止 */ int op = intent.getIntExtra("op", -1); if (op != -1) { switch (op) { case PLAYING: play(); break; case PAUSE: pause(); break; case STOP: stop(); break; case PROGRESS_CHANGE: int progress = intent.getExtras().getInt("progress"); mp.seekTo(progress); break; } } } // 播放音乐 private void play() { if (mp != null) { mp.start(); } } // 暂停音乐 private void pause() { if (mp != null) { mp.stop(); } System.out.println("音乐已经停止"); } // 停止音乐 private void stop() { if (mp != null) { mp.stop(); try { mp.prepare(); mp.seekTo(0); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } handler.removeMessages(1); } } /** * 初始化服务 */ private void init() { final Intent intent = new Intent(); intent.setAction(MUSIC_CURRENT); handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { currentTime = mp.getCurrentPosition(); intent.putExtra("currentTime", currentTime); sendBroadcast(intent); } handler.sendEmptyMessageDelayed(1, 600);// 发送空消息持续时间 } }; } /** * 准备工作 */ private void setup() { final Intent intent = new Intent(); intent.setAction(MUSIC_DURATION); try { if (!mp.isPlaying()) { mp.prepare(); mp.start(); } else if (!mp.isPlaying()) { mp.stop(); } mp.setOnPreparedListener(new OnPreparedListener() { public void onPrepared(MediaPlayer mp) { handler.sendEmptyMessage(1); } }); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } duration = mp.getDuration();// 获取媒体的总时间 intent.putExtra("duration", duration); sendBroadcast(intent);// 将Intent对象信息用广播发送出去 } public void onCompletion(MediaPlayer arg0) { Intent intent = new Intent(); intent.setAction(MUSIC_NEXT); sendBroadcast(intent); System.out.println("音乐播放下一首"); } @Override public IBinder onBind(Intent arg0) { return null; } } package com.example.music; public class LRCbean { private int beginTime = 0; public int getBeginTime() { return beginTime; } public void setBeginTime(int beginTime) { this.beginTime = beginTime; } public int getLineTime() { return lineTime; } public void setLineTime(int lineTime) { this.lineTime = lineTime; } public String getLrcBody() { return lrcBody; } public void setLrcBody(String lrcBody) { this.lrcBody = lrcBody; } private int lineTime = 0; private String lrcBody = null; } 
          
          
           
           
          
          
          
           
           
           
           
           
           
           
           
           
            
            
            
           
          
          
          
           
           
            
            
           
           
          
         
       
      
      
     
     
    
    
   
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值