當前位置:首頁 » 安卓系統 » android實驗

android實驗

發布時間: 2023-02-26 21:56:51

Ⅰ android怎麼用流 讀取雲端圖片

java 直接用BitmapFactory.decodeFile(pathName);就可以讀取。
或者用你的方式,BitmapFactory.decodeStream(fosfrom);
SE的學習過程中,我們就接觸到了I/O流的概念,並且使用了一些文件輸入輸出流的API來將數據保存到文件或者是從文件中讀取數據。同樣,這個手段也適用於Android系統,我們可以在應用開發過程中使用文件相關的API方法。

何謂內部存儲呢?實際上就是指將程序的私有數據以文件的形式存儲在Android設備的內存中。同理,如果是存放在SD卡等地方,就稱之為外部存儲。

我們在,你需要建立文件的輸入輸出流,並在流中操作數據。

首先是寫文件。
為了使用內部存儲向文件中寫入一些數據,你可以調用openFileOutput()方法,需要的參數為文件名和寫入模式。寫入模式實際上就是該文件的許可權歸屬,可以是公有的,也可以是私有的。如何具體地創建一個文件輸出流呢,具體方式如下:

FileOutputStream fileOut =
openFileOutput("file_name",MODE_WORLD_READABLE);

//第一個參數即文件名,第二個參數表示文件存儲的模式

對於第二個參數,需要補充的是:文件存儲的模式公有四種:

MODE_PRIVATE:該模式是默認的,通過該模式創建的文件是私有的,即只能被應用本身訪問。注意:在該模式下寫入的內容會覆蓋原有的內容。

MODE_APPEND:與上個模式類似,但在寫入內容時會檢查待創建的文件是否存在。若文件已被創建,則往該文件中追加內容,而不是覆蓋原來的內容;若文件未被創建,則創建新的文件。

MODE_WORLD_READABLE:表示當前創建的這個文件允許被其他應用讀取。

MODE_WORLD_WRITEABLE:表示當前創建的這個文件允許被其他應用寫入。

默認情況下,不僅是應用創建的文件,包括Shared
Preferences和資料庫,都是私有的。那麼問題來了,如果希望其他應用既能讀又能寫,應該怎麼辦呢?參考下面這種用法:

FileOutputStream fileOut = openFileOutput("file_name",MODE_WORLD_READABLE +
MODE_WORLD_WRITEABLE);

而對於openFileOutput()方法,它返回的是一個FileOutputStream實例。換言之,你通過文件輸出流對象中得到了這個實例,隨後你便可以調用寫相關的方法來向文件寫入數據。具體的用法如下:

String str = "shiyanlou";

//待寫入的數據

fOut.write(str.getBytes());

//實際上寫入文件的是一個位元組數組,我們用gettBytes()方法將其轉換成目標格式

fOut.close();

//記得寫入完畢後要用close()結束

接下來是讀文件。
怎樣讀取我們剛剛創建的這個文件呢?你應該猜到了,是使用openFileInput()方法。該方法需要填入待讀取文件的文件名,同樣,它返回的是一個FileInputStream的實例。具體用法如下:

FileInputStream fileIn = openFileInput(file);

在打開輸入流後,你可以調用read()方法每次從文件中讀出一個字元出來,然後裝入一個字元串變數中。具體做法如下:

int ch;

String temp="";

while( (ch = fin.read()) != -1){

temp = temp + Character.toString((char)ch);

//不斷地追加讀取的內容

}

//通過一個for循環,你最後得到的temp字元串包含了文件中的所有數據

fileIn.close();

//記得要關閉輸入流

除了上面我們用到的這些方法(比如write()、read()和close()),FileOutputStream和FileInputStream類中還有很多常用的方法,我們在下面作一簡要介紹。

FileOutputStream類中的其它常用方法:

write(byte[] b, int off, int len):該方法從指定的位元組數組開始到該文件輸出流關閉寫入len位元組。

getChannel():該方法返回一個只讀的、與文件輸出流關聯的文件通道對象(FileChannel)

getFD():該方法返回與此流有關的文件描述符對象(FileDescriptor)

FileInputStream類中的其它常用方法:

read(byte[] b, int off, int len):該方法從輸入流中數據讀取最多len個位元組到位元組數組

getChannel():該方法返回一個只讀的、與文件輸出流關聯的文件通道對象(FileChannel)

getFD():該方法返回與此流有關的文件描述符對象(FileDescriptor)

