2021年6月3日 星期四

如何建立桌面捷徑(適應不同的SDK版本)

要求權限
Manifest(AndroidManifest.xml) 裡加上權限要求
<uses-permission android:name=
"com.android.launcher.permission.INSTALL_SHORTCUT" />


import 會用到的物件類別
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.app.PendingIntent;


程式內容
//可以當成參數傳入的設定
String id = "testID";
String labelShort = "testA";//直接出現在桌面時使用的標題名稱
int iconID = R.mipmap.ic_heart;
Class targetClass = ActText.class;

//設定要攜帶的參數
String paraTitle = "FILENAME";
String paraVal = _fileLog;
//定義要開啟的 Activity
Intent intentTask = new Intent(this, targetClass)
        .setAction(Intent.ACTION_VIEW);

//攜帶參數
intentTask.putExtra(paraTitle, paraVal);
task 說明
//如果裝置版本較舊, 可以執行舊版SDK
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O)
{
 android.content.Intent intent = new android.content.Intent();
 intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, labelShort);
 intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intentTask);
 intent.putExtra(Intent.EXTRA_SHORTCUT_ICON,
        android.graphics.drawable.Icon.createWithResource(this, iconID));
 this.sendBroadcast(intent);
 return;
}
版本問題應對
//建立捷徑的外觀
ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder(this, id)
        .setShortLabel(labelShort)
        .setIcon(android.graphics.drawable.Icon.createWithResource(this, iconID))
        .setIntent(intentTask)
        .build();
//建立捷徑
ShortcutManager shortcutManager = this.getSystemService(ShortcutManager.class);
Intent pinnedShortcutCallbackIntent = shortcutManager.createShortcutResultIntent(pinShortcutInfo);
PendingIntent successCallback = PendingIntent.getBroadcast(this, 0, pinnedShortcutCallbackIntent, 0);
shortcutManager.requestPinShortcut(pinShortcutInfo, successCallback.getIntentSender());



確保 目標 Activity 能直接被啟動
activity 宣告要有這一段
<intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>




Activity 開啟後接收參數
import android.os.Bundle;
Bundle bundle = this.getIntent().getExtras();
if (bundle != null)
 {
        _id = (String) bundle.get(PARA_ID);
        _filename = (String) bundle.get(PARA_FILE);
 }



Intent-Task

意義在於
桌面捷徑被點選後觸發的事件內容

定義要啟動的 activity
以及要帶進的參數

設定 Task 基本內容
Intent task = new Intent(this, [類別名稱].class)
        .setAction(Intent.ACTION_VIEW);
必須要 setAction 為 ACTION_VIEW

為 task 加上參數
task.putExtra( [參數名稱] , [參數內容] );
設定參數名稱
必須要與接收的 Activity 端對應

啟免參數對應錯誤
可以將參數名稱寫成 final 字串共用
設定常數:
public static final String PARA_FILE= "FILENAME";
task 設定參數內容:
task.putExtra(PARA_FILE ,filename);
Activity 接收參數內容:
_filename = (String) bundle.get(PARA_FILE);

相關文章

如何讓程式在不同版本的SDK執行

相關資源

ShortcutManager 官方文件

ShortcutInfo 官方文件

PendingIntent 官方文件

如何讓程式在不同版本的SDK執行

Android 的 API 很多
compiler 時,常因版本問題無法通過
可以透過以下方法解決


使用 RequiresApi
格式:
@RequiresApi(api = [SDK版本編號])
sample:
@RequiresApi(api = 26)
private void test()
{
....
}
裝置在執行這個函式時會檢查
如果 API 版本不夠高,整個函式都不會被執行
雖然比較簡單(Android Studio 可以自動產生)
但,遇到舊版API,雖不致當掉,但整段函式都不執行
官方說明:
RequiresApi@Android Developers


