国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

《移動互聯(lián)網(wǎng)技術(shù)》第九章 感知與多媒體: 了解質(zhì)感設(shè)計的基本原則和設(shè)計方法

這篇具有很好參考價值的文章主要介紹了《移動互聯(lián)網(wǎng)技術(shù)》第九章 感知與多媒體: 了解質(zhì)感設(shè)計的基本原則和設(shè)計方法。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

《移動互聯(lián)網(wǎng)技術(shù)》第九章 感知與多媒體: 了解質(zhì)感設(shè)計的基本原則和設(shè)計方法,移動互聯(lián)網(wǎng)技術(shù),android,android-studio,安卓,ide

???? 博主 libin9iOak帶您 Go to New World.???
?? 個人主頁——libin9iOak的博客??
?? 《面試題大全》 文章圖文并茂??生動形象??簡單易學(xué)!歡迎大家來踩踩~??
?? 《IDEA開發(fā)秘籍》學(xué)會IDEA常用操作,工作效率翻倍~??
???? 希望本文能夠給您帶來一定的幫助??文章粗淺,敬請批評指正!????

《移動互聯(lián)網(wǎng)技術(shù)》課程簡介

《移動互聯(lián)網(wǎng)技術(shù)》課程是軟件工程、電子信息等專業(yè)的專業(yè)課,主要介紹移動互聯(lián)網(wǎng)系統(tǒng)及應(yīng)用開發(fā)技術(shù)。課程內(nèi)容主要包括移動互聯(lián)網(wǎng)概述、無線網(wǎng)絡(luò)技術(shù)、無線定位技術(shù)、Android應(yīng)用開發(fā)和移動應(yīng)用項目實踐等五個部分。移動互聯(lián)網(wǎng)概述主要介紹移動互聯(lián)網(wǎng)的概況和發(fā)展,以及移動計算的特點。無線網(wǎng)絡(luò)技術(shù)部分主要介紹移動通信網(wǎng)絡(luò)(包括2G/3G/4G/5G技術(shù))、無線傳感器網(wǎng)絡(luò)、Ad hoc網(wǎng)絡(luò)、各種移動通信協(xié)議,以及移動IP技術(shù)。無線定位技術(shù)部分主要介紹無線定位的基本原理、定位方法、定位業(yè)務(wù)、數(shù)據(jù)采集等相關(guān)技術(shù)。Android應(yīng)用開發(fā)部分主要介紹移動應(yīng)用的開發(fā)環(huán)境、應(yīng)用開發(fā)框架和各種功能組件以及常用的開發(fā)工具。移動應(yīng)用項目實踐部分主要介紹移動應(yīng)用開發(fā)過程、移動應(yīng)用客戶端開發(fā)、以及應(yīng)用開發(fā)實例。
課程的教學(xué)培養(yǎng)目標(biāo)如下:
1.培養(yǎng)學(xué)生綜合運用多門課程知識以解決工程領(lǐng)域問題的能力,能夠理解各種移動通信方法,完成移動定位算法的設(shè)計。
2.培養(yǎng)學(xué)生移動應(yīng)用編程能力,能夠編寫Andorid應(yīng)用的主要功能模塊,并掌握移動應(yīng)用的開發(fā)流程。
3. 培養(yǎng)工程實踐能力和創(chuàng)新能力。
 通過本課程的學(xué)習(xí)應(yīng)達(dá)到以下目的:
1.掌握移動互聯(lián)網(wǎng)的基本概念和原理;
2.掌握移動應(yīng)用系統(tǒng)的設(shè)計原則;
3.掌握Android應(yīng)用軟件的基本編程方法;
4.能正確使用常用的移動應(yīng)用開發(fā)工具和測試工具。

第九章 感知與多媒體

本章小結(jié):

1**、本單元學(xué)習(xí)目的**

通過學(xué)習(xí)如何使用移動設(shè)備的各種傳感器和硬件設(shè)備來獲取環(huán)境信息,掌握如何使用GPS實現(xiàn)定位功能,音視頻播放功能,攝像頭拍照功能;掌握界面設(shè)計原則、用戶體驗設(shè)計和質(zhì)感設(shè)計。

2**、本單元學(xué)習(xí)要求**

(1) 掌握各種感知處理方法;

(2) 了解質(zhì)感設(shè)計的基本原則和設(shè)計方法,并且通過不斷的實踐從復(fù)雜的事務(wù)中提煉出簡潔、舒適的設(shè)計。

3**、本單元學(xué)習(xí)方法**

結(jié)合教材以及Android Studio開發(fā)軟件,對傳感器、攝像頭、藍(lán)牙等模塊進(jìn)行編程練習(xí),運行調(diào)試,并在模擬器中觀察運行情況。

4**、本單元重點難點分析**

重點

(1) 傳感器

Android系統(tǒng)中包括兩類傳感器,分別是物理傳感器和虛擬傳感器。物理傳感器可以直接采集各種物理特性,包括溫度計、氣壓計、光傳感器、心率計、加速度計、陀螺儀、指南針等等。虛擬傳感器根據(jù)物理傳感器采集的數(shù)據(jù),通過融合算法計算出各種特性,比如:旋轉(zhuǎn)矢量、重力、線性加速度等等。手機上的計步器也是一種虛擬傳感器,它可以根據(jù)加速度計計算步數(shù)。另外,按照傳感器的用途,可劃分為:運動傳感器、環(huán)境傳感器和位置傳感器。運動傳感器測量加速度以及沿三個軸的旋轉(zhuǎn)速度,包括加速度計,重力感應(yīng)器,陀螺儀等等。環(huán)境傳感器測量各種環(huán)境參數(shù),例如:空氣溫度、照明等,包括氣壓計、光傳感器、溫度計等。位置傳感器測量設(shè)備的物理位置,包括:GPS、方向傳感器和磁力計等。