available():該方法可通過一個方法的調用者從輸入流中阻止這個輸入流返回可以讀取(或跳過)的位元組數的估計值。

四、在Android上實現文件讀寫

下面我們通過一個實例來學習如何將Java中常用的文件讀寫沿用到Android中去。

實驗步驟主要有:

(若你已在第二小節完成,請跳至下一步)使用Android
Studio創建應用項目FileIOPractice,包名為com.shiyanlou.android.fileiopractice,基於Android
5.1製作。同時添加MainActivity及其布局資源文件。

創建並打開AVD模擬器(鏡像選擇API22:Android 5.1.1)。

在res/layout/activity_main.xml資源文件放入一些文本框和按鈕。

在MainActivity.java中,初始化要用到的控制項,添加文件讀寫相關的代碼。

編譯並運行這個應用,等待應用安裝至模擬器,在模擬器中使用該應用。

現在你可以按照上述步驟自己完成該實驗。下面也給出了本實驗涉及到的源代碼和資源文件詳情,在必要時你可以使用它們。在注釋中我們也對一些模塊進行了詳細的講解。

以下是MainActivity的布局文件res/layout/activity_main.xml:

xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"

android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/textview_domain"

android:text="Shiyanlou.com"

android:textSize="40dp"

android:textColor="#11AA8C"

android:layout_alignParentTop="true"

android:layout_centerHorizontal="true" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/textView_appName"

android:text="File I/O Practice"

android:layout_below="@+id/textview_domain"

android:layout_centerHorizontal="true"

android:textColor="#000000"

android:textSize="40dp" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/editText"

android:hint="Input some text here."

android:focusable="true"

android:layout_marginTop="20dp"

android:layout_below="@+id/textView_appName"

android:layout_alignEnd="@+id/textView_appName"

android:layout_alignLeft="@+id/textView_appName"

android:layout_alignStart="@+id/textView_appName"

android:layout_alignRight="@+id/textView_appName"

android:inputType="textMultiLine"

android:minLines="5"

android:background="#DDDDDD" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/textView_data"

android:text="Text would be shown here."

android:layout_below="@+id/button_save"

android:layout_marginTop="10dp"

android:layout_centerHorizontal="true" />

android:layout_width="120dp"

android:layout_height="wrap_content"

android:id="@+id/button_save"

android:text="Save File"

android:textColor="#FFFFFF"

android:background="#11AA8C"

android:layout_alignLeft="@+id/textView_appName"

android:layout_alignStart="@+id/textView_appName"

android:layout_below="@+id/editText"

android:layout_marginTop="20dp"/>

android:layout_width="120dp"

android:layout_height="wrap_content"

android:id="@+id/button_load"

android:text="Load File"

android:textColor="#FFFFFF"

android:background="#11AA8C"

android:layout_alignTop="@+id/button_save"

android:layout_alignRight="@+id/editText"

android:layout_alignEnd="@+id/editText" />

以下是src/MainActivity.java中的源代碼:

package com.shiyanlou.android.fileiopractice;

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

import android.widget.Toast;

import java.io.FileInputStream;

import java.io.FileOutputStream;

public class MainActivity extends Activity {

private Button button_save;

private Button button_load;

private TextView textView_status;

private EditText editText;

//聲明各個控制項

private String data;

private String file = "shiyanlou_file";

//聲明用於存放數據的變數data和文件名常量file

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

button_save =(Button)findViewById(R.id.button_save);

button_load =(Button)findViewById(R.id.button_load);

editText =(EditText)findViewById(R.id.editText);

textView_status =(TextView)findViewById(R.id.textView_data);

//實例化各個控制項

//為按鈕設置點擊事件監聽器

//首先是保存按鈕(寫操作)

button_save.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

data = editText.getText().toString();

//調用getText()方法從文本框中讀取內容,使用toString()方法將其轉化為String類型數據,並存放到data變數中

try {

//對於文件讀寫操作應使用異常處理流程

FileOutputStream fileOut = openFileOutput(file, MODE_APPEND);

// 此處用到了MODE_PRIVATE,在新版本的Android系統中,不推薦使用MODE_WORLD_READABLE等模式

// 這是因為Android中為應用間的數據交互提供了更好的支持,如Content Privoder等,你可一進步了解

fileOut.write(data.getBytes());

//用write()方法保存數據

fileOut.close();

//關閉輸出流

Toast.makeText(getBaseContext(), "File saving completed.",
Toast.LENGTH_SHORT).show();

//用一個Toast來告訴用戶已經寫入完畢了

} catch (Exception e) {

e.printStackTrace();

}

}

});

