12/08/2018, 13:13

Hướng dẫn làm một app nghe nhạc online và offline đơn giản

Mình xin hướng dẫn các bạn một bài viết về một ứng dụng nghe nhạc online đơn giản . Để làm được ứng dụng này ngoài các vấn đề cơ bản về android ví dụ như layout, listview, gridview ... Bạn cần biết thêm về service , widget, media player, broadcast , notifications . Khi xây dựng một ứng dụng bạn ...

  • Mình xin hướng dẫn các bạn một bài viết về một ứng dụng nghe nhạc online đơn giản . Để làm được ứng dụng này ngoài các vấn đề cơ bản về android ví dụ như layout, listview, gridview ... Bạn cần biết thêm về service , widget, media player, broadcast , notifications .
  • Khi xây dựng một ứng dụng bạn cần phân tích ứng dụng mình cần phát triển như thiết kế hệ thống , giao diện người dùng ... và biết sự cần thiết tương tác người dùng và ứng dụng như yếu tố cần thiết ứng dụng cho người dùng , các điểm cần thiết người dùng có thể sử dụng nhất ...
  • Mình không thể nói chi tiết về mặt phân tích hệ thống và sự tương tác về mặt người dùng . Sau đây mình sẽ hướng dẫn ở phần I này về thiết kế giao diện về một ứng dụng nghe nhạc online cũng như offline khá đơn giản .
  • Mình xin nói qua các kiến thức cơ bản về service , media player , mediaplayer broadcast , notification .
  • Bạn có thể tham khảo ở bài viết trước của mình đã post link : "linktext": https://viblo.asia/kieunn/posts/AQrMJV9wM40E
  • Android cung cấp nhiều cách để phát lại quyền điều khiển file audio.video và âm thanh. Một trong cách này là gọi lớp MediaPlayer. Android đang cung cấp cho lớp MediaPlayer quyền truy cập được xây dựng trong các dịch vụ MediaPlayer như chơi nhạc, video,… Để sử dụng MediaPlayer, chúng ta phải gọi phương thức Create() của lớp này. Phương thức này trả về một thể hiện của lớp MediaPlayer khi lập trình android. Cú pháp như sau:

    MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.song);

  • Tham số thứ hai là tên của một bài hát mà bạn muốn nghe. Bạn phải tạo một tập tin mới trong dự án của bạn với một tên thật và đăt file nhạc trong nó.

  • Khi bạn đã tạo một đối tượng MediaPlayer, bạn có thể gọi phương thức để bắt đầu hoặc ngừng nhạc. Những phương thức được kiệt kê dưới đây: mediaPlayer.start(); mediaPlayer.pause();

  • Trong khi gọi phương thức start(), nhạc sẽ được chơi từ khi bắt đầu. Nếu phương thức này gọi lại sau phương thức pause(), nhạc sẽ bắt đầu chơi từ nơi mà nó tới và không từ đầu.

  • Để bắt đầu âm nhạc ngay từ đầu, bạn phải gọi phương thức reset(). Cú pháp của nó được đưa ra dưới đây. mediaPlayer.reset();

  • Ngoài sự bắt đầu và tạm dừng phương pháp, có những phương thức khác được cung cấp bởi lớp này để đối phó tốt hơn với các file audio/video. Những phương thức này được liệt kê dưới đây – **Phương thức và mô tả.

1.isPlaying()

  • Phương thức này chỉ trả về true/false cho biết bài hát được chơi hay không

2.seekTo (position)

  • Phương thức này có một số nguyên, và di chuyển bài hát đến giây phút đặc biệt

3.getCurrentDuration()

  • Phương thức này trả về vị trí hiện tại của bài hát trong mili giây

4.getDuration()

  • Phương thức này trả về tổng thời gian của bài hát trong mili giây

5.reset()

  • Phương thức này reset máy nghe nhạc phương tiện truyền thông