傳感器的數(shù)據(jù)采集有不同的方式:第一、可以持續(xù)不斷的采集數(shù)據(jù),通常實時的連續(xù)獲取數(shù)據(jù)常用于加速度計、陀螺儀等傳感器;第二、在一段時間內(nèi),當(dāng)傳感器數(shù)據(jù)發(fā)生變化時采集數(shù)據(jù),比如:心率計和計步器;第三、當(dāng)傳感器檢測到某種特定事件時,開始采集數(shù)據(jù),比如:紅外傳感器檢測到人靠近時會觸發(fā)相應(yīng)的事件;第四、某些特定需求的數(shù)據(jù)采集。

Android通過SensorManager來管理傳感器。首先創(chuàng)建SensorActivity,在onCreate函數(shù)中使用Context.getSystemService(String)來獲取SensorManager。

public class SensorActivity extends AppCompatActivity {
public static String TAG = “MainTAG”;
private SensorManager sensorManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sensor);

manager=(SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);

List sensorList;
// 獲取設(shè)備支持的所有傳感器
sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
List sensorNameList = new ArrayList();

for (Sensor sensor : sensorList) {
Log.d(TAG, "傳感器: " + sensor.getName());
}

}

}

如果要使用特定的傳感器,需要從SensorManager中獲取指定類型的傳感器。使用SensorManager.getDefaultSensor(int type)得到指定的Sensor。type參數(shù)用來指定要獲取的傳感器類型,比如:

Sensor.TYPE_ORIENTATION:方向傳感器;

Sensor.TYPE_ACCELEROMETER:重力傳感器;

Sensor.TYPE_LIGHT:光線傳感器;

Sensor.TYPE_MAGNETIC_FIELD:磁場傳感器。

當(dāng)外部環(huán)境發(fā)生變化時,Android系統(tǒng)首先通過傳感器獲取外部環(huán)境數(shù)據(jù),然后將數(shù)據(jù)傳遞給監(jiān)聽器的監(jiān)聽回調(diào)函數(shù)。為了采集傳感器數(shù)據(jù),通過SensorManager為Sensor添加監(jiān)聽器。在使用完后,還要注銷監(jiān)聽器。

sensorManager.registerListener(sensorListener,

sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),

SensorManager.SENSOR_DELAY_NORMAL);

第一個參數(shù)是監(jiān)聽器listener,第二個參數(shù)是傳感器sensor,第三個參數(shù)是傳感器的采樣率rateUs,表示從傳感器獲取值的頻率,它包括以下幾個選項:

SensorManager.SENSOR_DELAY_FASTEST:最快,延遲最??;

SensorManager.SENSOR_DELAY_GAME:適合游戲的頻率;

SensorManager.SENSOR_DELAY_NORMAL:正常頻率;

SensorManager.SENSOR_DELAY_UI:最慢,適合界面UI變化的頻率。

采樣頻率根據(jù)實際應(yīng)用的需要來確定說。通常采用SENSOR_DELAY_NORMAL 或SENSOR_DELAY_GAME。如果采用更高的采樣率,將耗費更多的資源,包括電量、CPU等。

接下來實現(xiàn)監(jiān)聽器。

private SensorEventListener sensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float x_lateral = sensorEvent.values[0];
float y_longitudinal = sensorEvent.values[1];
float z_vertical = sensorEvent.values[2];

   String info = "加速度傳感器xyz軸的加速度分別為:\n" + x_lateral +
       "\n" + y_longitudinal + "\n" + z_vertical + "\n";

   sView.setText(info);
 }

}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

};

當(dāng)傳感器采集的值發(fā)生變化時,觸發(fā)調(diào)用函數(shù)onSensorChanged(SensorEvent event);當(dāng)傳感器精度發(fā)生變化時,觸發(fā)調(diào)用函數(shù)onAccuracyChanged(Sensor sensor,int accuracy)。

關(guān)閉應(yīng)用后,傳感器的監(jiān)聽器不會自動釋放資源,因此需要開發(fā)人員在適當(dāng)?shù)臅r候注銷監(jiān)聽器。

@Override
protected void onStop() {
sensorManager.unregisterListener(sensorListener);
super.onStop();
}

(2) GPS****定位和位置服務(wù)

下面利用移動設(shè)備的GPS芯片來定位經(jīng)緯度坐標(biāo)。在界面上用TextView控件顯示定位的經(jīng)緯度信息。

<TextView

android:id="@+id/location_text_view"

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:textSize=“28sp”/>

使用設(shè)備的定位功能需要授予權(quán)限,考慮一下是使用動態(tài)授權(quán)還是靜態(tài)授權(quán)?靜態(tài)權(quán)限如下:

注意:Andriod 6.0以后要使用動態(tài)權(quán)限。如果已經(jīng)授權(quán),就直接調(diào)用定位程序。

int checkPermission = ContextCompat.checkSelfPermission(LocationActivity.this,

Manifest.permission.ACCESS_FINE_LOCATION);

if (checkPermission != PackageManager.PERMISSION_GRANTED) {

ActivityCompat.requestPermissions(LocationActivity.this, new String[]{

Manifest.permission.ACCESS_FINE_LOCATION }, 1);

} else {

position();

}

通過getSystemService得到位置管理器對象。調(diào)用LocationManager的getProviders 函數(shù)獲取所有可用的位置提供器,然后判斷GPS是否打開,如果無法使用GPS,則看看是否能通過網(wǎng)絡(luò)來定位。

locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

List providerList = locationManager.getProviders(true);

