MỤC LỤC
LỊCH SỬ HÌNH THÀNH PHÁT TRIỂN VÀ CÁC KHÁI NIỆM CƠ BẢN TRONG ANDROID
1. Lịch sử ra đời của Android
Hiện nay, trên thị trường có rất nhiều loại điện thoại ra đời kèm theo đó là
các hệ điều hành(OS mobile) cho loại điện thoại đó. Thường thì các hệ điều hành
này được cung cấp kèm theo máy và là mã nguồn đóng. Nhưng trong số những
OS mobile là mã nguồn mở đó là Android. Android là hệ điều hành cho các thiết
bị cầm tay dựa trên lõi Linux do công ty Android Inc. (California, Mỹ) thiết kế.
Công ty này sau đó được Google mua lại vào năm 2005 và sau tiếp, vào năm
2007, thuộc về Liên doanh Thiết bị Cầm tay Mã Nguồn mở (Open Handset
Alliance) gồm các đại gia trong ngành viễn thông và thiết bị cầm tay như Texas
Instruments, Broadcom Corporation, Google, HTC, Intel, LG, Marvell
Technology Group, Motorola, Nvidia, Qualcomm, Samsung Electronics, Sprint
Nextel, T-Mobile, ARM Holdings, Atheros Communications, Asustek Computer
Inc, Garmin Ltd, Softbank, Sony Ericsson, Toshiba Corp, and Vodafone Group
Plc...(tính đến nay)
Có thể coi mốc 05-11-2007 là ngày Android được công bố ra toàn thế giới
cùng với sự ra đời của liên danh OHA nói tên trên, và 18-8-2008, các lập trình
viên Android được phép tiếp cận và sử dụng mã nguồn mở để lập trình ứng dụng
cho hệ điều hành này.
Càng ngày càng có nhiều thiết bị sử dụng OS Android. Dưới đây là biểu
đồ thống kê so sánh các hệ điều hành cho điện thoại di động năm 2009 và quý 1
năm 2010 tại Mỹ.
Nhìn vào biểu đồ này ta có thể thấy được sự phát triệt vượt bậc của OS
Android trong 4 quý trở lại đây.
2. Các thành phần cơ bản của một ứng dụng android
Ứng dụng Android sẽ được xây dựng từ 4 thành phần mà được định nghĩa
bởi kiến trúc Android.
2.1. Activities
Activities có thể so sánh như là utility độc lập trên hệ thống desktop hay
như office applications. Activities là đoạn code thực thi mà khởi động thời điểm
cả user và hệ điều hành(Android) chạy song song khi được cần thiết. Nó có thể
tương tác với user và request data hoặc services từ những activities khác hoặc
những services thông qua queries hoặc Intents.
2.2. Services
Tương tự như những services chạy trên hệ thống desktop hay server. Nó là
những đoạn code thực thi mà thương chạy ngầm từ lúc thực thi đến khi thiết
bị(cell phone) shut down. Nói chung nó không expose ra cho user thấy.
Ví dụ như service là một MP3 player thì cần phải chơi các file được xếp
sẵn vào 1 queue nào đó(playlist) cho đến khi user tiếp tục dùng ứng dụng khác.
Ứng dụng cần implement services để thực thi task đó ngầm định mà sẽ không
expose ra giao diện.
2.3. Broadcast and Intent Receivers
Những responds những requests cho service từ ứng dụng khác. Broadcast
receiver trả lời cho hệ thống thông báo của một sự kiện nào đó. Những thông báo
này có thể đến từ chính hệ điều hành(ví dụ như thông báo pin yếu…) hoặc từ bất
kỳ chương trình nào đang chạy trên hệ thống. Một Activity hay Service cung cấp
ứng dụng khác access vào chức năng của nó bằng cách thực thi Intent Receiver,
một đoạn code nhỏ nào đó mà trả lời những requessts data hay services từ những
activities khác. Requesting Activity cho ra một Intent, để nó cho Android
framework figure out ứng dụng nào sẽ nhận và thực hiện nó.
Intents là một trong những yếu tố chính trong kiến trúc Android mà làm
cho dễ dàng tạo ra ứng dụng từ những ứng dụng đã tồn tại(mobile mashups). Ta
sẽ dùng Intents trong ứng dụng để tương tác với ứng dụng và services khác mà
cung cấp thông tin cần thiết cho ứng dụng.
2.4. Content providers
Content providers được tạo ra để chia sẻ data với các activities hay
services khác. Một content provider dùng một interface chuẩn từ URI để thực
hiện requests cho data từ ứng dụng khác mà có thể không biết content provider
nào mà chúng sẽ dùng. Ví dụ, khi một ứng dụng truy xuất Contact data, nó đánh
địa chỉ truy xuất dạng:
content://contacts/people
Hệ điều hành xem ứng dụng nào đã registered trong hệ thống như content
providers đối với URI được cho, và gửi request đến ứng dụng thích hợp(sẽ start
ứng dụng đó nếu nó chưa running). Nếu có nhiều hơn một content provider đã
registered cho cái requested URI đó, hệ điều hành sẽ hỏi user muốn dùng cái
nào.
Một ứng dụng không nhất thiết phải có tất cả components của Android,
nhưng một ứng ứng dụng viết tốt nên dùng những gì có sẵn hơn là sáng tạo lại
chức năng hoặc hardcoding references ứng dụng khác. URIs và Intent cho phép
Android cung cấp môi trường rất flexible. Ứng dụng có thể dễ dàng thêm, xóa,
thay thế và tương tác làm việc cùng nhau.
3. Android Activity LifeCycle
Android được thiết kế quanh những yêu cầu chính của ứng dụng điện
thoại. Cụ thể, Android nhận ra rằng tài nguyên thì không vô tận trên hầu hết các
thiết bị điện thoại(ví dụ như memory,battery…), và cung cấp những kỹ thuật để
duy trì những tài nguyên đó. Kỹ thuật đó thể hiện rõ nét ở Android Activity
Lifecycle, mà định nghĩa trạng thái hay sự kiện mà một activity chạy từ lúc nó
được tạo cho đến khi nó hoàn thành.
Hình 1. Android Activity Lifecycle
Activity sẽ giám sát và react những sự kiện bằng cách thực hiện những
method mà override những method của Activity class:
onCreate
Sẽ được gọi khi activity lần đầu tiên được tạo. Đây là nơi thường tạo
views, mở những file dữ liệu mà cần thiết cho activity , và nó chung là khởi tạo
activity . Khi cọi onCreate, Android framework sẽ được
truyền một đối tượng Bundle object mà chứa bất khì trạng thái hoạt động
nào đã được lưu khi activity đó đã chạy trước đó.
onStart
Được gọi trước khi activity xuất hiện ở màn hình. Khi onStart hoàn thành,
nếu activity foreground trên màn hình, điều khiển sẽ được chuyển cho
onResume. Nếu activity không thể foreground vì một vài lý do nào đó, điều
khiển sẽ được chuyển sang cho onStop.
onResume
Được gọi ngay sau khi onStart nếu activity foreground trên màn hình. Tại
thời điểm này activity sẽ chạy và tương tác với user. Ta sẽ nhận keyboard và
touch inputs, và màn hình sẽ hiển thị user interface . onResume cũng được gọi
nếu activity nhường foreground cho activity khác, và activity đó cuối cùng kết
thúc, lúc đó sẽ lại bật lên trời lại foreground. Đây là nơi activity sẽ thực
hiện(hoặc resume) những thứ mà cần thiết để update user interface.
onPause
Được gọi khi hệ điều hành resume activity khác, để activity đó
foreground. Tại thời điểm này activity sẽ không còn trên màn hình nữa, vì vậy
nên ngừng những việc mà tiêu thụ battery và CPU. Nếu đang chạy animation,
tất nhiên không ai có thể thấy nó, vì vậy nên suspend nó cho đến khi nó trở lại
màn hình. Activity cần sự thuận lợi của phương thức này để chứa bất kỳ trạng
thái nào mà sẽ cần trong trường hợp activity nhận lại được foreground và điều
này không đảm bảo rằng activity sẽ được resume. Nếu thiết bị đang chạy out of
memory, mà không có vitual memory trên đĩa cứng để dùng cho sự mở rộng, vì
vậy activity có lẽ phải tạo ra cách cho system process mà bộ nhớ cần. Khi exit
method này, Android có thể kill activity tại bất khì thời điểm nào mà không trả
lại quyền điều khiển.
onStop
Được gọi khi activity không còn visible nữa, bởi activity khác chiếm
foregroudn và bởi activity destroyed.
onDestroy
Cơ hội cuối cùng cho activity thực hiện bất khì processing nào trước khi
nó bị destroyed. Bình thường sẽ có được điều này(tức là sẽ tự destroyed và
không phải làm điều này) bởi vì activity được thực hiện và framework gọi
phương thức finish của chính nó. Nhưng như đã đề cập trước đây, phương thức
này có thể được gọi bởi vì Android đã quyết định tài nguyên mà activity tiêu
thụ.
4. Cấu trúc một Android project
Trong hình dưới đây là expand Package Explore để show những thư mục
mà Android SDK đã tạo.
Hình 2. Cấu trúc Android project
Android SDK đã tạo thư mục HelloWorld trong môi trường làm việc của
Eclipse cho project. Nó cũng tạo các thư mục con cho source code (.src),
Android Library, assets, resources(.res), và manifet file(AndroidManifest.xml).
Trong mỗi thư mục con nó cũng tạo ra các thư mục con thích hợp khác.
Sources(under src)
Chứa cấu trúc thư mục mà tương xứng với package name, trong trường
hợp này là com.android.helloworld
Chứa file Java cho Activity chỉ định trong ứng dụng và có thể chứ một
thư mực resource references(R.java). R.java được tạo ra bởi Android SDK khi
compile ứng dụng, nó chứa Java version của tất cả resource trong thư mục res.
Android Library
Nếu thích, có thể expand file android.jar để xem tên các module chứ
trong thư viện. Đây là nơi ứng dụng sẽ tham chiếu đến thư viện này.
assets
Những file muốn gói chung vào ứng dụng .
Resources(under res)
Drawable resources là images,bitmaps,… mà cần cho ứng dụng. Đối với
chương trình HelloWorld, Android SDK dùng icon mặc định của nó.
Layout resources chỉ cho Android làm cách nào đẻ sắp xếm item trên màn
hình. Những tài nguyên này là những file xml mà cho tự do laying out cho nhiều
mục đích khác nhau. Đối với ứng dụng HelloWorld, chúng ta chỉ dùng default
của Android SDK.
Values là constants, strings,… available cho ứng dụng . Giữ chúng ờ ngoài
sources khiến nó dễ dàng customize hơn. Ví dụ như adapting các ngôn ngữ khác
nhau.
Manifest(AndroidManifest.xml)
Đây là một file xml khác mà chỉ cho Android built hệ thống những gì mà
nó biết để built và đóng gói ứng dụng để mà có thể install trên Android phone
hay emulator.Chúng ta sẽ hiểu hơn khi làm các ứng dụng phức tạp hơn.
Trên đây là giới thiệu về cấu trúc của một Android project.
ỨNG DỤNG NGHE NHẠC TRÊN ANDROID
1. Giới thiệu phần mềm Simple Media Player của nhóm
Simple Media Player là một ứng dụng dùng để nghe nhạc trên hệ điều hành Android (Google). Là một phần mềm đơn giản có giao diện dễ sử dụng.
Các chức năng chính của ứng dụng là:- Liệt kê tất cả các bài hát có trong thẻ nhớ của thiết bị.- Bật một bài hát khi người dùng click và bài hát đó.- Next sang bài tiếp theo- Lùi về bài trước đó.- Lùi về đầu bài hát.- Hiển thị các thông tin của bài hát.Ứng dụng này có thể chạy được trên các nền tảng Android 1.6, Android 2.1,
Android 2.2.
2. Mã nguồn của ứng dụng
/src/com/mp/PlayMedia.class
package com.mp;
import android.app.ListActivity;import android.content.Intent;import android.database.Cursor;import android.os.Bundle;import android.provider.MediaStore;import android.view.View;import android.widget.ListView;
public class ListSong extends ListActivity {private Cursor mCursor;private ListSongAdapter adapter;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCursor = getContentResolver().query(MediaStore.Audio.Me-dia.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.TITLE + " ASC"); adapter = new ListSongAdapter(this, mCursor); setListAdapter(adapter); } @Override protected void onListItemClick(ListView l, View v, int posi-tion, long id){ super.onListItemClick(l, v, position, id); Intent mPlay = new Intent(getApplicationContext(), PlayMedi-a.class); mPlay.putExtra("ItemId", position); startActivity(mPlay); }}
/src/com/mp/ListSongAdapter.classpackage com.mp;
import android.content.Context;import android.database.Cursor;import android.provider.MediaStore;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;
public class ListSongAdapter extends BaseAdapter{
private LayoutInflater mInflate;private Cursor mData;/** * Hàm khởi tạo Adapter */public ListSongAdapter(Context context, Cursor data) {
mInflate = LayoutInflater.from(context);mData = data;
}
@Overridepublic int getCount() {
return mData.getCount();}
@Overridepublic Object getItem(int position) {
return position;}
@Overridepublic long getItemId(int position) {
return position;}
@Overridepublic View getView(int position, View convertView, ViewGroup par-
ent) {
ViewHolder holder;
if(convertView == null) {convertView = mInflate.inflate(R.layout.list_item,
null);
holder = new ViewHolder();holder.mTittle =
(TextView)convertView.findViewById(R.id.row_title);holder.mAlbum =
(TextView)convertView.findViewById(R.id.row_album);
holder.mArtist = (TextView)convertView.findViewById(R.id.row_artist);
holder.mIcon = (ImageView)convertView.findViewById(R.id.Icon);
holder.mIcon.setImageResource(R.drawable.type_music);convertView.setTag(holder);
} else {holder = (ViewHolder)convertView.getTag();
}
mData.moveToPosition(position);
holder.mTittle.setText(mData.getString(mDa-ta.getColumnIndex(MediaStore.Audio.Media.TITLE)));
holder.mAlbum.setText(mData.getString(mDa-ta.getColumnIndex(MediaStore.Audio.Media.ALBUM)));
holder.mArtist.setText(mData.getString(mDa-ta.getColumnIndex(MediaStore.Audio.Media.ARTIST)));
return convertView;}
private class ViewHolder {ImageView mIcon;TextView mTittle;TextView mAlbum;TextView mArtist;
}}
/src/com/mp/Ultility.classpackage com.mp;
public class Utility {public static final int MILISECOND = 1000;public static final int MINUTE = 60;/** * * @param value Truyền vào giá trị thời gian kiểu long * @return Chuỗi được định dạng theo thời gian phút giây mm:ss */public static String createHMFormatfromM(long value) {
String res, strMinute, strSecond = null;long tempsecond, second,minute = 0;
tempsecond = value/MILISECOND;second = tempsecond%MINUTE;minute = tempsecond/MINUTE;
if(minute < 10) {strMinute = "0" + String.valueOf(minute);
} else {strMinute = String.valueOf(minute);
}
if(second < 10) {strSecond = "0" + String.valueOf(second);
} else {strSecond = String.valueOf(second);
}
res = strMinute + ":" + strSecond;
return res;}
}
/src/com/mp/PlayMedia.class
package com.mp;
import android.app.Activity;import android.app.AlertDialog;import android.content.ContentUris;import android.content.DialogInterface;import android.content.Intent;import android.database.Cursor;import android.media.MediaPlayer;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.provider.MediaStore;import android.view.GestureDetector;import android.view.Menu;import android.view.MenuItem;import android.view.MotionEvent;import android.view.View;import android.view.GestureDetector.OnGestureListener;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.view.animation.AnimationUtils;import android.widget.Button;import android.widget.SeekBar;import android.widget.TextView;import android.widget.ViewFlipper;
public class PlayMedia extends Activity implements OnGestureListener {private static final int BACKLIST = Menu.FIRST;private static final int ABOUT = Menu.FIRST + 2;private Button mPausePlay;private Button mPrevious;private Button mNext;private SeekBar mSeekBar;private Cursor mCursor;private Boolean isPlay, isFirst;private MediaPlayer mMedia;private ViewFlipper mFlipper;private TextView txtTitle, txtFileName, txtSinger, txtEndTime;private int mCurSongId,mTotalSong, mTick, mCurrentPosOfSeek, mMe-
diaDuration;private GestureDetector gestureScanner;@Overridepublic void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);setContentView(R.layout.player);mPausePlay = (Button)findViewById(R.id.btnPause_Play);mPrevious = (Button)findViewById(R.id.btnPrevious);mNext = (Button)findViewById(R.id.btnNext);mSeekBar = (SeekBar)findViewById(R.id.seekbar);txtFileName = (TextView)findViewById(R.id.FileName);
txtTitle = (TextView)findViewById(R.id.Title);txtSinger = (TextView)findViewById(R.id.Singer);txtEndTime = (TextView)findViewById(R.id.End_Time);mMediaDuration = 0;mCurrentPosOfSeek = 0;isFirst = false;//Tạo hiệu ứng thể hiện tên bài hátmFlipper = ((ViewFlipper) this.findViewById(R.id.flipper));
mFlipper.startFlipping(); mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_out)); gestureScanner = new GestureDetector(this);
mCursor = getContentResolver().query(MediaStore.Audio.Medi-a.EXTERNAL_CONTENT_URI,
null , null, null, MediaStore.Audio.Media.TITLE + " ASC");
mTotalSong = mCursor.getCount();setOnClick(mPausePlay);setOnClick(mNext);setOnClick(mPrevious);setOnClick(mSeekBar);
if(!isFirst){Bundle b = getIntent().getExtras();mCurSongId = b.getInt("ItemId");createMediaPlayerFromId(mCurSongId);displayData(mCurSongId);playMedia();
}
}
@Overrideprotected void onDestroy(){
super.onDestroy();releaseMedia();
}
@Override public boolean onTouchEvent(MotionEvent me) { return gestureScanner.onTouchEvent(me); }
@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float ve-
locityX, float velocityY) { if (velocityX<-200) Next();; if (velocityX>200) Previous(); return true; }
private String[] createRecord(int recordId) {String[] res = new String[4];mCursor.moveToPosition(recordId);res[0] = mCursor.getString(mCursor.getColumnIndex(MediaS-
tore.Audio.Media.TITLE));res[1] = mCursor.getString(mCursor.getColumnIndex(MediaS-
tore.Audio.Media.ALBUM));res[2] = mCursor.getString(mCursor.getColumnIndex(MediaS-
tore.Audio.Media.DISPLAY_NAME));
return res;}
private void displayData(int recordId) {String[] record = createRecord(recordId);txtTitle.setText(record[1]);txtFileName.setText(record[0]);txtSinger.setText(record[2]);
}
private void releaseMedia() {if(mMedia != null) {
mMedia.stop();mMedia.release();
}isPlay = false;
}
private void createMediaPlayerFromId(int id) {releaseMedia();
mCursor.moveToPosition(id);Uri uri = ContentUris.withAppendedId(MediaStore.Au-
dio.Media.EXTERNAL_CONTENT_URI,Long.valueOf(mCursor.getString(mCur-
sor.getColumnIndex(MediaStore.Audio.Media._ID))));mMedia = MediaPlayer.create(getApplicationContext(),
uri);mMediaDuration = mMedia.getDuration();mSeekBar.setMax(mMediaDuration/Utility.MILISECOND);mTick = 0;mCurrentPosOfSeek = 0;
}
private void setOnClick(final View v){v.setOnClickListener(new OnClickListener(){
@Overridepublic void onClick(View v){
switch(v.getId()){case R.id.btnPrevious:
Previous();break;
case R.id.btnPause_Play:
if(isPlay){pauseMedia();
pauseMedia();}else{
playMedia();}
break;case R.id.btnNext:
Next();break;
default:break;
}}
});if(v.getId()==R.id.seekbar){
v.setOnTouchListener(new OnTouchListener(){
@Overridepublic boolean onTouch(View v, MotionEvent
event){switch(event.getAction()){case MotionEvent.ACTION_UP:
mCurrentPosOfSeek = mSeek-Bar.getProgress();
mTick = mCurrentPosOf-Seek*Utility.MILISECOND;
mMedia.seekTo(mTick);break;
default:break;
}
return false;}
});}
}private void Previous(){
if(mTick <= 3000){isFirst = true;if(mCurSongId == 0){
mCurSongId = mTotalSong -1;}else{
mCurSongId--;}createMediaPlayerFromId(mCurSongId);displayData(mCurSongId);playMedia();
}else{mTick = 0;mMedia.seekTo(0);mCurrentPosOfSeek = 0;
}
}private void Next(){
isFirst = true;
if(mCurSongId == mTotalSong-1){mCurSongId = 0;
} else{mCurSongId++;
}createMediaPlayerFromId(mCurSongId);displayData(mCurSongId);playMedia();
}private void pauseMedia(){
if(mMedia.isPlaying()){mMedia.pause();mPausePlay.setText("Play");isPlay = false;
}}Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if((mTick < mMediaDuration) &&(isPlay)) {mSeekBar.setProgress(mCurrentPosOfSeek);txtEndTime.setText(Utility.createHMFormat-
fromM(mTick));mTick += Utility.MILISECOND;mCurrentPosOfSeek++;sendEmptyMessageDelayed(0, Utili-
ty.MILISECOND);}
if(mTick >= mMediaDuration) {mPausePlay.setText("Play");
}}
};
private void playMedia() {if(!mMedia.isPlaying()) {
mPausePlay.setText("Pause");isPlay = true;mMedia.start();
}if(!isFirst) {
mHandler.sendEmptyMessage(0);}
}public void createDialog(String title, String text) {
AlertDialog ad = new AlertDialog.Builder(this).setPos-itiveButton("Ok",
null).setTitle(title).setMessage(text).create();ad.show();
}// Tạo Option Menu@Overridepublic boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);menu.add(0, BACKLIST, 0, "List Song").setIcon(
android.R.drawable.ic_menu_myplaces);
android.R.drawable.ic_menu_myplaces);menu.add(0, ABOUT, 0, "About").setIcon(
android.R.drawable.ic_menu_info_details);return true;
}
// Xử lý sự kiện khi các Option trong Menu được chọnpublic boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {case BACKLIST: {
backList();break;
}case ABOUT: {
AlertDialog.Builder ab = new AlertDia-log.Builder(this);
ab.setTitle("Nhóm phát triển");ab.setMessage("1. Nguyễn Thành Công" + "\n"
+ "2. Nguyễn Đức Thành" + "\n" + "3. Nguyễn Quang Tuyển "
+ "\n" + "4. Chu Minh Đức" + "\n" + "5. Nông Văn Quyết");
ab.setPositiveButton("Close",new DialogInterface.OnClickLis-
tener() {@Overridepublic void onClick(DialogIn-
terface dialog, int which) {}
});ab.setIcon(android.R.drawable.ic_dialog_info);ab.show();break;
}}return true;
}private void backList() {
Intent i = new Intent();i.setAction("backList");i.setClass(this, ListSong.class);startActivityForResult(i, 0);finish();
}
@Overridepublic boolean onDown(MotionEvent e) {
// TODO Auto-generated method stubreturn false;
}
@Overridepublic void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub}
@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {// TODO Auto-generated method stubreturn false;
}
@Overridepublic void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Overridepublic boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stubreturn false;
}}
/res/layout/list_item.xml<?xml version="1.0" encoding="UTF-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/Icon" android:gravity="center_vertical" android:scaleType="center" android:layout_marginLeft="8dip" android:layout_width="40dip" android:layout_height="fill_parent" /> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dip" android:layout_marginBottom="8dip" android:layout_marginLeft="12dip" android:layout_marginRight="12dip"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView android:id="@+id/row_artist" android:textColor="#ff99ff" android:textSize="12sp" android:layout_marginLeft="1dip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="artist"/>
<TextView android:id="@+id/row_album" android:textColor="#ffff99" android:textSize="12sp" android:layout_marginLeft="12dip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="album" android:lines="1"
android:ellipsize="marquee" android:singleLine="true"/>
</LinearLayout><TextView android:id="@+id/row_title"
android:textColor="#ffffff" android:textSize="18sp" android:shadowColor="#999999" android:shadowDx="1" android:shadowDy="1" android:shadowRadius="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1"
android:text="title" android:lines="1" android:ellipsize="marquee" android:singleLine="true"/>
</LinearLayout><TextView
android:id="@+id/artist" android:layout_width="fill_parent" android:layout_height="wrap_content" />
</LinearLayout>
/res/layout/player.xml<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:orientation="vertical"> <ViewFlipper android:id="@+id/flipper" android:layout_width="fill_parent" android:layout_height="wrap_content" android:flipInterval="2000" android:layout_marginBottom="20dip" > <TextView android:id="@+id/FileName" android:textColor="#ff99ff" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textSize="26sp"/> <TextView android:id="@+id/Title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textColor="#ffffff" android:textSize="26sp"/> <TextView android:id="@+id/Singer" android:textColor="#ffff99" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textSize="26sp"/> </ViewFlipper> <TextView android:id="@+id/End_Time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="100dip" android:text="3:30" android:textColor="#ffffff"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal">
<Button android:id="@+id/btnPrevious" android:text="Previous" android:layout_width="80dip" android:layout_height="wrap_content" /> <Button android:id="@+id/btnPause_Play"
/res/anim/push_up_in.xml
/res/anim/push_up_out.xml
android:text="Play" android:layout_width="80dip" android:layout_height="wrap_content" /> <Button android:id="@+id/btnNext" android:text="Next" android:layout_width="80dip" android:layout_height="wrap_content" />
</LinearLayout> <SeekBar android:id="@+id/seekbar" android:layout_width="fill_parent" android:layout_height="wrap_content"/></LinearLayout>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translate android:fromYDelta="100%p" android:toYDelta="0"
android:duration="300"/><alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:dura-
tion="300" /></set>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translate android:fromYDelta="0" android:toYDelta="-100%p" an-
droid:duration="300"/><alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:dura-
tion="300" /></set>
/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mp" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name="ListSong" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
<activity android:name="PlayMedia" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter>
</activity></application></manifest>
3. Thử nghiệm trên máy ảo Android
NHẬN XÉT CỦA GIẢNG VIÊN
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................