//其次是讀取按鈕(讀操作)

button_load.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

try {

//同理,建立文件輸入流

FileInputStream fileIn = openFileInput(file);

int ch;

//聲明一個整型變數ch用於接收數據

String tempText = "";

//這里的tempText用於臨時存放讀取的數據(字元串)

while ((ch = fileIn.read()) != -1) {

//這里的-1是特定的狀態碼,表示文件讀取結束

//在while循環中逐個讀取數據,並追加到tempText中

tempText = tempText + Character.toString((char) ch);

//將ch轉化為字元

}

textView_status.setText(tempText);

//讀取完畢後將文字顯示出來

Toast.makeText(getBaseContext(), "File reading completed.",
Toast.LENGTH_SHORT).show();

//同樣用一個Toast告知用戶已經讀取完成

} catch (Exception e) {

}

}

});

}

}

檢查一下代碼,編譯並運行該應用。在模擬器中嘗試輸入一些信息,保存一下,再試著讀取它們。

Ⅱ android推送保活實驗到結論

(以極光推送為例)

操作:從後台應用列表劃除應用
結果:只幹掉了UI進程,remote進程沒有幹掉。
所以推送服務正常運作。
重啟手機,推送服務正常運作。
判斷是,由於能夠捕獲到開機監聽,其他帶有極光SDK的應用做了開機自啟動,然後極光SDK再互相啟動手機里所有帶有極光SDK的服務。
於是自己的應用即使沒有做開機自啟動推送服務,推送服務也可以正常運作。極光SDK互相拉起。

操作:從後台應用列表劃除應用
結果:UI進程,remote進程都被幹掉了,所有包名下的服務都被幹掉,包括前台服務。乾乾凈凈。
開機監聽無法檢測到。
微信那些主流APP已經在小米白名單里,跟系統進程一樣開機就存在了。

操作:從後台應用列表劃除應用
結果:UI進程,remote進程都被幹掉了,所有包名下的服務都被幹掉,包括前台服務。乾乾凈凈。
開機監聽無法檢測到。
微信那些主流APP已經在小米白名單里,跟系統進程一樣開機就存在了。

除非能像微信、QQ等大牌應用獲取廠商支持,默認添加進白名單,否則其他應用在用戶主動殺死應用後(在後台應用列表中,滑動刪除應用),都無法存活,包括推送子進程。
當然,像NEXUS,LG,索尼這類不是本土品牌的手機,則可以存活,原因是本土廠商對手機系統做了嚴格的限制。你懂的,本土應用太過流氓,後台服務,互相保活,開機喚醒等各種騷操作使得手機性能急劇下降,為了提高用戶體驗,讓手機更具性價比,而為之。

在用戶沒有主動殺死應用的情況下,提高進程的優先順序,讓應用不被系統主動回收。進程參數oom_score_adj(oom_adj)標記了進程優先順序,數字越小優先順序越高,越難被系統回收。
前台進程>可見進程>服務進程>後台進程>空進程
如何提高進程優先順序可自行google

使用廠商自家的推送服務。
也就是說,你要支持華為用戶,那麼就接入華為推送;你要支持小米用戶,那麼就接入小米推送。
信鴿推送可以減少接入多個廠商的工作量,可以了解其SDK文檔。(截止目前,信鴿支持的第三方廠商,有華為、小米、魅族;OPPO剛出了自家的推送服務,信鴿還沒有;VIVO壓根沒有自家的推送服務)

Ⅲ Android 屏幕解析度適配

Android屏幕解析度千奇百怪,怎麼讓app在不同的解析度的設備上「看起來一樣」呢?
你也許還有以下疑惑:

這篇文章將會針對以上問題一一解答。

Pixels 我們看到屏幕上的圖像由一個個像素組成,像素里包含色彩信息。
如常說的手機解析度:1080 x 1920 指的是手機寬度可展示1080像素,高度可展示1920像素。

Pixels Per Inch 每英寸長度所具有的像素個數,單位面積內像素越多,圖像顯示越清晰。
ppi一般用在顯示器、手機、平板等描述屏幕精細度。

Dots Per Inch 每英寸長度所具有的點數。
dpi一般用來描述列印(書本、雜志、電報)的精細度

density-independent pixels (device-independent pixels 我查了一下,官網更多時候使用前者,有的時候也顯示後者),dip是縮寫,也可以更簡單些稱作dp。該單位的目的是屏蔽不同設備密度差異,後面細說。