if (providerList.contains(LocationManager.GPS_PROVIDER)) {

provider = LocationManager.GPS_PROVIDER;

} else if (providerList.contains(LocationManager.NETWORK_PROVIDER)) {

provider = locationManager.NETWORK_PROVIDER;

} else {

Toast.makeText(this, “無法提供位置信息”, Toast.LENGTH_SHORT).show();

return;

}

通過LocationManager的getLastKnownLocation函數(shù)獲得最近的位置信息,同時在界面上更新當(dāng)前的位置。雖然獲取了當(dāng)前的位置信息,但是用戶可能會隨時移動,怎樣才能在位置改變的時候獲取最新的位置信息呢?LocationManager 提供了請求定位更新函數(shù)requestLocationUpdates,它的第二個參數(shù)表示監(jiān)聽位置變化的時間間隔;第三個參數(shù)表示監(jiān)聽位置變化的距離間隔;第四個參數(shù)是位置監(jiān)聽器對象。

Location location = locationManager.getLastKnownLocation(provider);

if (location != null) {

? updateLocation(location);

}

locationManager.requestLocationUpdates(provider, 1000, 1, locationListener);

其中,“1000”表示監(jiān)聽位置變化的時間間隔以毫秒為單位,“1”表示監(jiān)聽位置變化的距離間隔以米為單位。

位置更新代碼是在界面上顯示經(jīng)緯度信息。

private void updateLocation(Location location) {

if (location == null) {

? return;

}

String currentPosition = “GPS 定位:” + “\n”

? + " 經(jīng)度: " + location.getLongitude() + “\n”

? + " 緯度: " + location.getLatitude();

locationTextView.setText(currentPosition);

}

創(chuàng)建位置監(jiān)聽器,監(jiān)聽位置的變化,一旦監(jiān)聽時間間隔和距離間隔發(fā)生改變就調(diào)用updateLocation函數(shù),來更新位置。

LocationListener locationListener = new LocationListener() {

@Override

public void onStatusChanged(String provider, int status, Bundle extras) { }

@Override

public void onProviderEnabled(String provider) { }

@Override

public void onProviderDisabled(String provider) { }

@Override

public void onLocationChanged(Location location) {

? updateLocation(location);

}

};

注意:在銷毀函數(shù)中,要移除位置監(jiān)聽器。

@Override

protected void onDestroy() {

super.onDestroy();

if (locationManager != null) {

? locationManager.removeUpdates(locationListener);

}

}

通過GPS確定經(jīng)緯度以后,還需要結(jié)合電子地圖才能知道自己當(dāng)前所在的位置。很多電子地圖軟件提供了定位和導(dǎo)航功能,比如百度地圖就提供了Android定位的SDK庫。通常第三方的定位庫還提供基站、WiFi、地磁、藍(lán)牙、傳感器等多種定位方式,適用于室內(nèi)、室外等多種定位場景;并且它們都有出色的定位性能,具有定位精度高、覆蓋范圍廣、定位流量小、定位速度快等特點。如果要使用第三方定位服務(wù),還需要申請定位API Key,很多公司提供了定位API的接口說明,可以直接在網(wǎng)上查閱相關(guān)的資料。

在MapActivity中,放置多個控件顯示當(dāng)前位置的經(jīng)度和緯度,可以選擇手工定位和GPS定位,設(shè)置目標(biāo)地以后,點擊按鈕可以實現(xiàn)路徑規(guī)劃功能,地圖上是一個切換按鈕可以切換顯示普通地圖和衛(wèi)星地圖。在應(yīng)用中,使用高德地圖實現(xiàn)位置服務(wù)功能。

