独立进程记录日志
class Activity{
private lateinit var process: Process
override fun onCreate(){
val logFile = File("/sdcard/Documents/", "${System.currentTimeMillis()}.log")
Runtime.getRuntime().exec("logcat -c")
process = Runtime.getRuntime().exec("logcat -f $logFile")
}
override fun onDestory(){
if(process.isAlive) {
process.destory()
}
}
}
动态请求存储权限
fun requestPermission(context: Context) {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(context,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(context, "申请权限", Toast.LENGTH_SHORT).show()
// 申请 相机 麦克风权限
ActivityCompat.requestPermissions(
context as Activity,
arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
),
100
)
}
}
是否具有读写权限
fun isExternalStorageWritable(): Boolean {
val state = Environment.getExternalStorageState()
if (Environment.MEDIA_MOUNTED == state) {
return true
}
return false
}
/* Checks if external storage is available to at least read */
fun isExternalStorageReadable(): Boolean {
val state = Environment.getExternalStorageState()
if (Environment.MEDIA_MOUNTED == state ||
Environment.MEDIA_MOUNTED_READ_ONLY == state
) {
return true
}
return false
}
隐藏手机软键盘
fun hideKeyboard(context: Context) {
val imm: InputMethodManager =
context.getSystemService(Context.INPUT_METHOD_SERVICE)
as InputMethodManager
if (imm.isActive) {
if ((context as Activity).currentFocus?.windowToken != null) {
imm.hideSoftInputFromWindow(
context.currentFocus!!.windowToken,
InputMethodManager.HIDE_NOT_ALWAYS
)
}
}
}
偏好设置工具类
class SharePreferenceUtil(mContext: Context, name: String) {
private val mSharePreferences: SharedPreferences
private val mEditor: SharedPreferences.Editor
private fun putInt(key: String, value: Int) {
mEditor.putInt(key, value).apply()
}
private fun getInt(key: String, defaultValue: Int): Int {
return mSharePreferences.getInt(key, defaultValue)
}
private fun putLong(key: String, value: Long) {
mEditor.putLong(key, value).apply()
}
private fun getLong(key: String, defaultValue: Long): Long {
return mSharePreferences.getLong(key, defaultValue)
}
private fun putFloat(key: String, value: Float) {
mEditor.putFloat(key, value).apply()
}
private fun getFloat(key: String, defaultValue: Float): Float {
return mSharePreferences.getFloat(key, defaultValue)
}
private fun putString(key: String, value: String) {
mEditor.putString(key, value).apply()
}
private fun getString(key: String, defaultValue: String): String {
var string = mSharePreferences.getString(key, defaultValue)
if (string == null) {
string = ""
}
return string
}
private fun putBoolean(key: String, value: Boolean) {
mEditor.putBoolean(key, value).apply()
}
private fun getBoolean(key: String, defaultValue: Boolean): Boolean {
return mSharePreferences.getBoolean(key, defaultValue)
}
fun put(key: String, value: Any) {
when (value) {
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Float -> putFloat(key, value)
is String -> putString(key, value)
is Boolean -> putBoolean(key, value)
else -> return
}
}
fun <T> get(key: String, defaultObject: T): T {
when (defaultObject) {
is String -> {
return getString(key, defaultObject as String) as T
}
is Int -> {
return Integer.valueOf(getInt(key, defaultObject as Int)) as T
}
is Boolean -> {
return java.lang.Boolean.valueOf(getBoolean(key, defaultObject as Boolean)) as T
}
is Long -> {
return java.lang.Long.valueOf(getLong(key, defaultObject as Long)) as T
}
is Float -> {
return java.lang.Float.valueOf(getFloat(key, defaultObject as Float)) as T
}
else -> return defaultObject
}
}
init {
mSharePreferences = mContext.getSharedPreferences(name, Context.MODE_PRIVATE)
mEditor = mSharePreferences.edit()
}
}
##PCM转WAV工具类
import android.media.AudioFormat;
import android.media.AudioRecord;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class PcmToWavUtil {
private final int mBufferSize; //缓存的音频大小
private int mSampleRate = 8000;// 8000|16000
private int mChannel = AudioFormat.CHANNEL_IN_STEREO; //立体声
private int mEncoding = AudioFormat.ENCODING_PCM_16BIT;
public PcmToWavUtil() {
this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannel, mEncoding);
}
public PcmToWavUtil(int sampleRate, int channel, int encoding) {
this.mSampleRate = sampleRate;
this.mChannel = channel;
this.mEncoding = encoding;
this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannel, mEncoding);
}
public void pcmToWav(String inFilename, String outFilename) {
FileInputStream in;
FileOutputStream out;
long totalAudioLen;
long totalDataLen;
long longSampleRate = mSampleRate;
int channels = 2;
long byteRate = 16L * mSampleRate * channels / 8;
byte[] data = new byte[mBufferSize];
try {
in = new FileInputStream(inFilename);
out = new FileOutputStream(outFilename);
totalAudioLen = in.getChannel().size();
totalDataLen = totalAudioLen + 36;
writeWaveFileHeader(out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
while (in.read(data) != -1) {
out.write(data);
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void writeWaveFileHeader(FileOutputStream out, long totalAudioLen,
long totalDataLen, long longSampleRate, int channels, long byteRate)
throws IOException {
byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W'; //WAVE
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (byte) channels;
header[23] = 0;
header[24] = (byte) (longSampleRate & 0xff);
header[25] = (byte) ((longSampleRate >> 8) & 0xff);
header[26] = (byte) ((longSampleRate >> 16) & 0xff);
header[27] = (byte) ((longSampleRate >> 24) & 0xff);
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);
header[32] = (byte) (2 * 16 / 8); // block align
header[33] = 0;
header[34] = 16; // bits per sample
header[35] = 0;
header[36] = 'd'; //data
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (totalAudioLen & 0xff);
header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
out.write(header, 0, 44);
}
}
计算媒体文件时长
fun computeLength(filePath: String): Int {
var duration = 0
try {
val metaRetriever = MediaMetadataRetriever()
metaRetriever.setDataSource(filePath)
duration =
metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
.toString().toInt()
metaRetriever.release()
} catch (e: Exception) {
e.printStackTrace()
}
return duration
}
Retrofit简单使用
//定义接口
interface NetService {
@GET("job/?")
fun downloadFile(@Query("device_id") deviceId: Int): Call<ResponseFileBean>
@GET("file/s3/presign/upload?")
fun downloadPath(@Query("job_id") jobId: Int): Call<ResponsePathBean>
//useless function temporary
@Headers("Content-type: application/octet-stream")
@Multipart
@PUT(".")
fun uploadFile(@Part fileBean: MultipartBody.Part): Call<ResponseUploadResultBean>
@Headers("Content-Type: application/json")
@PUT("job/{job_id}/success")
fun putResult(@Path("job_id") job_id: Int, @Body jsonBody: RequestBody): Call<ResponseBody>
}
//定义OKHttpClient
val OkHttpClientForRequest = OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.writeTimeout(60, TimeUnit.SECONDS)
.build()
//定义创建器
object NetServiceCreator {
private lateinit var mRetrofit: Retrofit
fun <T> create(serviceClass: Class<T>, url: String): T {
mRetrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(OkHttpClientForRequest)
.build()
return mRetrofit.create(serviceClass)
}
inline fun <reified T> create(url: String): T =
create(T::class.java, url)
}
//定义挂起,注意需要在协程作用域中执行
private suspend fun <T> Call<T>.await(): T {
return suspendCoroutine { continuation ->
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
val body = response.body()
if (body != null) {
continuation.resume(body)
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
//执行请求
val result = NetServiceCreator.create<NetService>("http://www.xxx.com")
.downloadFile(11).await()
##OKHttp上传示例
//定义OKHttpClient
val OkHttpClientForUpload = OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.writeTimeout(60, TimeUnit.SECONDS)
.build()
//构建请求
val tempFile = File(Objects.requireNonNull(xxx))
val mediaType = "application/octet-stream".toMediaTypeOrNull()
val requestBody = RequestBody.create(mediaType, tempFile)
val request: Request = Request.Builder()
.url(uploadUrl)
.method("PUT", requestBody)
.addHeader("Content-type", "application/octet-stream")
.build()
//执行请求
val response = NormalData.OkHttpClientForUpload.newCall(request).execute()
沉浸透明状态栏
//沉浸状态栏目
override fun onCreate(){
...
supportActionBar?.hide()
window.navigationBarColor = Color.TRANSPARENT
window.statusBarColor = Color.TRANSPARENT
...
}
//设置透明状态栏
override fun onCreate(){
...
supportActionBar?.hide()
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
...
}
HSB-> RGB方法
fun hsbToRgb(hsb: FloatArray): String? {
val rgb = StringBuffer()
val hsv = hsb[0]
val sat = hsb[1]
val value = hsb[2]
val hi = hsv / 60 % 6
val f = hsv / 60 - hi
val p = value * (1 - sat)
val q = value * (1 - sat * f)
val t = value * (1 - sat * (1 - f))
val V = String.format("%02x", (value * 255).toInt())
val T = String.format("%02x", (t * 255).toInt())
val P = String.format("%02x", (p * 255).toInt())
val Q = String.format("%02x", (q * 255).toInt())
when (hi.toInt()) {
0 -> {
rgb.append(V)
rgb.append(T)
rgb.append(P)
}
1 -> {
rgb.append(Q)
rgb.append(V)
rgb.append(P)
}
2 -> {
rgb.append(P)
rgb.append(V)
rgb.append(T)
}
3 -> {
rgb.append(P)
rgb.append(Q)
rgb.append(V)
}
4 -> {
rgb.append(T)
rgb.append(P)
rgb.append(V)
}
5 -> {
rgb.append(V)
rgb.append(P)
rgb.append(Q)
}
}
return rgb.toString()
}
安卓垂直进度条
class VerticalSeekBar2 : AppCompatSeekBar {
constructor(context: Context?) : super(context!!)
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
context!!,
attrs,
defStyle
)
constructor(context: Context?, attrs: AttributeSet?) : super(
context!!, attrs
)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(h, w, oldh, oldw)
}
@Synchronized
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec)
setMeasuredDimension(measuredHeight, measuredWidth)
}
override fun onDraw(c: Canvas) {
c.rotate(-90f)
c.translate(-height.toFloat(), 0f)
super.onDraw(c)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
if (!isEnabled) {
return false
}
when (event.action) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> {
progress = max - (max * event.y / height).toInt()
onSizeChanged(width, height, 0, 0)
}
MotionEvent.ACTION_CANCEL -> {}
}
return true
}
}
进度条的属性
示例文件
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dp" />
<solid android:color="#90A4AE" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="5dp" />
<solid android:color="#FFEB3B" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dp" />
<solid android:color="#2196F3" />
</shape>
</clip>
</item>
</layer-list>
<com.ikotliner.mylauncher.VerticalSeekBar
android:id="@+id/seek_bar"
android:layout_width="match_parent"
android:layout_height="200dp"
android:maxHeight="60dp"
android:minHeight="60dp"
android:progressDrawable="@drawable/seek_bar_background"/>
获取应用清单
fun getAppList(context: Context): MutableList<ResolveInfo> {
val pm = context.packageManager
val mainIntent = Intent(Intent.ACTION_MAIN, null)
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER)
val activities = pm.queryIntentActivities(mainIntent, 0)
return activities
}
申请系统设置修改权限
//Manifest文件添加权限
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
//判断是否有修改系统设置的权限
private fun requestPermission() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(this)) {
val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.data = Uri.parse("package:$packageName");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent)
}
}
}
申请读取系统状态权限
//Manifes文件中添加权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
//申请权限
val checkCallPhonePermission =
ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)
if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
context as Activity,
arrayOf(Manifest.permission.READ_PHONE_STATE),
0
)
return
}
创建前台服务
//新建通知
private Notification createForegroundNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// 唯一的通知通道的id.
String notificationChannelId = "notification_channel_id_01";
// Android8.0以上的系统,新建消息通道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//用户可见的通道名称
String channelName = "Foreground Service Notification";
//通道的重要程度
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel notificationChannel = new NotificationChannel(notificationChannelId, channelName, importance);
notificationChannel.setDescription("Channel description");
//LED灯
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
//震动
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
if (notificationManager != null) {
notificationManager.createNotificationChannel(notificationChannel);
}
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, notificationChannelId);
//通知小图标
builder.setSmallIcon(R.drawable.ic_launcher_foreground);
//通知标题
builder.setContentTitle("ContentTitle");
//通知内容
builder.setContentText("ContentText");
//设定通知显示的时间
builder.setWhen(System.currentTimeMillis());
//设定启动的内容
Intent activityIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, activityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
//创建通知并返回
return builder.build();
//在onStartCommand()中开启前台服务
// 获取服务通知
Notification notification = createForegroundNotification();
//将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
startForeground(NOTIFICATION_ID, notification);
下载Android源代码
Ubuntu查看端口被占用的进程
sudo lsof -i:端口号
评论 (0)