Scalable pixels 用於設置字體,在用戶更改字體大小時候會適配。

澄清了基本概念,我們現在從一個例子開始說明以上單位之間的區別與聯系。

布局文件里有個View,長寬都是200px,分別在解析度為480(寬)x800(高)簡稱A設備、1080(寬)x1920(高)簡稱B設備,效果如下:

左邊是A設備,右邊是B設備。問題出來了,同樣長寬都是200px,為啥A設備顯示很大,B設備顯示很小呢?你可能會說B設備的橫向解析度1080比A設備的480大,所以在B設備上看起來比較小。來看看A、B設備橫向到底是多少英寸,怎麼來計算呢?這時候就需要用到ppi了,既然知道橫向的像素點個數,也知道每英寸能容納的像素點,當然可以得知橫向的尺寸了。

其中一種方式獲取DisplayMetrics對象:

A設備寬度尺寸:480(px)/240(ppi)=2inch
B設備寬度尺寸:1080(px)/420(ppi)=2.5inch
可以看出,A、B設備尺寸差別不大。A設備ppi=240 B設備ppi=420,明顯地看出B設備單位長度上比A設備能夠容納更多的像素,因此同樣的200px,B設備只需要較小的尺寸就能夠顯示,因此在B設備上的view看起來比A設備小很多。
知道了問題的原因,然而顯示的效果卻不能接受。

我們總不能自己判斷每個設備的ppi,然後計算實際需要多少像素,再動態設置view的大小吧,那layout里的靜態布局大小就無法動態更改適應了。想當然的能有一個統一的地方替我們轉換,沒錯!Android系統已經幫我們實現了轉換。接下來就是dpi、dp出場了。

Android系統使用dpi來描述屏幕的密度,使用dp來描述密度與像素的關系。
A設備dpi=240
B設備dpi=420
Android系統最終識別的單位是px,怎麼將dpi和px關聯起來呢?,答案是dp。
Android規定當dpi=160時,1dp=1px,當dpi=240時,1dp=1.5px,依此類推,並且給各個范圍的dpi取了簡易的名字加以直觀的識別,如120<dpi<=160,稱作為mdpi,120<dpi<=240 稱作hdpi,最終形成如下規則:

現在知道了dp能夠在不同dpi設備上對應不同px,相當於中間轉換層,我們只需要將view長寬單位設置為合適的dp,就無需關注設備之間密度差異,系統會幫我們完成dp-px轉換。將我們之前的例子稍微更改,再看看效果驗證一下:

通過上面對dp的了解,我們知道在設定view大小、間距時使用dp能最大限度地屏蔽設備密度之間的差異。可能你就會問了,那bitmap展示的時候如何適配不同密度的設備呢?

自定義view從磁碟上載入一張圖片,並將之顯示在view上,view的大小決定於bitmap大小。依舊以上述A、B設備為例,展示結果如下:

左邊是A設備,右邊是B設備。
明顯地看出,在A設備顯示比B設備大很多,實際上和我們之前用px來描述view的大小原理是一樣的,bitmap的寬、高都是px在描述,而bitmap決定了view的寬、高,最終導致A設備和B設備上的view大小(寬、高像素)是一樣的,而它們屏幕密度又不相同,因此產生了差異。
那不會每次都需要我們自己根據屏幕密度來轉換bitmap大小吧?幸運的是,Android已經為我們考慮到了。

生成不同密度的目錄有什麼作用?
A設備dpi=240,根據dpi范圍,屬於hdpi
B設備dpi=420,根據dpi范圍,屬於xxhdpi
圖片原始尺寸:photo1.jpg(寬高 172px-172px)
當我們想要在不同密度設備上顯示同一張圖片並且想要「看起來一樣大時」。假設設計的時候以hdpi為准,放置photo1.jpg為172*172,那麼根據計算規則在xxhdpi上需要設置photo1.jpg為:

現在hdpi和xxhdpi目錄下分別存放了同名圖片:photo1.jpg,只是大小不同。當程序運行的時候:

來看看效果:

左邊A設備,右邊B設備
針對不同的密度設計不同的圖片大小,最大限度保證了同一圖片在不同密度設備上表現「看起來差不多大」。
來看看A、B設備上圖片占內存大小:

說明在B設備上顯示photo1.jpg需要更多的內存。
上邊只是列舉了hdpi、xxhdipi,同理對於mdpi、xhdpi、xxxhdpi根據規則放入相應大小的圖片,程序會根據不同的設備密度從對應的mipmap文件夾下載入資源。如此一來,我們無需關注bitmap在不同密度設備上顯示問題了。

