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 官方文件