編輯:關於Android編程
Activity代碼
package com.siyehuazhilian.musicplay; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; import android.graphics.Color; import android.os.Bundle; import android.provider.MediaStore; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ImageButton; import android.widget.ListView; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.SimpleAdapter; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener { // ListView private ListView listView; // 適配器 private SimpleAdapter adapter; // 數據源 private ArrayList> list; // 當前播放的曲目 private int currentPositionMusic = -1; // 上一首 private ImageButton lastImageButton; // 播放 private ImageButton playImageButton; // 下一首 private ImageButton nextImageButton; // 循環 private ImageButton loopImageButton; // 播放進度 private SeekBar playSeekBar; // 當前播放曲目 private TextView currentPlayingSong; // 是否是第一次進來 private boolean ifFirstIn = true; private Intent intent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.listview); lastImageButton = (ImageButton) findViewById(R.id.imagebutton_previous); playImageButton = (ImageButton) findViewById(R.id.imagebutton_play); nextImageButton = (ImageButton) findViewById(R.id.imagebutton_next); loopImageButton = (ImageButton) findViewById(R.id.imagebutton_loops); playSeekBar = (SeekBar) findViewById(R.id.seekbar_play); currentPlayingSong = (TextView) findViewById(R.id.textview_songinformation); list = new ArrayList >(); adapter = new SimpleAdapter(this, list, R.layout.list_item, new String[] { "title" }, new int[] { R.id.textview_item }); listView.setAdapter(adapter); // 為listView設置監聽器 listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView> arg0, View arg1, int position, long arg3) { try { currentPositionMusic = position; playMusic(); } catch (Exception e) { e.printStackTrace(); } } }); lastImageButton.setOnClickListener(this); playImageButton.setOnClickListener(this); nextImageButton.setOnClickListener(this); loopImageButton.setOnClickListener(this); playSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { // 改變進度條 intent = new Intent("changed"); intent.putExtra("seekbarprogress", progress); startService(intent); } } }); } private void playMusic() { // 啟動播放音樂的服務 intent = new Intent("play"); intent.putExtra("uri", ((HashMap ) list .get(currentPositionMusic)).get("path")); intent.putExtra("title", ((HashMap ) list .get(currentPositionMusic)).get("title")); startService(intent); // 把圖片改為播放的圖片 playImageButton.setImageResource(R.drawable.play); // 同時更改SeekBar的進度,因為進度是不斷變化的,所以需要一個子線程來刷新下 // playSeekBar.setMax(mp.getDuration()); // 設置當前播放曲目信息 currentPlayingSong.setTextColor(Color.GREEN); currentPlayingSong.setText(list.get(currentPositionMusic).get("title")); } @Override protected void onResume() { super.onResume(); // 得到所有音頻 if (ifFirstIn) { ifFirstIn = false; scanMusic(); } // 動態注冊廣播 IntentFilter filter = new IntentFilter(); filter.addAction("seekbarmaxprogress"); filter.addAction("seekbarprogress"); filter.addAction("playNextSong"); filter.addAction("pause"); filter.addAction("setplay"); filter.addAction("stoploop"); filter.addAction("startloop"); registerReceiver(broadcastReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); // 關閉通知 intent = new Intent("stopnotification"); startService(intent); // 停止服務 stopService(intent); // 取消廣播的注冊 unregisterReceiver(broadcastReceiver); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("你確定要退出嗎?"); builder.setPositiveButton("確定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); builder.show(); return true; } else { return super.onKeyDown(keyCode, event); } } /** * 得多所有的音頻 */ private void scanMusic() { // 置空list集合中的所有元素,放置反復啟動導致的數據重復,其實這個部分是因為每次進來都會重新獲得焦點,執行onResume造成的 // 這個修改雖然可以,但是每次進來都有重新加載,增加了手機的符合,所以可以設置一個標志,只有在第一進來的時候才會加載數據 // list.clear(); new Thread() { public void run() { Cursor cursor = getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); while (cursor.moveToNext()) { String title = cursor .getString(cursor .getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); String path = cursor .getString(cursor .getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)); String size = cursor .getString(cursor .getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)); if (Long.parseLong(size) > 1024 * 1024) { HashMap hashMap1 = new HashMap (); hashMap1.put("title", title); hashMap1.put("path", path); list.add(hashMap1); } } cursor.close(); }; }.start(); } /** * 監聽 */ @Override public void onClick(View v) { switch (v.getId()) { case R.id.imagebutton_previous: playLastSong(); break; case R.id.imagebutton_play: intent = new Intent("clickplay"); startService(intent); break; case R.id.imagebutton_next: playNextSong(); break; case R.id.imagebutton_loops: intent = new Intent("loops"); startService(intent); break; default: break; } } /** * 播放下一曲 */ private void playNextSong() { // 只有當有音樂在播放的時候才可以點擊下一首 if (currentPositionMusic != -1) { // 如果當前歌曲為最後一首,就播放第一首歌曲 if (currentPositionMusic == list.size() - 1) { // 設置當前歌曲為第一首 currentPositionMusic = 0; try { // 播放第一首歌曲 playMusic(); } catch (Exception e) { e.printStackTrace(); } }// 否則就播放下一首歌曲 else { // 設置當前歌曲為下一首 currentPositionMusic++; try { // 播放下一首歌曲 playMusic(); } catch (Exception e) { e.printStackTrace(); } } } } /** * 播放上一曲 */ private void playLastSong() { // 只有當有音樂在播放的時候才可以點擊上一首 if (currentPositionMusic != -1) { // 如果當前歌曲為第一首,就播放最後一首歌曲 if (currentPositionMusic == 0) { // 設置當前歌曲為最後一首 currentPositionMusic = list.size() - 1; try { // 播放最後一首歌曲 playMusic(); } catch (Exception e) { e.printStackTrace(); } }// 否則就播放上一首歌曲 else { // 設置當前歌曲為前一首 currentPositionMusic--; try { // 播放前一首歌曲 playMusic(); } catch (Exception e) { e.printStackTrace(); } } } } /** * 廣播對象,動態注冊,用來接收從Service傳過來的消息,根據不同的消息做不同的事情 */ private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("seekbarmaxprogress")) { playSeekBar.setMax(intent .getIntExtra("seekbarmaxprogress", 100)); } else if (intent.getAction().equals("seekbarprogress")) { playSeekBar.setProgress(intent .getIntExtra("seekbarprogress", 0)); } else if (intent.getAction().equals("playNextSong")) { playNextSong(); } else if (intent.getAction().equals("pause")) { // 還要把圖片改為暫停的圖片 playImageButton.setImageResource(R.drawable.pause); } else if (intent.getAction().equals("setplay")) { // 把圖片設置成播放的圖片 playImageButton.setImageResource(R.drawable.play); } else if (intent.getAction().equals("stoploop")) { // 還要把圖片改為不循環的圖片 loopImageButton.setImageResource(R.drawable.loop_false); } else if (intent.getAction().equals("startloop")) { // 把圖片設置成循環播放的圖片 loopImageButton.setImageResource(R.drawable.loop_true); } } }; }
Service代碼
package com.siyehuazhilian.service; import java.util.HashMap; import com.siyehuazhilian.musicplay.MainActivity; import com.siyehuazhilian.musicplay.R; import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnPreparedListener; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.widget.Toast; public class PlayMusicService extends Service { private MediaPlayer mediaPlayer; // 設置Seebar最大進度 private static final int SET_SEEKBAR_MAX = 3; // 刷新SeekBar進度 private static final int UPDATE_PROGRESS = 1; // 加載數據 private static final int LOADING_DATA = 2; // 通知管理 private NotificationManager notificationManager; // 通知 private Notification notification; private Intent intent; @Override public IBinder onBind(Intent intent) { return null; } @SuppressLint("ShowToast") @Override public int onStartCommand(Intent intent, int flags, int startId) { notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (intent.getAction().equals("play")) {// 如果是播放Action,就播放音樂 try { Toast.makeText(getApplicationContext(), "開始播放", 1000).show(); playMusic(intent.getStringExtra("uri")); showNotification(intent.getStringExtra("title")); } catch (Exception e) { e.printStackTrace(); } } else if (intent.getAction().equals("changed")) {// 如果是拖動的Action,就跳至拖動的進度 if (mediaPlayer != null) { mediaPlayer.seekTo(intent.getIntExtra("seekbarprogress", 0)); } } else if (intent.getAction().equals("clickplay")) {// 如果是播放/暫停Action,就執行相應的播放或者暫停 Toast.makeText(getApplicationContext(), "播放被點擊了", 1000).show(); if (mediaPlayer != null) { // 如果音樂播放器正在播放 if (mediaPlayer.isPlaying()) { // 那就暫停它 mediaPlayer.pause(); // 發送暫停廣播給程序 this.intent = new Intent("pause"); sendBroadcast(this.intent); } else { // 否則就播放它 mediaPlayer.start(); // 發送播放廣播 this.intent = new Intent("setplay"); sendBroadcast(this.intent); } } } else if (intent.getAction().equals("loops")) {// 如果是loop循環Action,就把歌曲設置為循環播放 Toast.makeText(getApplicationContext(), "循環被點擊了", 1000).show(); if (mediaPlayer != null) { // 如果音樂播放器正在循環 if (mediaPlayer.isLooping()) { // 那就終止循環它 mediaPlayer.setLooping(false); // 發送終止循環廣播 this.intent = new Intent("stoploop"); sendBroadcast(this.intent); } else { // 否則就循環播放它 mediaPlayer.setLooping(true); // 發送開始循環廣播 this.intent = new Intent("startloop"); sendBroadcast(this.intent); } } } else if (intent.getAction().equals("stopnotification")) { notificationManager.cancelAll(); } return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); handler.removeMessages(UPDATE_PROGRESS); mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } /** * 播放音樂 * * @param path * @throws Exception */ private void playMusic(String path) throws Exception { if (mediaPlayer == null) { // 新建一個mediaPalyer對象 mediaPlayer = new MediaPlayer(); } // 使mediaPalyer進入Idle狀態 mediaPlayer.reset(); // 設置數據源,使mediaPlayer進入Intialized狀態 mediaPlayer.setDataSource(path); // 准備播放 mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { // 開始播放音樂 mp.start(); handler.sendEmptyMessage(SET_SEEKBAR_MAX); handler.sendEmptyMessage(UPDATE_PROGRESS); } }); mediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if (mp.isLooping()) { mp.start(); } else { intent = new Intent("playNextSong"); sendBroadcast(intent); } } }); } private Handler handler = new Handler() { @SuppressLint("HandlerLeak") public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_PROGRESS: // 設置最大當前播放進度 intent = new Intent("seekbarprogress"); intent.putExtra("seekbarprogress", mediaPlayer.getCurrentPosition()); sendBroadcast(intent); // 需要隨著播放設置 handler.sendEmptyMessageDelayed(UPDATE_PROGRESS, 1000); break; case LOADING_DATA: // adapter.notifyDataSetInvalidated(); break; case SET_SEEKBAR_MAX: intent = new Intent("seekbarmaxprogress"); intent.putExtra("seekbarmaxprogress", mediaPlayer.getDuration()); sendBroadcast(intent); // 因為進度條只需要設置一次就夠了,所以不需要反復發送Message; break; default: break; } }; }; /** * 顯示通知 * */ private void showNotification(String title) { notification = new Notification(R.drawable.app_icon, "百度音樂", System.currentTimeMillis()); notification.flags |= Notification.FLAG_NO_CLEAR; notification.flags |= Notification.FLAG_ONGOING_EVENT; Intent intent = new Intent(this, MainActivity.class); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); notification.setLatestEventInfo(this, "正在播放", title, pendingIntent); notificationManager.notify(1, notification); } }
AndroidManifest.xml代碼
上一篇講了內存緩存,這一篇就緊接著講一下磁盤緩存DiskLruCache.官方文檔:https://developer.android.com/training/disp
在Android系統中提供了多種存儲技術.通過這些存儲技術可以將數據存儲在各種存儲介質上.比如sharedpreferences可以將數據保存著應用軟件的私有存儲區,這些
最近,由於正在做的一個應用中要用到側滑菜單,所以通過查資料看視頻,學習了一下自定義View,實現一個類似於QQ的側滑菜單,順便還將其封裝為自定義組件,可以實現類似QQ的側
github地址:https://github.com/JimiSmith/PinnedHeaderListView 關於實現類似聯系人列表,組的頭部總是懸浮在list