首先要去高德開放平臺注冊成為開發(fā)者(http://lbs.amap.com/), 注冊成為高德開發(fā)者需要分三步:第一步,注冊高德開發(fā)者;第二步,去控制臺創(chuàng)建應(yīng)用;第三步,獲取使用API函數(shù)的Key。

MapActivity實現(xiàn)OnClickListener監(jiān)聽器,用來處理按鈕的點擊事件,OnGeocodeSearchListener是地理編碼搜索監(jiān)聽器,OnRouteSearchListener是路由搜索監(jiān)聽器,它們用來定位和路徑規(guī)劃;接下來,定義位置管理器等多個對象。

public class MapActivity extends AppCompatActivity
implements View.OnClickListener,
OnGeocodeSearchListener, OnRouteSearchListener {

   private MapView mapView;
   private AMap aMap;
   private LocationManager locationManager;

   *//* *導(dǎo)航**

* private Button btnNavigation;
private GeocodeSearch geocodeSearch;
private RouteSearch routeSearch;
private EditText editTextAddress;
private String province = “四川”;

@Override
protected void onCreate(Bundle savedInstanceState) {

? … …
? mapView = findViewById(R.id.map);
? // *必須回調(diào)MapView的**onCreate()方法
* mapView.onCreate(savedInstanceState);
? init();

? ToggleButton tb = findViewById(R.id.tb);
? tb.setOnCheckedChangeListener(

new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,

? boolean isChecked) {
? if (isChecked) { *
* aMap.setMapType(AMap.MAP_TYPE_SATELLITE);
? } else {
? aMap.setMapType(AMap.MAP_TYPE_NORMAL);

} } });

onCreate函數(shù),獲取定位管理器,為GPS單選按鈕設(shè)置監(jiān)聽器,如果RadioButton選擇GPS定位,則通過監(jiān)聽器監(jiān)聽GPS提供的定位信息的改變。requestLocationUpdates函數(shù)的第一個參數(shù)是定位方式,第二個參數(shù)是定位更新的最小時間間隔(毫秒),第三個參數(shù)是定位更新的最小距離(米),第四個參數(shù)是定位監(jiān)聽器,接下來實現(xiàn)監(jiān)聽代碼。

locationManager = (LocationManager) getSystemService(
Context.LOCATION_SERVICE);

RadioButton rb = findViewById(R.id.radio_btn_gps);*
* rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView
, boolean isChecked) {
*
* if (isChecked) { *
* locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
300, 8, new LocationListener() {

@Override
public void onLocationChanged(Location loc) { *
* updatePosition(loc);
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) { }

@Override
public void onProviderEnabled(String provider) {*

* updatePosition(locationManager.getLastKnownLocation(provider));
}

@Override
public void onProviderDisabled(String provider) { }

});

當(dāng)位置改變時,將觸發(fā)onLocationChanged函數(shù),調(diào)用updatePosition函數(shù),根據(jù)GPS提供的定位信息來更新位置

(3) 視頻播放

在Android系統(tǒng)中,有三種實現(xiàn)視頻播放的方式:(1)使用系統(tǒng)自帶的播放器,并且將intent的action指定為ACTION_VIEW,Data指定為Uri,Type指定為媒體的MIME類型。(2)使用VideoView控件來播放視頻。在布局文件中設(shè)置VideoView控件,然后編寫視頻播放控制函數(shù)來控制播放。(3)使用系統(tǒng)的MediaPlayer類和SurfaceView控件來播放視頻。

下面用VideoView控件來實現(xiàn)一個簡易的視頻播放器。首先,創(chuàng)建視頻播放界面的布局文件,視頻播放要用到VideoView控件。注意:讀寫文件要申請授權(quán)。

<VideoView

android:id="@+id/video_view"

android:layout_width=“match_parent”

android:layout_height=“wrap_content” />

<LinearLayout

<Button

? android:text=“播放”

? android:onClick=“play”/>

可以在SD卡的根目錄下存放要播放的視頻文件。因為視頻文件存放在SD卡上,在MediaActivity中,要用getExternalStorageDirectory獲取外部存儲目錄。注意設(shè)置訪問權(quán)限:

如果需要設(shè)置動態(tài)權(quán)限,需要在MediaActivity中編寫運行時權(quán)限檢查代碼:

int checkPermission = ContextCompat.checkSelfPermission(MediaActivity.this,

? Manifest.permission.WRITE_EXTERNAL_STORAGE);

if (checkPermission != PackageManager.PERMISSION_GRANTED) {

ActivityCompat.requestPermissions(MediaActivity.this, new String[]{

? Manifest.permission.WRITE_EXTERNAL_STORAGE }, 1);

} else {

// 通過視頻文件名(絕對路徑)創(chuàng)建一個文件

File file = new File(Environment.getExternalStorageDirectory(), “Androidstudio.3gp”);

}

videoView.setVideoPath(file.getPath());

播放功能很簡單,在三個函數(shù)中分別調(diào)用控件的開始、暫停和恢復(fù)功能。

public void play(View view) {

if (!videoView.isPlaying()) {

? videoView.start();

}

}

public void pause(View view) {

if (videoView.isPlaying()) {

? videoView.pause();

}

}

public void resume(View view) {

if (videoView.isPlaying()) {

? videoView.resume();

}

}

難點

(1) 攝像頭拍照

Android智能手機都會提供照相功能,大部分手機的攝像頭都會支持光學(xué)變焦、曝光以及快門等功能。下面通過攝像頭實現(xiàn)拍照功能,并將拍攝的相片顯示在界面上。首先定義拍照方法,在啟動拍照之前先判斷內(nèi)存是否可用;然后通過重寫onActivityResult()方法,獲取拍好的圖片。

創(chuàng)建一個拍照的界面。包括一個按鈕和一個圖片視圖。

<LinearLayout

<Button

? android:id="@+id/take_picture"

? android:text=“拍照”

? android:textSize=“28sp”/>

<ImageView

? android:id="@+id/picture"

/>

在拍照之前,先創(chuàng)建照片的存儲文件。在緩存目錄中存儲。

takePicture.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

? File savePicture = new File(getExternalCacheDir(), “MyPicture.jpg”);

? try {

? if (savePicture.exists()) {

? savePicture.delete();

? }

? savePicture.createNewFile();

? } catch (IOException e) {

? e.printStackTrace();

? }

}

如果SDK的版本是Android 7.0以上,調(diào)用FileProvider的getUriForFile 函數(shù)將File對象轉(zhuǎn)換成一個封裝的Uri 對象。FileProvider的第二個參數(shù)是一個唯一性字符串,第三個參數(shù)是剛剛創(chuàng)建的用來存儲照片的文件對象。

如果版本低于Android 7.0,調(diào)用Uri的fromFile 函數(shù)將直接將文件對象轉(zhuǎn)成Uri對象,Uri指示照片的本地路徑。然后用Intent啟動攝像頭,拍照的action為:android.media.action.IMAGE_CAPTURE。把拍照后的輸出地址也存入Intent,然后打開拍攝界面。用戶在拍完照片后,會把照片輸出到指定的MyPicture.jpg中。

if (Build.VERSION.SDK_INT >= 24) {

picUri = FileProvider.getUriForFile(CameraActivity.this,

? “pers.cnzdy.tutorial.fileprovider”, savePicture);

} else {

picUri = Uri.fromFile(savePicture);

}

Intent Intent = new Intent(“android.media.action.IMAGE_CAPTURE”);

Intent.putExtra(MediaStore.EXTRA_OUTPUT, picUri);

startActivityForResult(Intent, TAKE_PICTURE);