6.release()

  • Phương thức này phát hành bất kỳ tài nguyên gắn với đối tượng MediaPlayer

7.setVolume(float leftVolume, float rightVolume)

  • Phương thức này đặt âm lượng lên xuống cho cầu thủ này

8.setDataSource(FileDescriptor fd)

  • Phương thức này tập hợp các nguồn dữ liệu của tập tin âm thanh / video

9.selectTrack(int index)

  • Phương thức này có một số nguyên, và chọn bài hát từ danh sách trên chỉ số đặc biệt

10.getTrackInfo()

  • Phương thức này trả về một mảng các thông tin theo dõi

Intent.

Khái niệm về Intent:

Intent Là một miêu tả về một hoạt động cần được thực hiện. Còn nói một cách đơn giản và dễ hiểu hơn, Intent là một cơ cấu cho phép truyền thông điệp giữa các thành phần của 1 ứng dụng và giữa các ứng dụng với nhau.

Các thuộc tính của Intent:

Action:

  • Là hành động được thực hiện, vd : ACTION_VIEW, ACTION_MAIN

Data:

  • Là dữ liệu sẽ được xử lý trong action, thường được diễn tả là một Uri (Uniform Resource Identifier, tham khảo http://en.wikipedia.org/wiki/Uniform…rce_Identifier để hiểu rõ thêm chi tiết).

VD:

ACTION_VIEW content://contacts/people/1

  • Hiển thị thông tin về người với mã danh 1

ACTION_DIAL content://contacts/people/1

  • Hiển thị màn hình gọi đến người với mã danh 1

ACTION_DIAL tel:123

  • Hiển thị màn hình gọi với số gọi là 123

Ngoài ra còn có 1 số thuộc tính mà ta có thể bổ sung vào Intent:

Category:

  • Bổ sung thêm thông tin cho action của Intent.

VD:

CATEGORY_LAUNCHER

  • Thông báo sẽ thêm vào Launcher như là một ứng dụng top-level

Type:

  • Chỉ rõ kiểu của data

Component:

  • Chỉ rõ thành phần sẽ nhận và xử lý intent. Khi thuộc tính này được xác định thì các thuộc tính khác sẽ trở thành thuộc tính phụ.

Extras:

  • mang theo đối tượng Bundle chứa các giá trị bổ sung.

VD:

  • ACTION_MAIN và CATEGORY_HOME: trở về màn hình Home của Android (khi bấm nút Home của di động)

Phân loại Intent:

  • Intent được chia làm 2 loại:

    Explicit Intents:

  • Intent đã được xác định thuộc tính component, nghĩa là đã chỉ rõ thành phần sẽ nhận và xử lý intent. Thông thường intent dạng này sẽ không bổ sung thêm các thuộc tính khác như action, data. Explicit Intent thương được sử dụng để khởi chạy các activity trong cùng 1 ứng dụng.

    Implicit Intents:

  • Intent không chỉ rõ component xử lý, thay vào đó nó bổ sung thông tin trong các thuộc tính. Khi intent được gửi đi, hệ thống sẽ dựa vào những thông tin này để quyết định component nào thích hợp nhất để xử lý nó.

VD:

ACTION_DIAL

  • tel:123 thông thường sẽ được hệ thống giao cho activity Phone Dialer mặc định của Android xử lý. Một số action thường sử dụng trong Intent:

ACTION_ANSWER

  • Mở Activity để xử lý cuộc gọi tới, thường là Phone Dialer của Android

ACTION_CALL

  • Mở 1 Phone Dialer (mặc định là PD của Android) và ngay lập tức thực hiện cuộc gọi dựa vào thông tin trong data URI

ACTION_DELETE

  • Mở Activity cho phép xóa dữ liệu mà địa chỉ của nó chứa trong data URI

ACTION_DIAL

  • Mở 1 Phone Dialer (mặc định là PD của Android) và điền thông tin lấy từ địa chỉ chứa trong data URI

ACTION_EDIT

  • Mở 1 Activity cho phép chỉnh sửa dữ liệu mà địa chỉ lấy từ data URI

ACTION_SEND

  • Mở 1 Activity cho phép gửi dữ liệu lấy từ data URI, kiểu của dữ liệu xác định trong thuộc tính type

ACTION_SENDTO

  • Mở 1 Activity cho phép gửi thông điệp tới địa chỉ lấy từ data URI

ACTION_VIEW

  • Action thông dụng nhất, khởi chạy activity thích hợp để hiển thị dữ liệu trong data URI

ACTION_MAIN

  • Sử dụng để khởi chạy 1 Activity
  • Broadcast Receivers được hiểu đơn giản là nhận và xử lý các thông điệp được phát ra từ các ứng dụng khác, từ hệ thống, hoặc từ các services chạy ngầm bên trong ứng dụng gửi lên để cập nhật giao diện. Trong Broadcast Receiver có sử dụng đối tượng Intent Filter, nó giống như bộ lọc, giúp cho Receiver nhận được thông điệp và chọn đúng tác vụ để thực thi, chi tiết hơn bạn có thể tham khảo thêm tại link đính kèm.

Sau đây là ví dụ một số sự kiện Intent hệ thống cung cấp:

Android.intent.action.BATTERY_CHANGED:

Broadcast về các trạng thái của pin như: sạc, mức độ pin,…

  • android.intent.action.BATTERY_LOW: Cho biết tình trạng pin yếu trên thiết bị.

  • android.intent.action.BATTERY_OKAY: Cho biết pin đang ở tình trạng tốt sau khi ở tình trạng pin yếu.

  • android.intent.action.BOOT_COMPLETED: Broadcast chỉ thực hiện một lần, sau khi hệ thống hoàn thành việc khởi động. Bạn cần khai báo permission

  • android.permission.RECEIVE_BOOT_COMPLETED trong manifest khi dùng intent này.

  • android.intent.action.BUG_REPORT: Hiển thị 1 activity để báo lỗi.

  • android.intent.action.CAMERA_BUTTON: Người dùng nhấn vào button camera để đi đến trình quay số.

  • android.intent.action.DATE_CHANGED: Ngày đã được thay đổi.

  • android.intent.action.REBOOT: Khởi động lại thiết bị.

Có hai bước quan trọng để cho Broadcast Receivers làm việc:

Tạo Broadcast Receiver.

Đăng ký Broadcast Receiver.

Để đăng kí Broadcast Receiver, chúng ta có hai cách để thực hiện vấn đề này:
  • Đăng ký trong coding bằng hàm registerReceiver(BroadcastReceiver receiver, Intent filter).

    Cách này thường được sử dụng khi ứng dụng chỉ cần nhận thông điệp và xử lý trong khi một Activity nào đó đang sống. Lưu ý: Khi bạn đăng ký trong Activity, thì khi thoát khỏi Activity, bạn nên hủy đăng ký (unregisterReceiver(BroadcastReceiver receiver)) để tránh những xử lý ngoài ý muốn có thể gây crash ứng dụng. Thông thường, các chuyên gia khuyên bạn nên register/unregister theo từng cặp sự kiện vòng đời của một activity như: onCreate/onDestroy, onResume/onPause.

  • Đăng ký trong Manifest:

    Nó trở thành dịch vụ, tự động lắng nghe mọi thứ trong Intent – filter (kể cả khi đã đóng ứng dụng).Trong trường hợp bạn muốn tự phát ra và gửi các intents tùy chỉnh riêng từ ứng dụng của bạn thì bạn làm thêm một bước nữa là phải tạo và Broadcast các intents này bằng cách sử dụng phương thức sendBroadcast()/ sendStickyBroadcast(Intent) của class activity.

  1. Creating the BroadcastReceive on Android.
public class MyReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
      Toast.makeText(context, "Intent Detected.", Toast.LENGTH_LONG).show();
   }
}
  1. Registering Broadcast Receiver
