十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團隊
量身定制 + 運營維護+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
1.來說下主程序MainActivity.java
成都創(chuàng)新互聯(lián)公司是一家專業(yè)提供云龍企業(yè)網(wǎng)站建設,專注與網(wǎng)站設計制作、成都網(wǎng)站設計、H5建站、小程序制作等業(yè)務。10年已為云龍眾多企業(yè)、政府機構等服務。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站設計公司優(yōu)惠進行中。
public class MainActivity extends Activity {
private TableLayout table;
private Button select;
EmployeeDao dao = new EmployeeDao(this);
private Button add;
private Button update;
int selectedRow = 0;
int ActivityID=1;
ListEmployee list = new ArrayListEmployee();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
table = (TableLayout) this.findViewById(R.id.table);
table.setBackgroundColor(Color.GREEN);
//table.set
add = (Button) this.findViewById(R.id.add);
update = (Button) this.findViewById(R.id.update);
select = (Button) this.findViewById(R.id.select);
// 點擊查詢按鈕處理事件
// Toast.makeText(this, "已查詢過了!", Toast.LENGTH_SHORT).show();
select.setOnClickListener(new selectListener());
// 點擊添加按鈕事件處理,跳轉到另一個activity
add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent();
i.setClass(MainActivity.this, AddAndUpdateActivity.class);
Bundle bundle=new Bundle();
ActivityID=1;
bundle.putInt("ID", ActivityID);
i.putExtras(bundle);
startActivity(i);
}
});
// 更新員工信息
update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent();
i.setClass(MainActivity.this, AddAndUpdateActivity.class);
Bundle bundle=new Bundle();
ActivityID=2;
bundle.putInt("ID", ActivityID);
bundle.putInt("emID", selectedRow);
i.putExtras(bundle);
startActivity(i);
}
});
}
// 查詢信息監(jiān)聽類
private class selectListener implements View.OnClickListener {
@Override
public void onClick(View v) {
list = dao.getAll();
if (list.size() != 0) {
for (int i = 0; i list.size(); i++) {
TableRow row = new TableRow(MainActivity.this);
Employee em = list.get(i);// 查找所有員工信息
// 設置行標記
row.setId(em.getId());
row.setPadding(6, 1, 6, 1);
row.setGravity(Gravity.CENTER);
row.setBackgroundColor(Color.WHITE);
TextView view1 = new TextView(MainActivity.this);
view1.setText(Integer.toString(em.getId()));
view1.setGravity(Gravity.CENTER);//文本居中
view1.setTextSize((float) 18);文本大小
view1.setTextColor(Color.RED);
view1.setPadding(10, 2, 10, 2);//邊框左、上、右、下
row.addView(view1);添加一行
TextView view2 = new TextView(MainActivity.this);
view2.setText(em.getName());
view2.setTextSize((float) 18);
view2.setPadding(10, 2, 10, 2);
row.addView(view2);
TextView view3 = new TextView(MainActivity.this);
view3.setText(Integer.toString(em.getAge()));
view3.setTextSize((float) 18);
view3.setGravity(Gravity.CENTER);
view3.setPadding(10, 2, 10, 2);
row.addView(view3);
TextView view4 = new TextView(MainActivity.this);
view4.setText(em.getPosition());
view4.setTextSize((float) 18);
view4.setPadding(10, 2, 10, 2);
row.addView(view4);
TextView view5 = new TextView(MainActivity.this);
view5.setText(em.getDepartment());
view5.setTextSize((float) 18);
view5.setPadding(10, 2, 10, 2);
row.addView(view5);
TextView view6 = new TextView(MainActivity.this);
view6.setText(em.getWorkdate());
view6.setTextSize((float) 18);
view6.setPadding(10, 2, 10, 2);
row.addView(view6);
TextView view7 = new TextView(MainActivity.this);
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = format.parse(em.getWorkdate());
} catch (ParseException e) {
e.printStackTrace();
}
float d= (float)((new Date().getTime()-date.getTime())/(24*60*60*1000)/365);//計算工齡
String dd=Integer.toString((int) d+1);
view7.setText(dd);
view7.setTextSize((float) 18);
view7.setPadding(10, 2, 10, 2);
row.addView(view7);
table.addView(row);
row.setOnClickListener(new View.OnClickListener() {//點擊某行觸發(fā)事件
@Override
public void onClick(View v) {
System.out.println("行標記:" + v.getId());
for (int i = 0; i table.getChildCount(); i++) {
if (table.getChildAt(i).getId() != v.getId())
table.getChildAt(i).setBackgroundColor(Color.WHITE);
// 選中時,高亮顯示即設置背景色
v.setBackgroundColor(Color.YELLOW);
}
selectedRow = v.getId();
AlertDialog.Builder dialog = new AlertDialog.Builder(
MainActivity.this);
dialog.setTitle("請確認:");
dialog.setMessage("是否刪除這條記錄?");
dialog.setPositiveButton("確定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog,int which) {
EmployeeDao dao = new EmployeeDao(MainActivity.this);
dao.delete(selectedRow);
Toast.makeText(MainActivity.this,
"刪除成功", Toast.LENGTH_SHORT).show();
Intent i = new Intent();
i.setClass(MainActivity.this,MainActivity.class);
startActivity(i);
}
});
dialog.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
dialog.cancel();
} });
dialog.show();
}
});
}
}
}
}
}
2.然后是添加和更新的界面,兩個功能使用同一個xml文件布局
RelativeLayout
android:background="#2691f2"
tools:context=".AddAndUpdateActivity"
TextView
android:id="@+id/t"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="25sp"
android:text="@string/addinfo"
android:textColor="#bc4b86" /
LinearLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_below="@+id/t"
android:orientation="vertical"
TextView
android:layout_width="wrap_content"
android:layout_height="30dp" /
LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/name" /
EditText
android:id="@+id/nm"
android:inputType="text"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp" /
/LinearLayout
LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/age" /
EditText
android:id="@+id/ag"
android:inputType="text"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp" /
/LinearLayout
LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/position" /
EditText
android:id="@+id/pzs"
android:inputType="text"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp" /
/LinearLayout
LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/dptmt" /
EditText
android:id="@+id/dptmt"
android:inputType="text"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp" /
/LinearLayout
LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/date" /
EditText
android:id="@+id/wkdt"
android:inputType="text"
android:layout_width="150dp"
android:layout_height="wrap_content" /
/LinearLayout
TextView
android:layout_width="wrap_content"
android:layout_height="20dp" /
Button
android:id="@+id/addnew"
android:layout_width="60dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:text="@string/add"
/Button
/LinearLayout
/RelativeLayout
Android P的新功能特性集中在了UI、通知體驗、室內(nèi)定位、圖像存儲幾個方面,解決了之前一直存在的痛點。例如WiFi RTT一定程度上彌補了蜂窩網(wǎng)絡在室內(nèi)環(huán)境下的定位問題,HEIC圖像格式則重點解決了存儲容量問題。同時,Android P也在通知豐富度及操作便捷性等功能方面有所增強和提升。
一、WiFi RTT功能——復雜地形精確導航
WiFi RTT功能是Android P新引入的一個功能,從原理上來說與蜂窩網(wǎng)絡的定位原理一致,但這個功能極大的彌補了蜂窩網(wǎng)絡在室內(nèi)定位的短板,WiFi RTT將能夠在室內(nèi)提供高精度的定位,這是蜂窩網(wǎng)絡很難做到的。
WiFi RTT是全新的功能,在android.net.wifi包下增加了rtt包,用于存放WiFi RTT相關類和接口。
WiFi RTT的API以WifiRttManager為核心,借助AP熱點或WiFi,利用RTT原理完成測距,通過三個以上的測距點就能夠準確地定位到設備所在位置。
WiFiRTTManager提供了測距接口,是一個異步測距操作,根據(jù)官方文檔()說明,其測距接口如下:
void startRanging(RangingRequest request, RangingResultCallback callback, Handler handler);
注:?SDK Platforms Android P Preview Revision 1的相關接口定義與此不同,但實際的官方鏡像中接口與此一致,開發(fā)者需要更新最新的Android P Preview Revision 2,此版本中Google已經(jīng)修正該接口。
接口中,RangingRequest通過RangingRequest.Builder構建,RangingRequest.Builder構建出RangingRequest所需要的參數(shù)可以通過WiFiManager等系統(tǒng)服務獲取到相關的內(nèi)容,如?ListScanResult scanResults = wifiManager.getScanResults();
以下提供一個簡單的測試Demo,以供參考:
private WifiRttManager wifiRttManager;
private WifiManager wifiManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ... ...
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)) {
Object service = this.getApplicationContext().getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
if(service instanceof WifiRttManager) {
wifiRttManager= (WifiRttManager) service;
Log.i(TAG, "Get WifiRttManager Succ.");
}
wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
IntentFilter wifiFileter = new IntentFilter();
wifiFileter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
wifiFileter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
wifiFileter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(new WifiChangeReceiver(), wifiFileter);
}
// ... ...
}
private void startScanAPs() {
wifiManager.setWifiEnabled(true);
wifiManager.startScan();
}
class WifiChangeReceiver extends BroadcastReceiver {
@RequiresApi(api = 28)
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
ListScanResult scanResults = wifiManager.getScanResults();
Log.i(TAG, "Wifi Scan size:" + scanResults.size());
for(ScanResult scanResult:? scanResults) {
Log.i(TAG, scanResult.toString());
RangingRequest.Builder builder = new RangingRequest.Builder();
builder.addAccessPoint(scanResult);
wifiRttManager.startRanging(builder.build(), new RangingResultCallback() {
@SuppressLint("Override")
@Override
public void onRangingFailure(int i) {
// TODO
}
@SuppressLint("Override")
@Override
public void onRangingResults(ListRangingResult list) {
// TODO get result from list
for(RangingResult result : list) {
Log.i(TAG, result.toString());
}
}
}, new Handler());
}
}
}
}
使用WiFi RTT時,需要在AndroidManifest.xml中增加如下聲明:
uses-feature android:name="android.hardware.wifi.rtt" /
通過上面的簡單代碼,就能夠實現(xiàn)WiFi RTT的功能。
WiFi RTT功能適用于復雜地形的大型室內(nèi)外場所,如商場、娛樂場所、大型休閑、游樂場等等,提供場所內(nèi)的局部區(qū)域精確化導航等功能。相信在很快的時間內(nèi),就能夠在各大地圖應用內(nèi)體驗到這項便利功能,對于路癡、地圖盲的伙伴們將是極大的福音。
二、顯示剪切——支持劉海屏
隨著iPhone X的推出,“劉海屏”達到了空前的高潮。Android P里提供了對異形屏幕的UI適配兼容方案,通過DisplayCutout類提供的相關接口,能夠獲取到屏幕中Cutout區(qū)域的信息。
借助DisplayCutout,可以獲取到如下信息:
DisplayCutout displayCutout = view.getRootWindowInsets().getDisplayCutout();
if(displayCutout != null) {
Region bounds = displayCutout.getBounds();
Log.d(TAG, String.format("Bounds:%s", bounds.toString()));
int top = displayCutout.getSafeInsetTop();
int bottom = displayCutout.getSafeInsetBottom();
int left = displayCutout.getSafeInsetLeft();
int right = displayCutout.getSafeInsetRight();
Log.d(TAG, String.format("Cutout edge:[left:%d, top:%d,right:%d, bottom:%d]", left, top, right, bottom));
}
public Region getBounds()能夠獲取到Cutout區(qū)域的所有信息,Region就是Cutout區(qū)域。
public int getSafeInsetTop()
public int getSafeInsetBottom()
public int getSafeInsetLeft()
public int getSafeInsetRight()
以上四個接口,可以獲取到去除Cutout區(qū)域后的安全區(qū)域邊界值。
通過上述數(shù)據(jù),開發(fā)者能夠精準的控制UI的繪制,避免將UI內(nèi)容繪制到Cutout區(qū)域造成UI顯示異常。
Android機器里,劉海屏目前還是極為罕見的Google為了方便開發(fā)者調(diào)試,在Android P Preview鏡像中,特別提供了Cutout的支持,具體打開方式可以參考Google提供的特性說明文檔cutout小節(jié)內(nèi)容。
cutout小節(jié):
如圖所示,筆者使用手頭的Pixel 2 XL體驗了Android P的Cutout設置。
三、通知優(yōu)化——操作更多樣,內(nèi)容更豐富
Android P在通知內(nèi)容的豐富度和操作上做了優(yōu)化。
最近的版本中,Android系統(tǒng)的通知管理方面一直優(yōu)化升級,Android O提供了更細粒度的Channel功能,通知欄推送時需要指定NotificationChannel,用戶可以對通知的Channel選擇,只允許感興趣的Channel推送的通知顯示。通過通道設置、免打擾優(yōu)化等方式,極大增強了消息體驗。
增強消息體驗
Android P繼續(xù)改進和增強消息通知[v1]?。早在Android 7.0時,就提供了在通知中直接應答和輸入,Android P對這一功能做了更多的增強。
Android P的通知中支持圖像內(nèi)容,可以通過setData()方法,給出消息的圖像內(nèi)容,在通知上展示給用戶。
Android P同樣簡化了通知的配置形式。Android P中增加了Notification.Person類,用于區(qū)分同一個對話的參與者信息,如參與者的頭像、URI等。根據(jù)官方說明,Android P中,通知消息的其他一些API,也使用Person替代之前的CharSequence。
簡單的體驗下新的API的開發(fā):
NotificationChannel channel = new NotificationChannel("WtTestChannel",
"WtTestChannel", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true); // luncher icon right corner's point
channel.setLightColor(Color.RED); // read point
channel.setShowBadge(true); // whether show this channel notification on long press icon
Notification.Builder builder =
new Notification.Builder(MainActivity.this,
"WtTestChannel");
Notification.Person p = new Notification.Person();
p.setName("WeTest");
p.setUri("" +
"ui/1.2.0/pc/static/image/newLogo-16042.png");
Notification.MessagingStyle messageStyle = new Notification.MessagingStyle(p);
Notification.MessagingStyle.Message message =
new Notification.MessagingStyle.Message("WeTestMessage", 2000, p);
//show image
Uri image = Uri.parse(
"");
message.setData("image/png", image);
messageStyle.addMessage(message);
builder.setStyle(messageStyle);
builder.setSmallIcon(R.mipmap.ic_launcher);
Notification notification = builder.build();
NotificationManager notifyManager =
(NotificationManager) getSystemService(
MainActivity.this.getApplicationContext().NOTIFICATION_SERVICE);
notifyManager.createNotificationChannel(channel);
notifyManager.notify("WeTest", 1, notification);
通道設置、廣播和免打擾優(yōu)化
Android P中,重點做了內(nèi)容豐富上的工作,同時也對Channel的設置方面做了一些簡化處理。
Android O版本里,首次推出了NotificationChannel,開發(fā)者需要配置相應的Channel,才能夠推送通知給用戶。用戶能夠更加細粒度[v1]?的針對App的Channel選擇,而不是禁止App的所有通知內(nèi)容。
而在Android P中,對通知的管理做了進一步的優(yōu)化,包括可以屏蔽通道組、提供新的廣播類型和新的免打擾優(yōu)先級。
屏蔽通道組:?用戶可以在通知設置中屏蔽App的整個通道組。開發(fā)者可以通過isBlocked()來判斷某個通道組是否被屏蔽了,并根據(jù)結果,不向已經(jīng)被屏蔽的通道組發(fā)送任何通知。另外,開發(fā)者可以在App中使用新接口getNotificationChannelGroup()來查詢當前的通道組設置。
新的廣播類型:新廣播類型是針對通道和通道組的功能增加的“通道(組)屏蔽狀態(tài)變化”廣播。開發(fā)者App中可以對所擁有的通道(組)接收廣播,并根據(jù)具體廣播內(nèi)容作出動作。開發(fā)者可以通過NotificationManager,查看廣播相關的具體信息。針對廣播的動作可以通過Broadcasts查看具體的方法和信息。
免打擾優(yōu)先級:?NotificationManager.Policy增加了兩個新的優(yōu)先級常量,PRIORITY_CATEGORY_ALARMS(警告優(yōu)先),PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER?(媒體、系統(tǒng)和游戲聲音優(yōu)先)。
四、支持多攝像機和相機共享
近一段時間,雙攝、多攝等機型紛紛面世。雙攝及多攝提供了單攝像頭所無法完成的能力,如無縫縮放、散景和立體視覺。Android P在這方面也提供了系統(tǒng)級的API支持。
Android P提供了系統(tǒng)API,支持從兩個或者多個物理攝像頭同步獲取數(shù)據(jù)流。此前OEM廠商提供的雙攝設備多是廠商自行定制系統(tǒng)實現(xiàn),此時Android P推出了API,從系統(tǒng)層面上制定了API規(guī)范。
新的API提供了在不同相機之間切換邏輯數(shù)據(jù)流或混合數(shù)據(jù)流的調(diào)用能力。在捕捉延遲方面,提供新的會話參數(shù),降低初始捕捉延遲。同時,提供相機共享能力,以解決在多種使用相機的場景下重復停止、開啟相機流。閃光燈方面,Android P增加基于顯示的閃光燈支持。光學防抖方面,Android P向開發(fā)者提供OIS時間戳,用于圖像穩(wěn)定性優(yōu)化以及其他特效使用。
此外,Android P還支持外部USB/UVC相機,可以使用更強大的外置攝像頭模組。
五、支持圖像媒體后期處理
Android P引入了新的ImageDecoder,該類除了支持對各種圖片格式的解碼、縮放、裁剪之外,其強大之處在于支持對解碼后的圖像做后期處理(post-process),使用該功能可以添加復雜的自定義特效,比如圓角,或是將圖片放在圓形像框中。編寫后期處理回調(diào)函數(shù),你可以添加任何繪圖指令實現(xiàn)需要的效果。
此外,Android P原生支持GIF和WebP格式的動圖,新增了AnimatedImageDrawable類,并被新增的解碼器類ImageDecoder直接支持,用法跟矢量動畫類AnimatedVectorDrawable類似,實現(xiàn)方式也類似,通過新增渲染線程和工作線程,不需要在UI線程處理動圖更新,可以說是無痛使用,非常省心。
下面通過編寫代碼,顯示一張gif圖,并利用后期處理機制,在圖像中間繪制一個綠色的實心圓。
final ImageView image = (ImageView) findViewById(R.id.image);
File gifFile = new File("/data/local/tmp/test.gif");
if (!gifFile.exists()) {
Log.d(TAG, "gifFile is not exsited!");
return;
}
ImageDecoder.Source source = ImageDecoder.createSource(gifFile);
try {
d = ImageDecoder.decodeDrawable(source, new ImageDecoder.OnHeaderDecodedListener() {
@Override
public void onHeaderDecoded(ImageDecoder imageDecoder, final ImageDecoder.ImageInfo imageInfo, ImageDecoder.Source source) {
imageDecoder.setPostProcessor(new PostProcessor() {
@Override
public int onPostProcess(Canvas canvas) {
int w = imageInfo.getSize().getWidth();
int h = imageInfo.getSize().getHeight();
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
canvas.drawCircle(w/2, h/2, h/4, new Paint(paint));
return 0;
}
});
}
});
image.setVisibility(View.VISIBLE);
image.setImageDrawable(d);
} catch (IOException e){
Log.d(TAG, e.toString());
}
Button button = (Button) findViewById(R.id.buttonText);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (d != null d instanceof AnimatedImageDrawable) {
AnimatedImageDrawable ad = (AnimatedImageDrawable) d;
if (ad.isRunning()) {
Log.d(TAG, "stop running");
ad.stop();
} else {
Log.d(TAG, "start running");
ad.start();
}
}
}
});
六、支持HDR VP9和HEIF
Android P內(nèi)置了對HDR VP9和HEIF(heic)圖像編碼的支持。HEIF是蘋果在iOS11推出的一種高效壓縮格式,目前在IphoneX、Iphone 8、IPhone 8P上已經(jīng)支持。該格式的壓縮率更高,但是編碼該格式需要硬件的支持,解碼并不需要。最新的支持庫中的HeifWriter支持從YUV字節(jié)緩沖區(qū)、Surface或是Bitmap類轉換為HEIF格式的靜態(tài)圖像。
Android P新引入了MediaPlayer2,支持DataSourceDesc創(chuàng)建的播放列表。
功能優(yōu)化提升一覽
一、神經(jīng)網(wǎng)絡API 1.1
在前不久發(fā)布的Android 8.1 (API level 27)上,Google首次在Android平臺上推出了神經(jīng)網(wǎng)絡API,這意味著我們的Android機器智能化水平又提高了一大步。而本次Android P,進一步豐富了神經(jīng)網(wǎng)絡的支持,不僅對之前的相關API進行了優(yōu)化,并且提供了9個新的操作,為具體的數(shù)據(jù)操作方面提供了更深入的支持。
二、改進表單自動填充
Android 8.0(API等級26)中引入了自動填充框架,這使得在應用中填寫表單變得更加容易。 Android P引入了自動填充服務并實現(xiàn)了多項改進,得以在填寫表單時進一步增強用戶體驗。
三、安全增強
Android P引入了許多新的安全功能,包括統(tǒng)一的指紋驗證對話框和敏感交易的高確信度的用戶確認。應用程序內(nèi)的指紋認證UI也將會更加一致。
統(tǒng)一的指紋驗證對話框
如果第三方APP想要使用指紋,Android系統(tǒng)框架為應用提供了指紋認證對話框,該功能可以提供統(tǒng)一的外觀和使用體驗,用戶使用起來更放心。如果您的程序還在使用FingerprintManager,現(xiàn)在改用FingerprintDialog替代吧,系統(tǒng)來提供對話框顯示。對了,在使用FingerprintDialog之前,別忘了調(diào)用hasSystemFeature()方法檢查手機設備是否支持指紋。
敏感交易的高確信度的用戶確認
Android P系統(tǒng)提供了受保護的確認API,借助這組全新的API,應用可以使用ConfirmationDialog對話框向用戶提示,請求用戶批準一條簡短的聲明, 該聲明允許應用提醒用戶,即將完成一筆敏感交易,例如支付。
如果用戶接受聲明,應用將會收到一條key-hash的消息認證碼(HMAC),該簽名由TEE產(chǎn)生,以保護用于輸入和認證對話框的顯示。該簽名表示用于已經(jīng)看到了聲明并同意了。
硬件安全模塊
Android P還提供了StrongBox Keymaster(強力沙盒秘鑰大師),一個存儲在硬件安全模塊的具體實現(xiàn)。在這個硬件安全模塊中有自己的CPU、安全存儲空間,真隨機數(shù)生成器,以及額外的機制抵御應用被篡改或是未授權應用的惡意加載。當檢查存儲在StrongBox Keymaster中的密鑰時,系統(tǒng)通過可信執(zhí)行環(huán)境(TEE)確認密鑰的完整性。為了降低能耗,StrongBox支持了一組算法和不同長度的秘鑰:
●?RSA 2048
●?AES 128 and 256
●?ECDSA P-256
●?HMAC-SHA256 (支持8字節(jié)到64字節(jié)任意秘鑰長度)
●?Triple DES 168
需要說明的是,這個機制需要硬件支持。
安全秘鑰導入KeyStore
使用新的ASN.1編碼的秘鑰格式添加導入秘鑰到Keystore,Android P提供了額外的密碼解密安全能力。之后KeyMaster就可以解密KeyStore存儲的秘鑰,這種工作方式使得秘鑰明文永遠不會出現(xiàn)在設備內(nèi)存中。這項特性要求設備支持Keymaster 4。
四、支持客戶端側Android備份加密
Android P支持使用客戶端密鑰對Android備份進行加密。 這項隱私措施,需要設備的PIN、圖案密碼或標準密碼才能從用戶設備備份的數(shù)據(jù)中恢復數(shù)據(jù)。
五、Accessibility優(yōu)化
為了使App使用更便捷,Android在多個方面為開發(fā)者提供了易用性的優(yōu)化。
1、Navigation semantics
Android P在App的場景切換和操作上為開發(fā)者提供了很多的優(yōu)化點。
2、Accessibility pane titles
Android P中對Section提供了新的機制,被稱為accessibility pane titles, Accessibility services能夠接收這些標題的變化,使得能夠對一些變化提供更加細粒度的信息。
指定Section的標題,可以通過android:accessibilityPaneTitle新屬性來設置,同樣運行時可以通過setAccessibilityPaneTitle()來設置標題。
3、頂部欄導航
Android P提供了新的頂部欄導航機制,通過設置View實例的android:accessibilityHeading屬性為true,來顯示邏輯標題。通過這些標題,用戶就可以從一個標題導航到下一個標題,
4、群組導航和輸出
針對屏幕閱讀器,Android P對View提供了新的屬性android:screenReaderFocusable代替原有的android:focusable來做標記,來解決在一些場景下為了使屏幕閱讀器工作而設置View為可獲取焦點的操作。這時,屏幕閱讀器需要同時關注android:screenReaderFocusable和android:focusable設置為ture的View。
5、便捷操作
tooltips交互
Android P中,可以使用getTooltipText()去讀取tooltips的文本內(nèi)容。使用新的ACTION_SHOW_TOOLTIP和ACTION_HIDE_TOOLTIP控制View顯示或者隱藏tooltips。
新全局交互
Android P在AccessibilityService類中提供了兩個全新的操作。開發(fā)者的Service可以通過GLOBAL_ACTION_LOCK_SCREEN幫助用戶鎖屏,通過GLOBAL_ACTION_TAKE_SCREENSHOT幫助用戶完成屏幕截圖。
窗體改變的一些細節(jié)
Android P優(yōu)化了在App多窗體同步發(fā)生變化時的更新內(nèi)容獲取。當出現(xiàn)TYPE_WINDOWS_CHANGED時,開發(fā)者可以通過getWindowChanges()API獲取窗體變化情況。
當多窗體發(fā)生改變時,每個窗體都會發(fā)出自己的事件,開發(fā)者可以通過getSource()獲取到事件窗體的根View。
如果你的App為View定義了accessibility pane titles,UI更新時你的Service就能夠識別到相應的改動。當出現(xiàn)TYPE_WINDOW_STATE_CHANGED事件時,使用新方法 getContentChangeTypes()返回的類型,就能夠獲取到當前窗體的變化情況。例如,現(xiàn)在就能夠通過上述的機制,檢測到一個[v1]?窗格是否有了新標題,或者一個窗格的消失。
六、新的Rotation方案
旋轉屏幕,是一些游戲、視頻等場景必要的操作,但有一些場景,用戶旋轉屏幕并不是為了讓應用顯示從豎屏變成橫屏或反過來。為了避免這種誤操作,Android P提供了新的機制,開發(fā)者可以指定屏幕不隨重力感應旋轉,而是用戶通過一個單獨的按鈕自行控制屏幕顯示轉向。
你是做web開發(fā)的吧?
問題要發(fā)到 電腦/網(wǎng)絡—軟件開發(fā)—移動開發(fā)下比較準確。
android上是沒有form表單的概念的,通常用listView列表來顯示。
前幾天給別人寫了一個這樣的demo,如果有需要,可以留下郵箱發(fā)給你
1.服務器端的準備
為了完成該實例,我們需要在服務器端做以下準備工作:
(1)我們需要在MyEclipse中創(chuàng)建一個Web工程,用來模擬服務器端的Web服務,這里,我將該工程命名為了“myhttp”。
(2)修改該工程的“index.jsp”文件,添加兩個輸入框和一個提交按鈕,作為該Web工程的顯示頁面。運行Tomcat,在瀏覽器中訪問該Web工程,可以看到如圖1所示的界面。
Web工程的顯示頁面
(3)在該Web工程中,創(chuàng)建一個繼承自HttpServlet的LoginAction類,并實現(xiàn)其中的doPost()方法,用來響應圖1所示頁面的用戶操作。具體實現(xiàn)如下:
由上述代碼可以看出,當我們在圖1所示的頁面輸入用戶名“admin”,密碼“123”時,點擊提交按鈕,會得到“Login succeeded!”的提示信息,如圖2所示。若用戶名、密碼錯誤,則會得到“Login failed!”的提示信息。
2.客戶端實現(xiàn)
在Android客戶端,我們需要完成的工作是:以POST方式發(fā)送用戶名密碼到上述服務器,并獲得服務器的驗證信息。
我們分以下幾個步驟來完成。
2.1 UI界面
在Android工程中,我們需要完成一個簡單的UI界面,用來完成用戶名密碼的輸入、發(fā)送POST請求、顯示服務器的驗證結果,完成后的界面如圖3所示。
在MainActivity中,我們需要獲取兩個EditText控件的輸入,“提交”按鍵的監(jiān)聽,以及服務器驗證結果的TextView內(nèi)容顯示。具體實現(xiàn)代碼如下:
2.2發(fā)送POST請求到服務器
可以看到上述代碼中,我們調(diào)用了HttpUtils類的靜態(tài)方法submitPostData()完成了發(fā)送POST請求到服務器,并將該方法的返回值(服務器的響應結果)顯示在了TextView控件中。
通過以上的代碼可以看出,在該方法中,其實完成了3件事:
(1)將用戶名密碼封裝成請求體,這是通過調(diào)用getRequestData()方法來實現(xiàn)的(后面會講到這個方法的具體實現(xiàn))。
(2)設置HttpURLConnection對象的各種參數(shù)(其實是設置HTTP協(xié)議請求體的各項參數(shù)),然后通過httpURLConnection.getOutputStream()方法獲得服務器輸出流outputStream,再使用outputStream.write()方法將請求體內(nèi)容發(fā)送給服務器。
(3)判斷服務器的響應碼,通過httpURLConnection.getInputStream()方法獲得服務器的響應輸入流,然后再調(diào)用dealResponseResult()方法處理服務器的響應結果。
2.3封裝請求體
使用POST請求時,POST的參數(shù)不是放在URL字符串里,而是放在HTTP請求數(shù)據(jù)中,所以我們需要對POST的參數(shù)進行封裝。
針對該實例而言,我們發(fā)送的URL請求是:,但是我們需要將POST的參數(shù)(也就是username和password)封裝到該請求中,形成如下的形式:
2.4處理響應結果
最后,我們再來看一看對服務器返回結果的處理是怎樣的。因為在本實例中,服務器的返回結果是字符串“Login succeeded!”或“Login failed!”,所以這里我們需要做的就是將服務器的返回結果輸入流轉化成字符串。當然了,如果服務器返回的是圖片,那么,我們就需要就得到的輸入流轉化成Bitmap圖片了。如下代碼是上面代碼中用到的dealResponseResult()方法的具體實現(xiàn)。
2.5運行效果