拍照完成以后,結(jié)果將返回onActivityResult函數(shù)。如果成功(resultCode = RESULT_OK),就解析出圖片,顯示在界面上。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case TAKE_PICTURE:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(
getContentResolver().openInputStream(picUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}

FileProvider是 Android 7.0 新增的一個類,繼承自ContentProvider,因此需要在配置文件AndroidManifest中進(jìn)行注冊。注意android:authorities的屬性值和調(diào)用FileProvider的getUriForFile函數(shù)的第二個參數(shù)要一致。

<provider

android:name=“android.support.v4.content.FileProvider”

android:authorities=“pers.cnzdy.tutorial.fileprovider”

android:exported=“false”

android:grantUriPermissions=“true”>

<meta-data

? android:name=“android.support.FILE_PROVIDER_PATHS”

? android:resource="@xml/file_provider_paths" />

用來指定Uri的共享路徑,file_provider_paths是一個xml文件,需要創(chuàng)建。在res目錄下,創(chuàng)建一個xml目錄,然后在目錄上點擊鼠標(biāo)右鍵,選擇New—File,創(chuàng)建file_provider_paths.xml文件,xml文件的內(nèi)容如下:

<?xml version="1.0" encoding="utf-8"?>

? ](http://schemas.android.com/apk/res/android)

?

file_provider_paths.xml文件的標(biāo)簽用來指定Uri共享,name屬性設(shè)定為“my_pictures”,path屬性表示共享的路徑位置,設(shè)置空值就表示將整個SD卡進(jìn)行共享,也可以設(shè)置為只共享存放MyPicture.jpg這張照片的路徑。

(2) 音樂播放器

在Android系統(tǒng)中,提供了多種播放音頻的方式,包括:SoundPool、MediaPlayer、AudioTrack、Ringtone等等。

SoundPool用于管理和播放應(yīng)用程序的音頻資源,主要用于播放時間短,延遲小的聲音。它支持多個音頻文件同時播放,占用的資源較少,適合播放按鍵音、消息提示音等短促音效的場景。

MediaPlayer是Android內(nèi)置的多媒體播放類,在android.media.MediaPlayer包中,它包含了音頻和視頻播放功能。MediaPlayer適用于播放時間較長,延遲要求不高,能全面控制和操作播放過程的情況。MediaPlayer能播放多種格式的聲音文件,比如MP3、AAC、WAV、OGG、MIDI等等。

AudioTrack實現(xiàn)PCM(Pulse Code Modulation)音頻流的回放,是更底層的音頻播放方式。AudioTrack支持流式播放,可讀取本地和網(wǎng)絡(luò)音頻流。相比于MediaPlayer,它更加高效,適用于實時播放音頻的場景,如加密音頻播放。AudioTrack只能播放已經(jīng)解碼的PCM流,如果要播放其它格式的音頻文件,需要相應(yīng)的解碼器。

AsyncPlayer對MediaPlayer進(jìn)行封裝,提供了異步音頻播放功能。由于播放等操作都在新線程中執(zhí)行,不會阻塞UI線程。AsyncPlayer適用于異步播放,不需要復(fù)雜控制。

Ringtone提供鈴聲、提示音等系統(tǒng)類聲音的播放功能。另外,RingtoneManager管理鈴聲數(shù)據(jù)庫,包括:來電鈴聲(TYPE_RINGTONE)、提示音(TYPE_NOTIFICATION)、鬧鐘鈴聲(TYPE_ALARM)等。通常Ringtone類和RingtoneManager類在一起使用。

下面構(gòu)造一個音樂播放器,實現(xiàn)音樂播放、上一曲、下一曲、開始/暫停、拖動進(jìn)度條實現(xiàn)快進(jìn)和快退等功能。

布局文件activity_music_player.xml采用LinearLayer布局,加入ListView,隨后再加入進(jìn)度條控件SeekBar。

<SeekBar

? android:id="@+id/sb"

? android:layout_width=“match_parent”

? android:layout_height=“40dp”

? android:maxHeight=“4dp”

? android:minHeight=“4dp”

? android:paddingBottom=“4dp”

? android:paddingLeft=“14dp”

? android:max=“240”

? android:paddingRight=“14dp”

? android:paddingTop=“4dp” />

接下來添加四個按鈕:上一首、開始播放、暫停和下一首。

<Button

android:id="@+id/btn_last"

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“下一首”/>

… … … …

在MusicPlayerActivity類中聲明對應(yīng)的變量,并完成初始化。

public class MusicPlayerActivity extends AppCompatActivity implements Runnable {

boolean firstplay = true;

private Button btnStart, btnStop, btnNext, btnLast;

private ListView listView;

// 顯示當(dāng)前播放音樂的名稱、播放的時間、以及歌曲長度

private TextView music_Info;

private SeekBar seekBar;

private MusicPlayerService musicService = new MusicPlayerService();

? @Override

protected void onCreate(Bundle savedInstanceState) {

? super.onCreate(savedInstanceState);

? setContentView(R.layout.activity_music_player);

?

btnStart = (Button) findViewById(R.id.btn_star);

? btnStart.setOnClickListener(new View.OnClickListener() {

? @Override

? public void onClick(View view) {

? try {

? if (firstplay) {

? musicService.play();

? firstplay = false;

? } else {

? if (!musicService.player.isPlaying()) {

? musicService.goPlay();

? } else if (musicService.player.isPlaying()) {

? musicService.pause();

? }

? }

? } catch (Exception e) {

? Log.i(“TAG”, “音樂播放異常!”);

? }

? }

? });

btnStop = (Button) findViewById(R.id.btn_stop);

? btnStop.setOnClickListener(new View.OnClickListener() {

? @Override

? public void onClick(View view) {

? try {

? musicService.stop();

? firstplay = true;

? seekBar.setProgress(0);

? txtInfo.setText(“暫停已經(jīng)停止”);

? } catch (Exception e) {

? Log.i(“LAT”, “暫停異常!”);

? }

? }

? });

? … …

}

}

“上一首”和“下一首”功能的代碼類似,都是調(diào)用MusicService中的對應(yīng)函數(shù),具體實現(xiàn)可自行補全。接下來實現(xiàn)進(jìn)度條功能:

(1)當(dāng)拖動進(jìn)度條時,從拖動位置開始播放音樂;

(2)根據(jù)音樂的播放進(jìn)度顯示當(dāng)前已播放時間。

music_Info = (TextView) findViewById(R.id.textView_music_info);

seekBar = (SeekBar) findViewById(R.id.sb);

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

@Override

// SeekBar進(jìn)度值發(fā)送改變

public void onProgressChanged(SeekBar seekBar, int i, boolean b) { }

@Override

// 開始拖動SeekBar

public void onStartTrackingTouch(SeekBar seekBar) { }

@Override

// SeekBar停止拖動

public void onStopTrackingTouch(SeekBar seekBar) {

? int progress = seekBar.getProgress();

? int musicMax = musicService.player.getDuration(); //歌曲播放時間

? int seekBarMax = seekBar.getMax();

? // 從停止處開始播放音樂

? musicService.player.seekTo(musicMax * progress / seekBarMax);

}

});