(程式內)執行前檢查 SDK 版本
if (android.os.Build.VERSION.SDK_INT >=[ver])
{
執行程式
}
sample:
if (Build.VERSION.SDK_INT >= 26)
{
  myVibrator.vibrate (VibrationEffect.createWaveform(pattern, repeat));
}
else
{
  myVibrator.vibrate(pattern, repeat);
}
執行到底該處
如果 API 版本不夠高時,不執行該段程式
(不會因執行該段而當掉)
稍好一點
遇到 API 版本不夠高時,仍會執行函式
但會跳過新版功能,以免掛掉


Android 的 SDK 很多
還是希望程式盡可能多種裝置都正常執行

程式內依版本決定執行方式
if (android.os.Build.VERSION.SDK_INT >=[ver])
{
 使用新版方法
}
else
{
 使用舊版方法
}
有時候會遇到較複雜狀況:

if (android.os.Build.VERSION.SDK_INT >=28)
{
  SDK> 28 可用的API
}
else if (android.os.Build.VERSION.SDK_INT >=26)
{
  SDK> 26 可用的API
}
else
{
  SDK<26 可用的API
}

官方文件

這裡可以查到版本對應 API Levels@Android Developers

2021年5月15日 星期六

如何讓手機有節奏的震動

要求權限
Manifest(AndroidManifest.xml) 裡加上權限要求
<uses-permission android:name=
"com.android.launcher.permission.VIBRATE" />

import 會用到的物件類別
import android.os.VibratorEffect;
import android.os.Vibrator;
android.os.Build;

設定相關參數
//重覆次數
int repeat = 2;
設定節奏
int dot = 200; //震動持續
int dash = 500; //震動停止
long[] pattern = {
0, // Start immediately
dot, dash,
};
啟動震動功能
//使用 Context.getSystemService 建立Vibrator物件
Vibrator myVibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
    myVibrator.vibrate (VibrationEffect.createWaveform(pattern, repeat));
}
else
{
        myVibrator.vibrate(pattern, repeat);
        //SDK 較低的狀況下,執行舊版函式
}


createWaveform

讓裝置可依傳入的參數作有節奏的震動

VibrationEffect.createWaveform
VibrationEffect createWaveform (long[] timings,int repeat)
建立震動模式的 VibrationEffect 物件
傳入節奏陣列 及 重覆的次數
官方文件: createWaveform


相關文章

如何執行手機震動功能

相關資源

Vibrator 官方文件

VibrationEffect 官方文件

API level 官方文件

如何執行手機震動功能

要求權限
Manifest(AndroidManifest.xml) 裡加上權限要求
<uses-permission android:name=
"com.android.launcher.permission.VIBRATE" />


import 會用到的物件類別
import android.os.VibratorEffect;
import android.os.Vibrator;
android.os.Build;


設定相關參數
int streng = 100;
int min = 4;
int streng = VibrationEffect.DEFAULT_AMPLITUDE;
啟動震動功能
//使用 Context.getSystemService 建立Vibrator物件
Vibrator myVibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
      myVibrator.vibrate(VibrationEffect.createOneShot ( min * 1000, streng));
}
else
{      myVibrator.vibrate(min * 1000, streng);
        //SDK 較舊的狀況下,執行舊版函式
}


停止震動
myVibrator.cancel();


Vibrator 類別

Vibrator
android.os.Vibrator
用以操作裝置震動功能的類別
官方文件: Vibrator


vibrate 函式

Vibrator.vibrate
void vibrate(VibrationEffect vibe)
接收一個 VibrationEffect 物件
執行物件裡設定的震動模式
官方文件: vibrate


VibrationEffect 類別

VibVibrationEffectator
android.os.VibrationEffect
用來描述震動功能,供 vibrate 物件使用
官方文件: VibrationEffect



createOneShot 函式

