اجرای آهنگ با استفاده از سرویس در اندروید

سلام دوستان در این سری از آموزش برنامه نویسی اندروید به آموزش اجرای آهنگ با استفاده از سرویس در اندروید می پردازیم در صورتی که موزیک در ترد اصلی اجرا شود دیگر نمی توانید با برنامه کار دیگری انجام دهید یعنی برنامه فقط می تواند یک کاری را انجام دهد ولی اگر از سرویس استفاده کنیم همانطور که در مبحث سروریس توضیح داده بودیم سرویس در background اجرا می شود پس نتیجه میگریم می توان از بخش های دیگر اپلیکیشن استفاده کرد در ادامه می توانید پیش نمایشی از آن را مشاهده کنید با ما همراه باشید (دوستان دقت کنید این آموزش یک پروژه کامل Music Player است).
 

 
در اینجا پروژه ما به چهار بخش تقسیم می شود.

  • ساخت Layout برای قرار گرفتن اجزا.
  • دریافت File های آهنگ و نمایش آن در ListView
  • اجرای آهنگ در Background توسط سرویس
  • استفاده از Runtime Permission برای درخواست استفاده از Storage

حالا وارد فایل Build.gradle از نوع Module شده و در بخش dependencies خط زیر را اضافه کنید.

compile 'com.android.support:cardview-v7:25.3.1'

پروژه را sync کنید ممکن است به خطا بخورید بهتر است واژه Gradle را در سایت جستجو کنید.
وارد فایل AndroidManifest.xml شده و دسترسی زیر را اضافه کنید.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

در اینجا ما در  Layout اصلی که نام آن برابر با activity_list_of_songs.xml است کد های زیر را قرار داده ایم.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:background="@color/colorBackground"
    tools:context="com.example.mitaly.musicapp.ListOfSongsActivity">
<!--Top Section-->
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/cardView"
        android:visibility="gone"
        android:layout_margin="10dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:orientation="vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:id="@+id/txtSongName"
                android:layout_margin="15dp"
                android:gravity="center"
                android:textSize="20dp"
                android:text="Song Name"/>
            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:textColor="@android:color/white"
                android:background="@color/colorPrimary"
                android:id="@+id/btnPlayStop"
                android:gravity="center"/>
        </LinearLayout>
    </android.support.v7.widget.CardView>
<!--This is the list view showing list of songs-->
    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/listView"/>
</LinearLayout>

در بالا صفحه را به دو قسمت تقسیم کردی و در بخش پایین یک ListView و یک CardView در بالا قرار گرفته است.
باید شکل ظاهری هر کدام از آیتم ها را نیز ایجاد کنید.
پس یک فایل به نام list_item.xml ایجاد کرده و کد های زیر را در آن قرار دهید.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="8dp">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="File Name"
        android:layout_margin="10dp"
        android:textSize="18dp"
        android:id="@+id/textSong"/>
</LinearLayout>

علت این که ما این کار را انجام دادیم تا شما بعد بتوانید آن را سفارشی سازی کنید به طور مثال یک عکس در کنار هر آهنگ نیز قرار دهید.
باید یک getter و setter ایجاد کنیم تا نام و مسیر اصلی هر آهنگ را به دست بیارد.
یک فایل به نام SongObject.java ایجاد کرده و کدهای زیر را در آن قرار دهید.

package ir.programchi;
public class SongObject {
    String fileName;
    String absolutePath;
    public SongObject(String fileName,String absolutePath) {
        this.fileName = fileName;
        this.absolutePath=absolutePath;
    }
    public String getFileName() {
        return fileName;
    }
    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
    public String getAbsolutePath() {
        return absolutePath;
    }
    public void setAbsolutePath(String absolutePath) {
        this.absolutePath = absolutePath;
    }
}

چون داریم از شکل ظاهری سفارشی استفاده می کنیم باید آداپتور سفارشی نیز داشته باشیم.
یک فایل جاوا به نام AdapterClass.java ایجاد کرده و کد های زیر را در آن قرار دهید.

public class AdapterClass extends ArrayAdapter<SongObject> {
    Context cxt;
    int res;
    ArrayList<SongObject> list;
    public AdapterClass(Context context, int resource, ArrayList<SongObject> objects) {
        super(context, resource, objects);
        cxt=context;
        res=resource;
        list=objects;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view=null;
        view= LayoutInflater.from(cxt).inflate(res,parent,false);
        TextView fileName=(TextView)view.findViewById(R.id.textSong);
        SongObject sdOb=list.get(position);
        fileName.setText(sdOb.getFileName());
        return view;
    }
}