MusicPlayerService類還要實現(xiàn)播放、恢復(fù)播放、獲取當(dāng)前進(jìn)度、上一首、下一首、暫停和停止功能。

public void play() {
try {
player.reset();
String dataSource = musicList.get(musicId); // 獲取當(dāng)前播放音樂的路徑
setPlayName(dataSource); // 設(shè)置 musicName

 player.setAudioStreamType(AudioManager.STREAM_MUSIC);
 player.setDataSource(dataSource); // 設(shè)置播放路徑
 player.prepare();
 player.start();

 player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
   public void onCompletion(MediaPlayer arg0) {
     next(); // 歌曲播放完畢,自動播放下一首
   }
 });

} catch (Exception e) {
Log.v(“TAG”, e.getMessage());
}
}
// 繼續(xù)播放
public void resume(){
int position = getCurrentProgress();
player.seekTo(position); // 恢復(fù)當(dāng)前播放位置
try {
player.prepare();
} catch (Exception e) {
e.printStackTrace();
}
player.start();
}

public int getCurrentProgress() {
if (player != null & player.isPlaying()) {
return player.getCurrentPosition();
} else if (player != null & (!player.isPlaying())) {
return player.getCurrentPosition();
}
return 0;
}

public void next() {
musicId = musicId == musicList.size() - 1 ? 0 : musicId + 1;
play();
}

public void last() {
musicId = musicId == 0 ? musicList.size() - 1 : musicId - 1;
play();
}

// 暫停播放
public void pause() {
if (player != null && player.isPlaying()){
player.pause();
}
}

public void stop() {
if (player != null && player.isPlaying()) {
player.stop();
player.reset();
}
}

在AndroidManifest文件中配置服務(wù)。

3)質(zhì)感界面設(shè)計

“置于用戶控制之下”、“保持界面的一致性”和“減輕用戶的記憶負(fù)擔(dān)”,通常稱之為界面設(shè)計的“黃金三原則”。置于用戶控制之下要求不強迫用戶完成操作步驟,允許交互的中斷和撤消。界面要保持清晰一致便于用戶理解和使用。另外,由于人的短期記憶非常不穩(wěn)定,因此對用戶來說瀏覽比記憶更容易。

現(xiàn)在手機已經(jīng)不僅僅是一個通話設(shè)備,它能夠感知環(huán)境,提供各種智能化的服務(wù)。移動設(shè)備能夠持續(xù)收集來自GPS、攝像頭、麥克風(fēng)和其它傳感器的數(shù)據(jù),并且通過這些數(shù)據(jù)感知環(huán)境的變化,然后作出反應(yīng),比如手機上的GPS、陀螺儀、氣壓計、麥克風(fēng),能跟蹤用戶的位置、方向,了解用戶的各種信息,從而識別當(dāng)前用戶的狀態(tài)。

2014年6月25日在Google I/O大會上宣布了新的Android界面設(shè)計——Material Design(質(zhì)感設(shè)計)。Material Design要求交互和界面視覺更符合現(xiàn)實世界的物理反饋法則,比如一個小球下落,在真實世界中是一個加速的過程,如果在Android界面上顯示小球下落的動畫,也要有類似現(xiàn)實世界的感覺。質(zhì)感設(shè)計關(guān)心界面上實體的光效、表面質(zhì)感、運動感、實體感、層次、深度、與其他物體的疊放邏輯、動態(tài)效果、以及空間合理化利用等等。質(zhì)感設(shè)計就像把交互界面變成了一張張的卡片。利用質(zhì)感設(shè)計的API 接口,可以用來設(shè)計自己的具有Material Design的交互界面。

在界面上,菜單選項不顯示在主屏幕上,而是通過滑動的方式將隱藏的菜單顯示出來。滑動菜單只在需要的時候顯示,節(jié)省了屏幕空間。實現(xiàn)滑動菜單需要用到DrawerLayout布局。DrawerLayout分為側(cè)邊菜單和主內(nèi)容區(qū)兩部分,側(cè)邊菜單提供滑動的展開與隱藏功能;主內(nèi)容區(qū)用來設(shè)置菜單項,比如用ListView顯示菜單項,它由開發(fā)者實現(xiàn)。

創(chuàng)建MaterialDesignActivity,在它的布局文件activity_material_design.xml中使用DrawerLayout布局。

<?xml version="1.0" encoding="utf-8"?>
 <android.support.v4.widget.DrawerLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:id="@+id/slide_menu_drawer_layout"
   android:layout_width="match_parent"
   android:layout_height="match_parent" >
 
   <FrameLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent" >
     <android.support.v7.widget.Toolbar
       android:id="@+id/toolbar"
       android:layout_width="match_parent"
       android:layout_height="?attr/actionBarSize"
       android:background="?attr/colorPrimary"
       android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
       app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
     </android.support.v7.widget.Toolbar>
   </FrameLayout>  