VibrationEffect.createOneShot
VibrationEffect createOneShot(long milliseconds, int amplitude)
建立一次性震動的 VibrationEffect 物件
傳入時間(milliseconds,毫秒), 以及震動強度(amplitude)
震動強度的值必需在 1 ~ 255
或是 DEFAULT_AMPLITUDE(-1)
官方文件: createOneShot


DEFAULT_AMPLITUDE

VibrationEffect.DEFAULT_AMPLITUDE
VibrationEffect 定義常數
內容為 -1 (0xffffffff)
指示使用該設備的震動強度預設值
官方文件: DEFAULT_AMPLITUDE


停止震動

在設定的時間或次數到了後
震動會自動停止

但如果想在之前中斷
可以使用 cancel() 函式

Vibrator.cancel()
void Vibrator.cancel();
官方文件: Vibrator.cancel


不需要取回原先開啟震動的 Vibrator Object
所以也可以直接新建立一個 Vibrator 物件

因此也可以寫成:

((Vibrator) this.getSystemService(Service.VIBRATOR_SERVICE)).cancel();


SDK 版本確保

VibrationEffect 需要在 SDK > android.os.Build.VERSION_CODES.O 的環境執行
如果沒加上版本確保的動作,compiler 不會通過

如果只想 compiler 通過的話
只要函式前加上 RequiresApi 即可
@RequiresApi(api = Build.VERSION_CODES.O)
private void vibrateOneshot{
     ...
}

或是在執行前判斷 SDK 版本

if (android.os.Build.VERSION.SDK_INT >=
        android.os.Build.VERSION_CODES.O)
 {
        執行程式
 }


但無法確保使用者的 SDK 版本,建議用以下方式
依 SDK 版本決定執行方式
if (android.os.Build.VERSION.SDK_INT > = Build.VERSION_CODES.O)
 {
        執行新版
 }
 else
 {
        執行舊版
 }

如果覺得 Build.VERSION_CODES.O 太長
也可以改成數字 [ 26 ]( API level 26)
if (android.os.Build.VERSION.SDK_INT > = 26 )
{
... }

這裡可以查到版本對應

相關文章

如何讓手機有節奏的震動

相關資源

Vibrator 官方文件

VibrationEffect 官方文件

API level 官方文件

2021年1月28日 星期四

JSONObject.putOpt 函式

JSONObject 提供 put() 讓你做寫入

但又提供 putOpt()

基本上同 put(),但較安全

putOpt 函式
將 一組 key-value 寫入 json 物件 (JSONObject)
JSONObject JSONObject.putOpt(String key, Object value)
官方連結
putOpt()  JSONObject 

規則幾乎跟 put() 相同

傳入參數keyname,value
執行動作將 key-val 寫入
回傳值JSONObject物件本身


規則說明
傳入參數狀況 執行結果
keyname 不存在 新增一組 key-value
keyname 已存在 以傳入的 value 取代原有的 value
keyname 已存在
value = null
對應的 key-value 被刪除
keyname = null 沒有任何動作
使用 put 會丟出 Exception


說明範例
程式碼 JSON 內容變化
JSONObject jObj= new JSONObject(); {}
建立了一個空的 JSONObject 物件
jObj.putOpt("K1","Tom"); {"K1":"Tom"}
新增了字串
jObj.putOpt("K2",2); "K1":"Tom","K2":2}
新增了數字
jObj.putOpt("K3",true); {"K1":"Tom","K2":2,"K3":true}
新增了布林值
jObj.putOpt("K1","Jane"));
keyname-"K1" 已存在
{"K1":"Jane","K2":2,"K3":true}
"K1" 的 value 被覆蓋掉
jObj.putOpt("K2",null);
keyname-"K2" 已存在
value 給 null
{"K1":"Jane","K3":true}
"K2" 被移除
jObj.putOpt(null,"xxx");
keyname 給 null
沒有任何動作
使用 put() 會丟出 JSONException : must be non-null


相關文章

如何使用 JSON

如何巡覽 JSONObject 物件內容

