اجرای آهنگ با استفاده از سرویس در اندروید
سلام دوستان در این سری از آموزش برنامه نویسی اندروید به آموزش اجرای آهنگ با استفاده از سرویس در اندروید می پردازیم در صورتی که موزیک در ترد اصلی اجرا شود دیگر نمی توانید با برنامه کار دیگری انجام دهید یعنی برنامه فقط می تواند یک کاری را انجام دهد ولی اگر از سرویس استفاده کنیم همانطور که در مبحث سروریس توضیح داده بودیم سرویس در background اجرا می شود پس نتیجه میگریم می توان از بخش های دیگر اپلیکیشن استفاده کرد در ادامه می توانید پیش نمایشی از آن را مشاهده کنید با ما همراه باشید (دوستان دقت کنید این آموزش یک پروژه کامل Music Player است).
در اینجا پروژه ما به چهار بخش تقسیم می شود.
- ساخت Layout برای قرار گرفتن اجزا.
- دریافت File های آهنگ و نمایش آن در ListView
- اجرای آهنگ در Background توسط سرویس
- استفاده از Runtime Permission برای درخواست استفاده از Storage
حالا وارد فایل Build.gradle از نوع Module شده و در بخش dependencies خط زیر را اضافه کنید.
1 | compile 'com.android.support:cardview-v7:25.3.1' |
پروژه را sync کنید ممکن است به خطا بخورید بهتر است واژه Gradle را در سایت جستجو کنید.
وارد فایل AndroidManifest.xml شده و دسترسی زیر را اضافه کنید.
1 | <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
در اینجا ما در Layout اصلی که نام آن برابر با activity_list_of_songs.xml است کد های زیر را قرار داده ایم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?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 ایجاد کرده و کد های زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?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 ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 ایجاد کرده و کد های زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 ایجاد کرده و کدهای زیر را در آن قرار دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 (اکتیویتی اصلی ما) همانند زیر می شود.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | 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 که در بالا تعریف کردیم را ریجستر کنیم.
1 2 3 | <service android:name=".MusicService" android:exported="true" android:enabled="true"/> |
این آموزش هم به پایان رسید.
موفق و موید باشید.
سلام ممنون از آموزشتون 🙂
چطوری تصویر خود آهنگ رو بگیرم و نمایش بدم؟؟
سلام کد زیر می تونه بهتون کمک کنه
موفق باشید.
ممنونم 🙂
خواهش می کنم.
سلام ممنون بابت آموزش های خوبتون
ببخشید اگه بخوایم موقعی که روی stop کلیک میشه آهنگ به طور کامل قطع نشه یعنی منظورم اینه که وقتی دوباره روی play کلیک میکنیم آهنگ از ادامه پخش بشه و نه از ابتدا دوباره شروع بشه باید چکار کنیم؟
و اینکه این کارو میخوام از اکتیویتی انجام بدم نه از سرویس
ممنون