在mipmap各個文件夾下都放置同一套資源的不同尺寸文件似乎有點太佔apk大小,能否只放某個密度下圖片,其餘的靠系統自己適配呢?
現在只保留hdpi下的photo1.jpg圖片,看看在A、B設備上運行情況如何:

看起來和上張圖差不多,說明系統會幫我們適配B設備上的圖片。
再來看看A、B設備上圖片占內存大小:
先看A設備:

對比photo1.jpg 分別放在hdpi、xxhdpi和只放在hdpi下可以看出:B設備上圖片所佔內存變小了。為什麼呢?接下來從源碼里尋找答案。

A、B設備同樣載入hdpi/photo1.jpg,返回的bitmap大小不相同,我們從這方法開始一探究竟。

上面涉及到的關鍵點是density,分別是TypedValue的density和Options的density。
先來看看TypedValue density:

再來看看Options density

現在分析B設備載入hdpi/photo1.jpg如何做的:

和我們之前調試的結果一致。

B設備是怎麼決定使用hdpi下的圖片資源呢?
根據實驗(嘗試找了源碼,沒怎麼看懂,因此只是做了實驗,可能在不同密度設備上找尋規則不一樣):B設備先找屬於自己密度范圍文件夾下的圖片,B設備屬於xxhdpi,先查看xxhdpi有沒有photo1.jpg,如果沒有則往更高的密度找,比它高的密度是xxxhdpi,還是沒有,則往低密度找,找xhdpi,沒有再找hdpi,找到了則返回構造好的TypedValue,剩下的就是我們前面分析的。
既然我們只想放某個密度下的一份切圖,該放哪個密度下呢?從系統尋找規則看,更推薦放置在更高密度下的,因為如果放在低密度下,那麼當運行在高密度設備上時,圖片會進行放大,可能導致不清晰。我一般習慣放在xxhdpi下。

Android Studio默認創建了不同密度的mipmap文件夾,默認放置了ic_launcher.png。我們普通的切圖該放drawable還是mipmap下呢?對於這個問題網上也是眾說紛紜,實際上對於我們來說,關注的重點是圖片放在drawable或者mipmap,載入出來bitmap是否有差異,如果沒有差異放在哪就看習慣了。通過實踐,普通的切圖放drawable和mipmap下載入出來的bitmap是沒有差異的,只不過用drawable的話需要自己創建不同密度的文件夾。我習慣於放在drawable下(啟動圖標logo還是放在mipmap下)。

前邊 [注1] 留了個問題,我們使用dp來表示view的大小了,為啥兩個看起來還是有些差距?下面我們更加直觀地看一個例子。
A設備dpi=240 密度1.5 解析度(寬高px):480 * 800
B設備dpi=420 密度2.625 解析度(寬高px):1080 * 1794
換算成dp
A設備解析度:320dp * 533dp
B設備解析度:411dp * 683dp
依舊是上邊的例子:

將view寬高分別設置為320dp,看看效果:

左邊A設備,右邊B設備
可以看出同樣的320dp大小,A設備鋪滿了屏幕,而B設備沒有。這效果顯然是不能接受的,Android考慮到不同設備寬高不同,推出了"寬高限定符"。以A、B設備為例:
在res文件夾下創建文件夾:

假設設計師出圖是按照800x480,那麼我們創建dimen文件的時候

該文件放在values-800x480文件夾下。
根據解析度比例算出1794x1080的dimen值

這樣子,A、B設備載入資源的時候使用對應解析度限定符下的px,如果找不到再找默認值,可以在一定程度上解決屏幕寬高碎片化適配問題。
但是這樣子的限定比較嚴格,需要測試各種解析度,後來Android又推出了"smallest-width"簡稱最小寬度限制。
A設備寬320dp
B設備寬411dp
假設設計師切圖標准屏幕寬是320dp(A設備),那麼可以定義如下dimen.xml文件

該文件放在values-sw320dp文件夾下
根據規則,計算B設備dimen.xml

現在我們繼續來看之前的view

通過對dimen引用,A設備尋找和自己寬度一樣的dimen文件,找到values-sw320dp,dp320=320dp。B設備尋找和自己寬度一樣的dimen文件,找到values-sw411dp,dp320=410dp。這樣子同樣的dp320,得出不同的值,就適配了屏幕寬度不同的問題。
看看效果:

這次B設備也鋪滿了屏寬。

綜上,為了適配不同屏幕大小,推薦使用dp+smallest-width。

獲取設備dpi最終都是從這方法獲取的,實際上就是讀取系統的配置文件。因此我們也可以通過adb shell 獲取:

可以看出dpi是系統配置好的,當然有些手機是可以設置解析度的,設置之後我們查看解析度:

解析度變低了,dpi也變小了。

Ⅳ Android調用系統相機實現拍照和視頻錄制

(1)申請許可權

(2)設置布局

這里做了一個簡單的布局:添加了一個按鈕和一個ImageView控制項用於顯示拍攝的圖像。

(3)為按鈕添加點擊事件監聽

點擊按鈕時,調用系統相機進行拍照,並在確定後將圖像顯示在ImageView控制項中。

(1)申請許可權

(2)設置布局

添加了一個按鈕和一個VideoView控制項用於顯示錄制的視頻。

(3)為按鈕添加點擊事件監聽

同前面一樣,點擊按鈕後調用系統相機進行錄制視頻,錄制完成後點擊確定即可將錄制的視頻顯示在VideoView控制項中。

對於Android11.0的版本,在調用系統相近進行視頻錄制的時候,即使在AndroidMenifest.xml中申請了CAMERA許可權,還是會在程序運行時報錯: Permission  Denial ,   . .... ....  with revoked permission android.permission.CAMERA

解決方法是在程序中動態申請許可權:

寫在最後:文章是在學習過程中做的學習筆記,同時與志同道合者分享,文章內容均經過我自己實驗證實可行,如有問題歡迎留言,很高興一起交流討論,共同進步!

Ⅳ 進行Android開發的時候沒有測試機適配怎麼辦,如何進行屏幕適配

Android項目的res目錄下一般加上我們自己創建的,會有6個目錄,分別是:drawble drawble-ldpi drawble-mdpi drawble-hdpi drawble-xhdpi drawble-xxhdpi, 這里就不包括更為特殊的drawble目錄了,(比如drawlbe-land-hdpi, 表示水平方向的高解析度的圖片,這些都目錄不管多麼長,它們都是按一丁點規律匹配的, 我們的目的是, 從個別中發現規律,從而應用到整體)。
當一個apk運行起來時,Android系統會根據其所運行的手機的屏幕密度去相對應的圖片文件夾里找指定名稱的圖片。 注意, 先去哪個目錄里找,完全是根據這個手機的屏幕密度決定的。

其中注意兩點:
1, 中等解析度,即mdpi的屏幕密度是160,他是標準的參考密度。所以計算比例的時候它的比例值是1. 其他屏幕密度的參考比例都是以這個為依據。
2, 默認的drawble目錄(一般是自己建的),和mdpi是一樣的。將圖片放到這個目錄和放到drawble-mdpi目錄是一樣的效果。不過一般習慣性的放一些自定義selector或者點9的圖片在這里。
現在我們來看, HTC one V手機的屏幕密度是252ppi, 那距離哪一個最靠近呢, 就是hdpi了。 所以當apk運行在這個手機上時,首先會去這個目錄找圖片。
下面是用常見的一些類型的手機總結的一個表格:

注意一點: 上面說的對應關系,都是首選目錄, 那如果首選目錄裡面找不到圖片呢?