如何讀取 JSON 陣列

Jsonobject.put 函式

相關資源

JSONObject 官方文件

JSONObject.putOpt()

JSON 官方文件

2021年1月27日 星期三

JSONObject.put 函式

要操作 JSONObject 的內容, put 是最基本的函式

put 函式
將 一組 key-value 寫入 json 物件 (JSONObject)
系列函式
JSONObject JSONObject.put(String keyname, Object value)
JSONObject JSONObject.put(String keyname, int value)
JSONObject JSONObject.put(String keyname, boolean value)
JSONObject JSONObject.put(String keyname, long value)
JSONObject JSONObject.put(String keyname, double value)
官方連結
put(String, Object )  put(String, int )  put(String, boolean )
put(String, long )  put(String, double )

雖是 Overloading (多形)
各自不同的函式
但規則相同

傳入參數keyname,value
執行動作將 key-val 寫入
回傳值JSONObject物件本身


規則說明
傳入參數狀況 執行結果
keyname 不存在 新增一組 key-value
keyname 已存在 以傳入的 value 取代原有的 value
keyname 已存在
value = null
對應的 key-value 被刪除
keyname = null 丟出 JSONException


說明範例
程式碼 JSON 內容變化
JSONObject jObj= new JSONObject(); {}
建立了一個空的 JSONObject 物件
jObj.put("K1","Tom"); {"K1":"Tom"}
新增了字串
jObj.put("K2",2); "K1":"Tom","K2":2}
新增了數字
jObj.put("K3",true); {"K1":"Tom","K2":2,"K3":true}
新增了布林值
jObj.put("K1","Jane"));
keyname-"K1" 已存在
{"K1":"Jane","K2":2,"K3":true}
"K1" 的 value 被覆蓋掉
jObj.put("K2",null);
keyname-"K2" 已存在
value 給 null
{"K1":"Jane","K3":true}
"K2" 被移除
jObj.put(null,"xxx");
keyname 給 null
丟出 JSONException : must be non-null

使用 put 在 keyname 給 null 時, 會丟出 Exception
在某些 keyname 動態給予的狀況下會出問題
另有較安全的進階版本 JSONObject.putOpt
keyname 給 null 時不會丟出 JSONException
可以參考 putOpt 函式說明

相關文章

如何使用 JSON

如何巡覽 JSONObject 物件內容

如何讀取 JSON 陣列

Jsonobject.putOpt 函式

相關資源

JSONObject 官方文件

JSONObject.put(String, Object )

JSONObject.put(String, int )

JSONObject.put(String, boolean )

JSONObject.put(String, long )

JSONObject.put(String, double )

JSON 官方文件

2021年1月25日 星期一

如何巡覽 JSON 物件內容.使用 Keys 函式

取回 JSONObject 下所有 keyname
有兩個函式可以使用 names() 跟 keys()

JSONArray JSONObject.names()
Iterator<String> JSONObject.keys()

因為兩個函式回傳的資料型態不同
所以後續的處理式也會不同

使用 names() 的方法看這裡

這裡介紹使用keys() 的方法

以 keys() 檢視 JSONObject 所有內容
java.util.Iterator<String> keys= objRoot.keys();
while (keys.hasNext())
{
 String key =keys.next();
 Object val = objRoot.get(key);
 Log(key + "=" +val.tostring());
}
當沒有子元素,不會回傳 null
但,一開始呼叫 hasnext(),就會回傳 false
因此會從 while 直接跳出


keys 函式
Iterator<String> JSONObject.keys()
取回 JSONObject 物件下 keyname
會回傳一個指向 全部 keyname 的 Iterator<String> (迭代器)
keys() 官方說明
Iterator 物件 官方說明

相關文章

如何使用 JSON

如何讀取 JSON 陣列

相關資源

JSONObject 官方文件

keys() 的官方文件

JSONArray 官方文件

Iterator 物件 官方文件