<application
   android:icon="@drawable/ic_launcher"
   android:label="@string/app_name"
   android:theme="@style/AppTheme" >
   <receiver android:name="MyReceiver">

      <intent-filter>
         <action android:name="android.intent.action.BOOT_COMPLETED">
         </action>
      </intent-filter>

   </receiver>
</application>

**Xây dựng layout mainmenu **

  1. Get list nhạc trong máy .
  2. Giao diện music chạy nhạc .
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_awidth="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/desktop_background2"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/rl_bottom_view"
        android:layout_awidth="match_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:background="@drawable/top_layout_bg"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/list_show_album"
            android:layout_awidth="54dp"
            android:layout_height="60dp"
            android:layout_centerVertical="true"
            android:layout_margin="3dp"
            android:adjustViewBounds="true"
            android:background="@drawable/detail_pic_bg"
            android:minHeight="60dp"
            android:minWidth="60dp"
            android:paddingTop="4dp"
            android:scaleType="centerInside"
            android:src="@drawable/default_bg_s" />

        <LinearLayout
            android:id="@+id/ll_01"
            android:layout_awidth="100dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="10dp"
            android:layout_toRightOf="@+id/list_show_album"
            android:gravity="center_vertical"
            android:orientation="vertical">

            <TextView
                android:id="@+id/list_song_name"
                android:layout_awidth="100dp"
                android:layout_height="wrap_content"
                android:ellipsize="marquee"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:marqueeRepeatLimit="marquee_forever"
                android:singleLine="true"
                android:text="Song name:"
                android:textColor="@color/fashion_color"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/list_song_durction"
                android:layout_awidth="wrap_content"
                android:layout_height="wrap_content"
                android:text="00:00--00:00"
                android:textColor="@color/fashion_color" />
        </LinearLayout>

        <ViewFlipper
            android:id="@+id/my_flipper"
            android:layout_awidth="match_parent"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@+id/ll_01">

            <LinearLayout
                android:id="@+id/control"
                android:layout_awidth="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_vertical"
                android:orientation="horizontal"
                android:paddingBottom="2dp">

                <ImageButton
                    android:id="@+id/btnPrevious_player"
                    android:layout_awidth="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:background="@null"
                    android:scaleType="fitCenter"
                    android:src="@drawable/desktop_prevbt" />

                <ImageButton
                    android:id="@+id/btnPlay_player"
                    android:layout_awidth="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:background="@null"
                    android:scaleType="fitCenter"
                    android:src="@drawable/desktop_playbt" />

                <ImageButton
                    android:id="@+id/btnNext_player"
                    android:layout_awidth="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:background="@null"
                    android:scaleType="fitCenter"
                    android:src="@drawable/desktop_nextbt" />
            </LinearLayout>

            <LinearLayout
                android:id="@+id/ll_choose_menu"
                android:layout_awidth="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:gravity="center_vertical|right"
                android:orientation="horizontal">

                <ImageView
                    android:id="@+id/move_to_group"
                    android:layout_awidth="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:src="@drawable/move2group" />
            </LinearLayout>
        </ViewFlipper>

        <ProgressBar
            android:id="@+id/progressBar1"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_awidth="fill_parent"
            android:layout_height="4dp"
            android:layout_alignParentTop="true"
            android:progressDrawable="@drawable/progress_dotted" />
    </RelativeLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/center_body_view_pager"
        android:layout_awidth="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/rl_bottom_view"
        android:layout_below="@+id/actionbar"></android.support.v4.view.ViewPager>

</RelativeLayout>

Giao diện máy khi lấy ra dự liệu . Screenshot_2016-01-28-23-00-56.png

Mình sẽ update các image và source code vào đầu phần 2 : Phần 2 : Hướng dẫn cách lấy dữ liệu nhạc offline và play nhạc . Xin cảm ơn các bạn .

0