همانطور که گفتیم از سرویس برای اجرای آهنگ استفاده خواهیم کرد. یک فایل جاوا به نام MusicService.java ایجاد کرده و کدهای زیر را در آن قرار دهید.

public class MusicService extends Service {
    MediaPlayer mediaPlayer;
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setDataSource(ListOfSongsActivity.absolutePath);
            mediaPlayer.prepare();
            mediaPlayer.setLooping(true);
            mediaPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
            Log.i("show","Error: "+e.toString());
        }
        return START_STICKY;
    }
    public void onDestroy(){
        mediaPlayer.stop();
        mediaPlayer.release();
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

و در آخر هم کد مربوط به ListOfSongsActivity.java (اکتیویتی اصلی ما) همانند زیر می شود.

package ir.programchi;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.CardView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import java.io.File;
import java.util.ArrayList;
public class ListOfSongsActivity extends AppCompatActivity {
    ListView listview;
    Button btnPlayStop;
    TextView txtSongName;
    CardView cardView;
    ArrayList<SongObject> listOfContents;
    AdapterClass adapter;
    String path;
    static String absolutePath, songName;
    public static boolean playing = false;
    void initViews() {
        btnPlayStop = (Button) findViewById(R.id.btnPlayStop);
        txtSongName = (TextView) findViewById(R.id.txtSongName);
        cardView = (CardView) findViewById(R.id.cardView);
        listview = (ListView) findViewById(R.id.listView);
        listOfContents = new ArrayList<>();
        if (playing) {
            txtSongName.setText(songName);
            cardView.setVisibility(View.VISIBLE);
            btnPlayStop.setText("Stop");
        }
        path = Environment.getExternalStorageDirectory().getAbsolutePath();
        initList(path);
        adapter = new AdapterClass(this, R.layout.list_item, listOfContents);
        listview.setAdapter(adapter);
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                cardView.setVisibility(View.VISIBLE);
                if (playing) {
                    Intent i = new Intent(ListOfSongsActivity.this, MusicService.class);
                    stopService(i);
                }
                playing = true;
                SongObject sdOb = listOfContents.get(position);
                absolutePath = sdOb.getAbsolutePath();
                Intent start = new Intent(ListOfSongsActivity.this, MusicService.class);
                startService(start);
                songName = listOfContents.get(position).getFileName();
                txtSongName.setText(songName);
                btnPlayStop.setText("Stop");
            }
        });
        btnPlayStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (playing) {
                    playing = false;
                    btnPlayStop.setText("Play");
                    Intent i = new Intent(ListOfSongsActivity.this, MusicService.class);
                    stopService(i);
                } else if (!playing) {
                    playing = true;
                    btnPlayStop.setText("Stop");
                    Intent i = new Intent(ListOfSongsActivity.this, MusicService.class);
                    startService(i);
                }
            }
        });
    }
    void initList(String path) {
        try {
            File file = new File(path);
            File[] filesArray = file.listFiles();
            String fileName;
            for (File file1 : filesArray) {
                if (file1.isDirectory()) {
                    initList(file1.getAbsolutePath());
                } else {
                    fileName = file1.getName();
                    if ((fileName.endsWith(".mp3")) || (fileName.endsWith(".mp4"))) {
                        listOfContents.add(new SongObject(file1.getName(), file1.getAbsolutePath()));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    void checkPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            initViews();
        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    initViews();
                } else {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
                        finish();
                    }
                    else {
                        AlertDialog.Builder builder = new AlertDialog.Builder(this);
                        builder.setMessage("You have forcefully denied Read storage permission.\n\nThis is necessary for
the working of app." + "\n\n" + "Click on 'Grant' to grant permission")
                                .setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        finish();
                                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                                Uri.fromParts("package", getPackageName(), null));
                                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                        startActivity(intent);
                                    }
                                })
                                .setNegativeButton("Don't", new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        finish();
                                    }
                                });
                        builder.setCancelable(false);
                        builder.create().show();
                    }
                }
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_of_songs);
        if (Build.VERSION.SDK_INT >= 23)
            checkPermission();
        else
            initViews();
    }
}

حالا باید وارد AndroidManifest.xml شده و Service که در بالا تعریف کردیم را ریجستر کنیم.

<service android:name=".MusicService"
android:exported="true"
 android:enabled="true"/>

 
 
این آموزش هم به پایان رسید.
 
موفق و موید باشید.

مطالعه بیشتر