<ImageView
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_centerInParent="true"
   android:layout_gravity="start"
   android:src="@drawable/slide_bird"
   android:background="#FFF"/>


 </android.support.v4.widget.DrawerLayout>

在DrawerLayout中放置兩個控件。第一個控件是Toolbar,它放在FrameLayout布局中,作為主屏幕中顯示的內(nèi)容(主內(nèi)容區(qū))。第二個控件放置一個ImageView控件,作為滑動菜單(側(cè)邊菜單)顯示的內(nèi)容,當(dāng)然也可以使用其他控件。注意:主內(nèi)容區(qū)的布局代碼要放在側(cè)滑菜單布局代碼的前面,以便DrawerLayout能夠判斷哪個控件是側(cè)滑菜單,哪個控件是主內(nèi)容區(qū)。

在設(shè)置側(cè)邊菜單時,要注意設(shè)置控件的layout_gravity屬性,也就是必須告訴DrawerLayout滑動菜單是在屏幕的左邊還是右邊,指定left表示在左邊,指定right表示在右邊,如果指定了start,表示根據(jù)系統(tǒng)語言自動判斷。英語、漢語等從左到右顯示的語言,滑動菜單在左邊;阿拉伯語等從右到左的語言,滑動菜單就在右邊。

DrawerLayout側(cè)邊菜單的展開與隱藏事件通過DrawerLayout.DrawerListener來監(jiān)聽。當(dāng)觸發(fā)菜單展開與隱藏事件,可以更新Toolbar菜單或進(jìn)行其他操作。

下面在MaterialDesignActivity中添加代碼實現(xiàn)滑動菜單:

public class MaterialDesignActivity extends AppCompatActivity {
private DrawerLayout slideMenuDrawerLayout;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_material_design);

 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
 setSupportActionBar(toolbar);

 slideMenuDrawerLayout = (DrawerLayout)

findViewById(R.id.slide_menu_drawer_layout);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {

// 顯示actionBar上的導(dǎo)航按鈕
actionBar.setDisplayHomeAsUpEnabled(true);

// 在actionBar上設(shè)置導(dǎo)航按鈕圖標(biāo)
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
}
}

public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
slideMenuDrawerLayout.openDrawer(GravityCompat.START);
case R.id.search:
Toast.makeText(this, “搜索”, Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, “刪除”, Toast.LENGTH_SHORT).show();
break;
case R.id.add:
Toast.makeText(this, “增加”, Toast.LENGTH_SHORT).show();
default:
}
return true;
}
}

通常情況下滑動菜單隱藏起來,為了讓用戶知道應(yīng)用軟件有滑動菜單功能,需要提供一個提示讓用戶知道。在界面上,通過ActionBar的導(dǎo)航按鈕來提示用戶。ActionBar由Toolbar實現(xiàn)。

通過以上代碼實現(xiàn)了滑動菜單功能。作為Material Design的一種設(shè)計,滑動菜單為移動應(yīng)用的開發(fā)者提供了很好的設(shè)計理念。只要遵循Material Design的各種規(guī)范和建議來構(gòu)造應(yīng)用系統(tǒng),最終將創(chuàng)建統(tǒng)一、美觀的應(yīng)用界面。

(4) 藍(lán)牙

Android系統(tǒng)中使用藍(lán)牙設(shè)備的基本工作流程,首先,要申請藍(lán)牙設(shè)備的使用權(quán)限,獲得BluetoothAdapter對象,判斷當(dāng)前設(shè)備中是否擁有藍(lán)牙設(shè)備;判斷當(dāng)前設(shè)備中的藍(lán)牙設(shè)備是否已經(jīng)打開;通過掃描獲取周圍的藍(lán)牙設(shè)備對象。

BluetoothActivity實現(xiàn)了多個接口包括:視圖監(jiān)聽器,AdapterView,CompoundButton改變狀態(tài)按鈕的監(jiān)聽器,checkBox控件用來開啟和關(guān)閉藍(lán)牙設(shè)備的事件監(jiān)聽器,藍(lán)牙連接監(jiān)聽器,藍(lán)牙接收監(jiān)聽器。BluetoothAdapter類可以對藍(lán)牙進(jìn)行基本操作,比如:啟動設(shè)備發(fā)現(xiàn)(startDiscovery), 獲取已配對設(shè)備(getBoundedDevices), 通過mac藍(lán)牙地址獲取藍(lán)牙設(shè)備(getRemoteDevice), 從其它設(shè)備創(chuàng)建一個監(jiān)聽連接等等。最后,藍(lán)牙列表對象用來保存掃描到的藍(lán)牙設(shè)備。

public class BluetoothActivity extends AppCompatActivity implements
View.OnClickListener, AdapterView.OnItemClickListener,
CompoundButton.OnCheckedChangeListener,
BluetoothConnectTask.BlueConnectListener,
InputDialogFragment.InputCallbacks,
BluetoothAcceptTask.BlueAcceptListener {
private static final String TAG = “BluetoothActivity”;

private CheckBox checkBox;
private TextView textView;
private ListView listView;
private BluetoothAdapter bluetoothAdapter;
private ArrayList bluetoothList =

? new ArrayList();

在onCreate函數(shù)中,首先,調(diào)用自定義BluetoothTool類的getBlueToothStatus函數(shù)判斷藍(lán)牙設(shè)備是否開啟,同時設(shè)置checkbox的狀態(tài),接著,調(diào)用藍(lán)牙適配器的getDefaultAdapter函數(shù)獲取本機藍(lán)牙設(shè)備。

@Override
protected void onCreate(Bundle savedInstanceState) {
… …
if (BluetoothTool.getBlueToothStatus(this) == true) {
checkBox.setChecked(true); }

checkBox.setOnCheckedChangeListener(this);
textView.setOnClickListener(this);

bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Toast.makeText(this, “本機未找到藍(lán)牙功能”,

? Toast.LENGTH_SHORT).show();
? finish();
} }