JSON 官方文件

2021年1月19日 星期二

如何讀取 JSON 陣列

內文書籤

範例:取出 JSON 陣列

Length 函式說明

get 函式說明

get 糸列函式 特定資料型別

opt 函式說明

opt 糸列函式 特定資料型別

opt 系列函式 指定 fallback


巡覽 JSON 陣列內容
jstr = ["1",1,true];
jsonAry = new JSONArray(jstr);
try {
 for (int i = 0; i < jsonAry.length(); i++)
 {
  Object obj = jsonAry.get(i);
  log(obj.toString());
 }
}
catch (JSONException ex)
{
 Debug.log(ex);
}
因為失敗時會丟出 JSONException
所以用 try-cath 包起來


用來操作 Json 陣列的物件類別是 JSONArray

JSONArray
org.json.JSONArray
JSONArray 官方文件

要從 JSONObject 中取出陣列物件
要用到 getJSONArray()


要得到 JSONArray 陣列長度,則要用 length

Length 函式
org.json.JSONArray.Length
int length()
跟 ArrayList 不同,不是使用 size()
官方文件

取得陣列中元素是用 get 或 opt

get 函式
取得陣列中的元素
Object get(int index)
傳入 index,該位置的內容以 Object 傳回
如果 index 大於陣列長度,會丟回 JSONException
官方文件


取回 Object 型態有時還需要轉型處理
如果已經確定資料型別
可以直接使用指定回傳資料型別的 get 函式

get 糸列函式 [特定資料型別]
取得 JSONArray 中的特定型別元素
String getString(int index)
int getInt(int index)
boolean getBoolean(int index)
long getLong(int index)
double getDouble(int index)
JSONArray getJSONArray(int index)
JSONObject getJSONObject(int index)
傳入 index,傳回 該位置的內容以特定型別傳回
如果 index 大於陣列長度
或是該位置資型態不符
(像是使用 getInt(),但取得的內容卻不為數字)
會丟回 JSONException
官方文件
getString  getInt  getBoolean  getLong
getDouble  getJSONArray  getJSONObject

在無法確保取回的資料是否安全時,可使用 opt

opt 函式
取回 JSON 陣列中元素
Object opt(int index)
如果 index 大於陣列長度
或資料型態不符
會回傳 null
官方文件

opt 也有指定資料型別的版本

opt 糸列函式 [特定資料型別]
以較安全的方式取回 JSONArray 中元素
Object opt(int index)
booleanoptBoolean(int index)
double optDouble(int index)
int optInt(int index)
JSONArray optJSONArray(int index)
JSONObject optJSONObject(int index)
long optLong(int index)
String optString(int index)
如果 index 大於陣列長度,或資料型態不符
optString 會傳回空字串
optInt 會傳回 0
optBoolean 會傳回 false
optLong 會傳回 0
optDouble 會傳回 NaN
opt 會傳回 null
optJSONArray 會傳回 null
optJSONObject 會傳回 null
官方文件
optString  optInt  optBoolean  optLong
optDouble  optJSONArray  optJSONObject

opt 可以指定失敗時回傳預設內容的版本

opt 系列函式 + fallback
取回 JSONArray 中的元素,取值失敗時傳回指定的 fallback
String optString(int index , String fallback)
int optInt(int index , int fallback)
booleanoptBoolean(int index , boolean fallback)
double optDouble(int index , double fallback)
long optLong(int index , boolean fallback)
傳回 index 及失敗時回傳值,傳回該位置的內容
取值失敗
(ex: index 大於陣列長度,取回的值資料型態不符)
會傳回參數指定的 fallback
官方文件
optString  optInt  optBoolean  optLong
optDouble 


相關文章

如何使用 JSON

如何巡覽 JSONObject 物件內容

相關資源

JSONObject 官方文件

JSONArray 官方文件

Iterator 官方文件(Android Developers)

JSON 官方文件