Android圖片選擇策略
上面說到, 如果屏幕所對應的文件夾沒有要找的圖片,怎麼辦。這是很常見的,我們開發項目時一般不會去為每一個級別的屏幕去切一套圖片。那樣做只會讓apk很大。所以一般性的圖片我們只切一兩個典型密度屏幕的圖片。但是apk是有可能會運行在從ldpi到xxhdpi的各種級別的手機上。這個時候就需要根據一定的策略去尋找圖片了。
Android系統尋找圖片的步驟是這樣的:
1, 去屏幕密度對應的目錄去找。如果找到就拿來用。
2, 如果沒找到,就去比這個密度高一級的目錄裡面去找,如果找到就拿來用。
3, 如果沒找到就繼續往上找。以此類推。
4, 如果到了xxhdpi目錄還沒有找到的話,就會去比自身屏幕密度低一級的目錄去找,如果低一級的目錄>=hdpi,找到了就拿來用。
5, 如果沒找到, 就去mdpi目錄去找, 如果找到了,就拿來用。
6, 如果沒找到,就去默認的drawble目錄里去找, 如果找到了就拿來用。
7 ,如果沒找到,再去最低的ldpi目錄里去找。如果找到了,就拿來用。
8, 如果沒找到, 那就是沒找到了, 圖片無法顯示。(不過一般不會出現這種現象,因為如果每個目錄都沒有這個圖片的話,你是編譯不過的)
這里有兩點需要注意:
① 首先會去比自己密度高的目錄里去找,這是因為因為系統相信,你在密度更高的目錄里會放置解析度更大的圖片,這樣的話這個圖片會被縮小,但同時顯示效果不會有損失,但是如果優先去低一級別的目錄去找的話, 找到的圖片就會被放大,這樣的話這個圖片就會被拉扯模糊了。
e.g. 同一張圖片,你在mdpi和xxhdpi目錄各放了一份, 這個應用你現在運行在hdpi的手機上, 那應用會選擇哪張圖片呢。答案是xxhdpi目錄里的。即便hdpi離mdpi更近一點!
②,如果在mdpi里找不到是不會直接去ldpi里找的, 而是先去默認的drawble目錄里找,這是drawble目錄和drawble-mdpi是一個級別的。
下面用一張流程圖來總結:

(註: 以上流程圖是我通過做實驗總結出來的,如有謬誤還望指出。)

Android系統對圖片的縮放規則

上文中提到如果在手機對應的目錄沒有找到圖片,就會按照一定的策略去其他目錄找,那找到了以後就原圖顯示么? 非也。
對於放在不同目錄下的圖片, 系統會按照一定比例對原始的圖片進行放大或者縮小, 具體的放大縮小比例可參考下表, 圖片所在目錄和對應的屏幕密度是相同時圖片縮放比例為1,也就是原圖顯示,而橫向的比例表示分別放在該密度手機上運行時圖片被縮放的比例。
對原始圖片的縮放倍數。

上表幾點值得注意的地方:
①, drawable目錄和drawable-mdpi目錄和dp到px的轉換關系是一樣的。
②,當你放一個120px*180px的圖片到drawable-hdpi目錄,如果此應用運行在一個xhdpi的手機上,則這個圖片會被拉扯到160px*240px。
③, 最後一行dp->px, 說明了在代碼或者布局文件中聲明一個dp值, 這個值在不同屏幕密度的手機中會被乘以不同的倍數。 比如你在布局文件中寫了一個寬和高分別為120dp和180dp的LinearLayout, 那麼當這個應用運行在xhdpi的手機上時(比如上面那個常見手機表中的中興U985手機),它的實際像素就會被轉換為240px*360px。 如果運行在ldpi的手機上,就變成了90px*135px。 但是在這兩個手機中顯示的區域大小從肉眼看,是一模一樣大的。(這點作為後面內容的一個引子,「看起來」一樣大,這就是Android的一個神奇的地方)

我們來做個試驗
試驗材料:
① 一張120px*180px的圖片

② 四部手機, 具體參數參考上面的一張表格。三星 Galaxy win pro 3218 (hdpi)、 HTC one V (hdpi)、 中興U985 (xhdpi)、Google Nexus 7 (xhdpi)。
③ 我在布局文件里聲明了3個View, 第一個位於左上角,是一個線性布局,寬和高指定為120dp*180dp(注意是dp哦), 第二個位於右上角,是一個ImageView,內容就是上面這張120px*180px的圖片, 第三個位於左下角也是一個線性布局,固定寬高,是120px*180px。
我將這個圖片放到一個Android工程里的drawable-hdpi目錄

從上面的那種縮放關系表中我們可以知道,圖片從hdpi目錄中取, 運行在hdpi手機上寬高保持原始值,,運行在xhdpi手機上,寬高會乘以4/3, 也就是說圖片會被拉扯變大, 但是圖片的實際顯示效果,即「視覺大小」怎麼樣呢。
下面是運行後的效果:

如圖: 黑色區域是120dp*180dp的View, 藍色區域是120px*180px的圖片, 灰色區域是120px*120px的View。
1, 可以看到使用dp的View(黑色區域)在不同解析度,不同屏幕尺寸,不同屏幕密度的手機下,視覺大小看起來是一模一樣的。
但是他們的實際像素值是不一樣的: 120dp*180dp -> (hdpi) -> 180px*270px, 而120dp*180dp ->(xhdpi)-> 240px*360px。 由於屏幕密度的不同,縮放以後的像素可以顯示出一樣的視覺大小。
2, 藍色圖片的視覺大小也是一樣的, 由於圖片放到了hdpi目錄下, 所以前兩個手使用的是圖片的原始像素120px*180px, 而後兩個手機對圖片進行了放大, 參考上面的屏幕密度縮放關系表, 放大了4/3倍。 我通過對屏幕的截圖,測量下來的結果的確是放大了這么多, 分別為160px*240px。 由於屏幕密度的不同,它們顯示出來的視覺大小是相同的。
3, 但是使用固定像素值的View就沒那麼幸運了, 它在hdpi的手機上看起來要比在xhdpi的手機上大一些。 要是在屏幕密度相差更大的手機上看的話, 這個區域的大小會相差很大。 這就是為什麼Android推薦使用dp作為View的尺寸,而不是真實像素的原因了。
4, 經過反復試驗,(實驗結果就不貼圖了,很多),得出一個結論,使用哪個目錄下的圖片(前提是圖片只放在某一個目錄中),在所有,不管是解析度還是屏幕尺寸還是屏幕密度,3個參數都在改變的情況下,圖片顯示的視覺大小都和運行在這個目錄對應屏幕密度手機上時的大小是一樣的。

UI給工程師切多大圖是合適的。

說說我之前走的冤枉路吧。
在之前, 設計師的交互和視覺設計都是基於480*800的界面, 切圖的時候會以480*800為基礎切一版, 然後在給所切圖片的寬和高乘上個4/3,然後在出一版。
比如同一個120*180的圖片, 就會出兩個版本, 一個是120*180的一個是160*240的。分別放到hdpi目錄和xhdpi目錄。
吃到的苦頭是,UI很累, apk很大。T^T
這番探究下來, 發現直接基於720*1280的視覺稿切一版圖片就可以了。 將圖片只放到xhdpi目錄中,這樣系統會在不同密度屏幕的手機中對圖片進行合理的縮放, 而之前這個縮放工作竟然是人工完成的!
另: 如果想在xxhdpi的手機上顯示的很好, 也可以基於1080P的屏幕設計, 這樣的話就兼容所有低密度屏幕的手機, 而且也不會出現圖片被拉扯的現象。

Ⅵ android獲取視頻每一幀

本周給大家分享如何獲取視頻的每一幀的信息,說到這個那就得看我們的谷歌官方給我們的提供的api介面類:MediaMetadataRetriever,這個類是提供給我們用來獲取視頻信息的,
官方文檔:
https://developer.android.google.cn/reference/android/media/MediaMetadataRetriever
通過文檔我們知道,我們可以通過它提供的extractMetadata()方法獲取視頻基本信息,
例如:視頻寬、高,時長,作者等,還有通過getFrameAtTime()方法獲取對應時長位置的視頻幀信息,返回的是一個bitmap對象
通過實踐知道,這個方法好是好,但是獲取視頻幀的速度太慢了,我自己做的實驗是,獲取一個4分多鍾的視頻,每隔10秒取一幀,開了4個線程去取,時間大概在10秒左右,這樣對於我們來說是不可以忍受的,所以最後在github上找到了一個很好的庫推薦給大家:
https://github.com/wseemann/FFmpegMediaMetadataRetriever
這個庫是基於ffmpeg實現的,同樣的實驗獲取視頻幀信息的速度在1秒左右,只開了一個線程,ffmpeg還是依舊的強大啊。
通過本周的學習,自己對於ffmpeg是越來越趕興趣了,所以買了一本書來研究一下,但是本書講的都是c語言,所以沒辦法又把我大學學習的c語言的書找了出來,繼續開始著自己的爬坑之旅。

熱點內容
安卓取消耳機模式怎麼取消 發布:2025-05-15 18:24:24 瀏覽:58
氣球怎麼解壓視頻 發布:2025-05-15 18:20:00 瀏覽:782
電腦軟體密碼怎麼設置密碼 發布:2025-05-15 18:09:07 瀏覽:107
android應用是否運行 發布:2025-05-15 18:02:40 瀏覽:10
java排序list 發布:2025-05-15 18:02:40 瀏覽:298
net編譯可以在linux上嗎 發布:2025-05-15 18:01:18 瀏覽:533
華為怎麼知道不是安卓 發布:2025-05-15 18:00:32 瀏覽:909
清理華為手機存儲空間不足 發布:2025-05-15 17:54:46 瀏覽:349
java從控制台輸入 發布:2025-05-15 17:47:38 瀏覽:483
上傳文章微信 發布:2025-05-15 17:42:46 瀏覽:813