實現(xiàn)checkBox的onCheckedChanged方法,如果checkbox開啟,則調(diào)用beginDiscovery函數(shù)開始掃描藍(lán)牙設(shè)備,并通過intent啟動藍(lán)牙設(shè)備設(shè)置界面,修改藍(lán)牙設(shè)備的可見性,Intent的動作ACTION_REQUEST_DISCOVERABLE 表示請求用戶選擇是否使該藍(lán)牙設(shè)備能被發(fā)現(xiàn)(掃描);如果checkbox關(guān)閉,則取消掃描,并且設(shè)置藍(lán)牙的狀態(tài),清理藍(lán)牙列表,同時清理界面上ListView控件顯示的藍(lán)牙設(shè)備。

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.getId() == R.id.check_box_bluetooth) {
if (isChecked == true) {
beginDiscovery();
Intent intent = new Intent(

BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(intent, 1);*
* } else {
cancelDiscovery();
BluetoothTool.setBlueToothStatus(this, false);
bluetoothList.clear();
BluetoothListAdapter adapter = new BluetoothListAdapter(this, bluetoothList);
listView.setAdapter(adapter);
}
}
}

發(fā)現(xiàn)(掃描)藍(lán)牙函數(shù),首先清理藍(lán)牙列表,通過藍(lán)牙列表適配器將藍(lán)牙設(shè)備列表與ListView控件關(guān)聯(lián)起來,然后,調(diào)用bluetoothAdapter的startDiscovery開始掃描設(shè)備。取消發(fā)現(xiàn)(掃描)函數(shù),從handler中取消刷新回調(diào),并通過bluetoothAdapter對象取消發(fā)現(xiàn)操作。

private void beginDiscovery() {
if (bluetoothAdapter.isDiscovering() != true) {
bluetoothList.clear();
BluetoothListAdapter adapter = new BluetoothListAdapter(
BluetoothActivity.this, bluetoothList);
listView.setAdapter(adapter);
textView.setText(“正在搜索藍(lán)牙設(shè)備”);
bluetoothAdapter.startDiscovery();
}
}

private void cancelDiscovery() {
handler.removeCallbacks(refresh);
textView.setText(“取消搜索藍(lán)牙設(shè)備”);
if (bluetoothAdapter.isDiscovering() == true) {
bluetoothAdapter.cancelDiscovery();
}
}

本章習(xí)題:

1**、本單元考核點**

各種傳感器的基本概念和使用方法。

Android系統(tǒng)中GPS的定位方法。

Android系統(tǒng)音視頻播放的使用方法。

使用攝像頭實現(xiàn)拍照功能。

界面設(shè)計原則、用戶體驗設(shè)計和質(zhì)感設(shè)計(Material Design)。

2**、本單元課后習(xí)題**

1、說明SoundPool與MediaPlayer的區(qū)別,以及在什么情況下使用SoundPool。
答案:在Android開發(fā)中經(jīng)常使用MediaPlayer來播放音頻文件,但是MediaPlayer存在一些不足:資源占用量較高、延遲時間較長、不支持多個音頻同時播放等。這些缺點決定了MediaPlayer在某些場合的使用情況不會很理想,例如在對時間精準(zhǔn)度要求相對較高的游戲開發(fā)中。在游戲開發(fā)中,經(jīng)常需要播放一些游戲音效(比如:子彈爆炸,物體撞擊等),這些音效的共同特點是短促、密集、延遲程度小。在這樣的場景下,可以使用SoundPool代替MediaPlayer來播放這些音效。
MediaPlayer:占用資源較高,不支持同時播放多個音頻。
SoundPool:可以同時播放多個短促的音頻,而且占用的資源較少。適合在程序中播放按鍵音,或者消息提示音等。
3、。什么是ANR,如何避免它?
答案:ANR(Application Not Responding)是指程序不響應(yīng),在用戶使用過程中,應(yīng)用程序有一段時間響應(yīng)不夠靈敏,系統(tǒng)會向用戶顯示一個對話框,這個對話框稱作應(yīng)用程序無響應(yīng)的對話框。
避免ANR: Android應(yīng)用程序通常運行在一個單獨的線程里面,稱謂主線程,所以在主線程里面少做一些耗時長的程序,而是利用子線程來操作一些繁瑣的事情,用Handler來把子線程處理的消息返回給主線程。

參考資源:

1、GitHub:https://github.com

2、劉望舒著.Android進(jìn)階之光.北京:電子工業(yè)出版社,2017.

原創(chuàng)聲明

=======

作者: [ libin9iOak ]


本文為原創(chuàng)文章,版權(quán)歸作者所有。未經(jīng)許可,禁止轉(zhuǎn)載、復(fù)制或引用。

作者保證信息真實可靠,但不對準(zhǔn)確性和完整性承擔(dān)責(zé)任。

未經(jīng)許可,禁止商業(yè)用途。

如有疑問或建議,請聯(lián)系作者。

感謝您的支持與尊重。

點擊下方名片,加入IT技術(shù)核心學(xué)習(xí)團隊。一起探索科技的未來,共同成長。文章來源地址http://www.zghlxwxcb.cn/news/detail-516350.html

到了這里,關(guān)于《移動互聯(lián)網(wǎng)技術(shù)》第九章 感知與多媒體: 了解質(zhì)感設(shè)計的基本原則和設(shè)計方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包