android开发可用技巧

android开发可用技巧


都是本人在android开发的学习过程中用到的小技巧,记录于此,便于以后查找

获取屏幕尺寸

DisplayMetrics dm = getResources().getDisplayMetrics();
int screenWidth = dm.widthPixels;
int screenHeight = dm.heightPixels;

自定义view获取自身尺寸

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
    
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    float width = getMeasuredWidth();
    float height = getMeasuredHeight();
}

dp和px转换

//dp转px
final float scale = context.getResources().getDisplayMetrics().density;
pxValue = (int) (dpValue * scale + 0.5f);
//px转dp
final float scale = context.getResources().getDisplayMetrics().density;
dpValue = (int) (pxValue / scale + 0.5f);

获取状态栏高度

public int getStatusBarHeight() {
    
    
    Resources resources = Resources.getSystem();
    int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
    return resources.getDimensionPixelSize(resourceId);
}

设置状态栏字体颜色

//isLightModel为true字体黑,反之字体白
public static void setStatusBarLightMode(Activity activity, boolean isLightMode) {
    
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    
    
        Window window = activity.getWindow();
        int option = window.getDecorView().getSystemUiVisibility();
        if (isLightMode) {
    
    
            option |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
        } else {
    
    
            option &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
        }
        window.getDecorView().setSystemUiVisibility(option);
    }
}

状态栏透明

//方法一:不兼容低版本
//res/values/styles.xml(改AppTheme的方式)
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowTranslucentStatus">false</item>
    <item name="android:windowTranslucentNavigation">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>
//方法二:兼容低版本
public void makeStatusBarTransparent(Activity activity) {
    
    
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
    
    
        return;
    }
    Window window = activity.getWindow();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    
    
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        int option = window.getDecorView().getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        window.getDecorView().setSystemUiVisibility(option);
        window.setStatusBarColor(Color.TRANSPARENT);
    } else {
    
    
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    }
}
//再结合隐藏标题栏即可

按返回键

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    
    
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
    
    
        //业务逻辑
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

字体不跟随系统设置

@Override
public Resources getResources() {
    
    
    Resources res=super.getResources();
    Configuration config=new Configuration();
    config.setToDefaults();
    res.updateConfiguration(config,res.getDisplayMetrics());
    return res;
}

去除标题栏

ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
    
    
    actionBar.hide();
}

广播监听网络状态

//需要的uses-permission:
android.permission.INTERNET
android.permission.ACCESS_NETWORK_STATE
//onResume中:
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(netStateReceiver,filter);
//定义广播接收器
BroadcastReceiver netStateReceiver = new BroadcastReceiver() {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String action = intent.getAction();
        if(action.equals(ConnectivityManager.CONNECTIVITY_ACTION)){
    
    
            //此时网络状态发生变化->调用获取网络状态的方法获取网络状态即可
        }
    }
};

获取当前网络状态

//需要的uses-permission:
android.permission.INTERNET
android.permission.ACCESS_NETWORK_STATE
int getNetWorkStatus(Context context){
    
    
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    if (activeNetworkInfo!=null&&activeNetworkInfo.isConnected()){
    
    
        if (activeNetworkInfo.getType()==(ConnectivityManager.TYPE_WIFI)){
    
    
            return NETWORK_WIFI;
        }else if (activeNetworkInfo.getType()==(ConnectivityManager.TYPE_MOBILE)){
    
    
            return NETWORK_MOBILE;
        }
    }else {
    
    
        return NETWORK_NONE;
    }
    return NETWORK_NONE;
}

收起软键盘

private void hideKeyboard(){
    
    
    View view = getCurrentFocus();
    if(view != null){
    
    
        InputMethodManager inputMethodManager = (InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}

数据存储到手机本地

SharedPreferences.Editor editor = getSharedPreferences("文件名",MODE_PRIVATE).edit();
editor.putString("key",value);
editor.apply();

读取手机本地存储的数据

SharedPreferences pref = getSharedPreferences("文件名",MODE_PRIVATE);
String username = pref.getString("key","默认值");

跳转至浏览器打开网站

Uri uri = Uri.parse("http://www.xxx.cn/");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

正则判断手机号格式是否正确

private boolean isPhone(String phone) {
    
    
    String regex = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$";
    if (phone.length() != 11) {
    
    
        return false;
    } else {
    
    
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(phone);
        return m.matches();
    }
}

长按控件

控件.setOnTouchListener(new View.OnTouchListener() {
    
    
    @Override
    public boolean onTouch(View v, MotionEvent event) {
    
    
        switch (event.getAction()){
    
    
            case MotionEvent.ACTION_DOWN:
             //单指按下
                break;
            case MotionEvent.ACTION_UP:
             //单指释放
                break;
            case MotionEvent.ACTION_MOVE:
             //移动
                break;
            case MotionEvent.ACTION_CANCEL:
             //取消
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                //多指按下
                break;
            case MotionEvent.ACTION_POINTER_UP:
                //多指释放
                break;
        }
        return false;
    }
});

更新app

//动态注册广播接收器
private void initReceiver(){
    
    
    IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
    registerReceiver(downloadApkReceiver,filter);
}
//下载更新包
private void downloadApk(){
    
    
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse("下载地址"));
    request.setDestinationInExternalFilesDir(this,Environment.DIRECTORY_DOWNLOADS,"xxx.apk");
    request.setTitle("xxx.apk");
    request.setDescription("xxx");
    request.setVisibleInDownloadsUi(true);
    DownloadManager apkDownloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
    long mReference = apkDownloadManager.enqueue(request);
}
//定义下载完成时的广播接收器
BroadcastReceiver downloadApkReceiver = new BroadcastReceiver() {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String action = intent.getAction();
        if(action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)){
    
    
            //下载完成,提交handler处理
        }
    }
};
//handler中
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
    
    
    boolean canInstallApk = getPackageManager().canRequestPackageInstalls();
    if(!canInstallApk){
    
    
     //向用户拿安装apk的权限
        Uri uri = Uri.parse("package:"+getPackageName());
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,uri);
        startActivityForResult(intent,996);
    }else{
    
    
        installApk("storage/emulated/0/Android/data/com.example.xxx/files/Download/xxx.apk");
    }
}else{
    
    
    installApk("storage/emulated/0/Android/data/com.example.xxx/files/Download/xxx.apk");
}
//拿到权限后安装
@Override
protected void onActivityResult(int requestCode,int resultCode,Intent data){
    
    
    super.onActivityResult(requestCode,resultCode,data);
    if(requestCode == 996){
    
    
        installApk("storage/emulated/0/Android/data/com.example.xxx/files/Download/xxx.apk");
    }
}
//安装更新包
private void installApk(String downloadApk) {
    
    
    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.setVmPolicy(builder.build());
    builder.detectFileUriExposure();
    Uri uri = Uri.fromFile(new File(downloadApk));
    Intent installIntent = new Intent(Intent.ACTION_VIEW);
    installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
    startActivity(installIntent);
}

界面不被软键盘挤上去

//activity配置xml中
android:windowSoftInputMode:adjustPan

获取系统当前时间(自定义时间格式)

SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date curDate = new Date(System.currentTimeMillis());
String nowTime = timeFormat.format(curDate);

设置透明

//方法一
xml中 android:alpha 设置01
//方法二
xml中 android:background 设置#xx红绿蓝 xx为16进制
//方法三
view.getBackground().setAlpha(x); 设置0255

监听软键盘点击完成

xml中 EditText 
android:singleLine true
android:imeOptions="某action"
java中
EditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    
    
    @Override
    public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
    
    
        if(i == EditorInfo.IME_ACTION_SEARCH){
    
    
            //业务逻辑
            return true;
        }
        return false;
    }
});
imeOptions可选值分别是:
actionDone 完成 EditorInfo.IME_ACTION_DONE
actionGo 前进 EditorInfo.IME_ACTION_GO
actionPrevious 上一项 EditorInfo.IME_ACTION_PREVIOUS
actionNext 下一项 EditorInfo.IME_ACTION_NEXT
actionSearch 搜索 EditorInfo.IME_ACTION_SEARCH
actionSend 发送 EditorInfo.IME_ACTION_SEND
actionUnspecified 未指定 EditorInfo.IME_ACTION_UNSPECIFIED
actionNone 无动作 EditorInfo.IME_ACTION_NONE

延时处理延迟处理

new Handler().postDelayed(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        //业务逻辑
    }
},延迟的时间毫秒);

数据库SQLite

//先创建一个数据库类
public class DBHelper extends SQLiteOpenHelper {
    
    
    private static Integer Version = 1;
    public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){
    
    
        super(context, name, factory, version);
    }
    public DBHelper(Context context, String name, int version){
    
    
        this(context,name,null,version);
    }
    public DBHelper(Context context,String name){
    
    
        this(context, name, Version);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
    
    
        String sql = "create table record(id integer primary key autoincrement,content text,time varchar(60))";
        db.execSQL(sql);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
    

    }
}
//java中使用
DBHelper dbHelper = new DBHelper(context,"record");
SQLiteDatabase db = dbHelper.getWritableDatabase();
//增
ContentValues values = new ContentValues();
values.put("content",content);
values.put("time",time);
db.insert("record",null,values);
//删
db.delete("record","id=?",new String[]{
    
    id});
//改
ContentValues values = new ContentValues();
values.put("content",content);
values.put("time",time;
db.update("record",values,"id=?",new String[]{
    
    id});
//查
Cursor cursor = db.query("record", new String[]{
    
    "id","content","time"}, "content LIKE ? ",new String[]{
    
    "%"+keywords+"%"},null,null,"time DESC");
while (cursor.moveToNext()) {
    
    
    String id = cursor.getString(cursor.getColumnIndex("id"));
    String content = cursor.getString(cursor.getColumnIndex("content"));
    String time = cursor.getString(cursor.getColumnIndex("time"));
    //业务逻辑
}
//关闭数据库
db.close();

shape

corners //圆角属性
android:radius //数值
android:topLeftRadius //数值
android:topRightRadius //数值
android:bottomLeftRadius //数值
android:bottomRightRadius //数值

gradient //渐变属性
android:angle //渐变角度,必须为45的倍数,0为从左到右,90为从上到下
android:startColor //渐变开始点的颜色
android:endColor //渐变结束点的颜色
android:centerColor //渐变中间点的颜色
android:centerX //渐变中心X的相当位置,范围为0~1
android:centerY //渐变中心Y的相当位置,范围为0~1
android:type=["linear" | "radial" | "sweep"] //渐变类型,线性渐变(默认)/放射渐变/扫描式渐变
android:gradientRadius= //渐变的半径,只有当渐变类型为radial时才能使用
android:useLevel=["true" | "false"] //使用LevelListDrawable时就要设置为true。设为false时才有渐变效果

padding //边距属性
android:left //数值
android:top //数值
android:right //数值
android:bottom //数值

solid //填充属性
android:color //颜色

stroke //描边属性
android:width //宽度
android:color //颜色
android:dashWidth //虚线的宽度,值为0时是实线
android:dashGap //虚线的间隔

size //大小属性
android:width //数值
android:height //数值

selector

//注:用于设置background时用android:drawable,用于设置各种color时用android:color
item android:state_pressed="false"
android:drawable(或color)//未被按住时的样子
item android:state_pressed="true"
android:drawable(或color) //被按住时的样子
类似的还有:
//设置是否选中状态,true表示已选中,false表示未选中
android:state_selected
//设置是否勾选状态,主要用于CheckBox和RadioButton,true表示已被勾选,false表示未被勾选
android:state_checked
//设置勾选是否可用状态,类似state_enabled,只是state_enabled会影响触摸或点击事件,state_checkable影响勾选事件
android:state_checkable
//设置是否获得焦点状态,true表示获得焦点,默认为false,表示未获得焦点
android:state_focused
//设置触摸或点击事件是否可用状态,一般只在false时设置该属性,表示不可用状态
android:state_enabled

message带数据提交handler

//message:
Message message = new Message();
message.what = 1;
Bundle bundle = new Bundle();
bundle.putString("key",value);
message.setData(bundle);
handler.sendMessage(message);
//handler中:
String value = message.getData().getString("key");

数据转json

//简单的键值对数组
JSONObject jsonObject = new JSONObject();
jsonObject.put("key1","value1");
jsonObject.put("key2","value2");
String json = jsonObject.toString();
//稍复杂的多维数组,子元素为自定义类,且子元素没键名
需要引入gson:implementation 'com.google.code.gson:gson:2.7'
List<自定义类> list = new ArrayList<>();
list.add(new 自定义类(xxx));
list.add(new 自定义类(xxx));
Gson gson = new Gson();
String json = gson.toJson(list);
//更复杂的多维数组,子元素为自定义类,且子元素有键名
需要引入gson:implementation 'com.google.code.gson:gson:2.7'
Map map = new HashMap<>();
map.put("key1",new 自定义类(xxx));
map.put("key2",new 自定义类(xxx));
String json = gson.toJson(map);

解析json

//JSONObject方式解析(灵活方便,能满足绝大多数情况)
try{
    
    
    JSONObject jsonObject = new JSONObject("json字符串");
    String code = jsonObject.getString("code");                     
    JSONObject result = jsonObject.getJSONObject("result");
    JSONArray data = result.getJSONArray("data");
    for (int i = 0;i < data.length();i++){
    
    
        JSONObject value = data.getJSONObject(i);
        String title = value.getString("title");
    }
}catch(Exception e){
    
    
    e.printStackTrace();
}
//gson方式解析(需要自定义类,麻烦,适用情况:自定义类存在)
需要引入gson:implementation 'com.google.code.gson:gson:2.7'
Gson gson = new Gson();
List<自定义类> list = new ArrayList<>();
list = gson.fromJson("json字符串",new TypeToken>(){
    
    }.getType());

bitmap转base64

public String bitmapToBase64(Bitmap bitmap){
    
    
    String result = null;
    ByteArrayOutputStream byteArrayOutputStream = null;
    try{
    
    
        if(bitmap != null){
    
    
            byteArrayOutputStream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
            byteArrayOutputStream.flush();
            byteArrayOutputStream.close();
            byte[] bitmapBytes = byteArrayOutputStream.toByteArray();
            result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
        }
    }catch(IOException e){
    
    
        e.printStackTrace();
    }finally{
    
    
        try{
    
    
            if(byteArrayOutputStream != null){
    
    
                byteArrayOutputStream.flush();
                byteArrayOutputStream.close();
            }
        }catch(IOException e){
    
    
            e.printStackTrace();
        }
    }
    return result;
}

图片处理(缩放尺寸、改变质量、旋转)

//缩放图片大小
Matrix matrix = new Matrix();
matrix.setScale(0.1f, 0.1f);
Bitmap saveBitmap = Bitmap.createBitmap(originBitmap,0,0,originBitmap.getWidth(),originBitmap.getHeight(),matrix,true);
//降低图片质量
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int quality = 50;//图片质量,0-100,值越小质量越差
originBitmap.compress(Bitmap.CompressFormat.JPEG,quality,byteArrayOutputStream);
Bitmap saveBitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()),null,null);
//旋转图片
int width = originBitmap.getWidth();
int height = originBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.setRotate(angle);//angle为旋转的角度
Bitmap saveBitmap = Bitmap.createBitmap(originBitmap, 0, 0, width, height, matrix, false);

okhttp3发送get请求

//需要引入okhttp3:implementation 'com.squareup.okhttp3:okhttp:3.4.1'
Thread thread = new Thread(){
    
    
    public void run(){
    
    
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        try{
    
    
            Response response = client.newCall(request).execute();
            String result = response.body().string();
            //业务逻辑(若要更新UI需提交给handler处理)
        }catch(Exception e){
    
    
            e.printStackTrace();
        }
    }
};
thread.start();

okhttp3发送post请求

//需要引入okhttp3:implementation 'com.squareup.okhttp3:okhttp:3.4.1'
Thread thread = new Thread(){
    
    
    public void run(){
    
    
        OkHttpClient client = new OkHttpClient();
        RequestBody requestBody = new FormBody.Builder().add("key",value).build();
        Request request = new Request.Builder().url(url).post(requestBody).build();
        try{
    
    
            Response response = client.newCall(request).execute();
            String result = response.body().string();
            //业务逻辑(若要更新UI需提交给handler处理)
        }catch(Exception e){
    
    
            e.printStackTrace();
        }
    }
};
thread.start();

okhttp3发送json格式的post请求

//需要引入okhttp3:implementation 'com.squareup.okhttp3:okhttp:3.4.1'
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
Thread thread = new Thread(){
    
    
    @Override
    public void run(){
    
    
        String json = "自己组织json";
        OkHttpClient okHttpClient = new OkHttpClient();
        RequestBody requestBody = RequestBody.create(JSON,json);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        try{
    
    
            Response response=okHttpClient.newCall(request).execute();
            String result = response.body().string();
            //业务逻辑(若要更新UI需提交给handler处理)
        }catch(Exception e){
    
    
            e.printStackTrace();
        }
    }
};
thread.start();

动态设置文字样式

设置字体大小:
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,getResources().getDimensionPixelSize(R.dimen.xxx));
//如果设置后字体过大,用:
textView.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX,getResources().getDimension(R.dimen.xx));
设置字体颜色:
textView.setTextColor(getResources().getColor(R.color.xxx));
设置样式:
textView.setTypeface(Typeface.SANS_SERIF,Typeface.NORMAL);
Typeface.BOLD //粗体
Typeface.BOLD_ITALIC //粗斜体
Typeface.ITALIC //斜体
Typeface.NORMAL //常规

时间选择器

private TimePickerView pvTime;
//需要显示时间的控件点击显示选择器
textView.setOnClickListener(new View.OnClickListener() {
    
    
    @Override
    public void onClick(View v) {
    
    
        pvTime.show(textView);
    }
});
//设置选择器
Calendar selectedDate = Calendar.getInstance();//默认选中时间
Calendar startDate = Calendar.getInstance();
startDate.set(2018, 12, 1);//可选时间范围的初始时间
Calendar endDate = Calendar.getInstance();
endDate.set(2029, 12, 31);//可选时间范围的结束时间
pvTime = new TimePickerView.Builder(this, new TimePickerView.OnTimeSelectListener() {
    
    
    @Override
    public void onTimeSelect(Date date, View v) {
    
    
        TextView btn = (TextView) v;
        btn.setText(getTimes(date));//getTimes为自定义函数,目的是把date转成需要的时间格式
    }
}).setType(new boolean[]{
    
    true, true, true, false, false, false})//显示选项年月日时分秒
.setLabel("年", "月", "日", "时", "", "")//显示格式
.isCenterLabel(true)
.setDividerColor(Color.DKGRAY)
.setContentSize(21)
.setDate(selectedDate)
.setRangDate(startDate, endDate)
.setDecorView(null)
.build();

时间选择器-年月日

Calendar c = Calendar.getInstance();
new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
    
    
    @Override
    public void onDateSet(DatePicker datePicker, int i, int i1, int i2) {
    
    
        String date = i + "年" + (i1+1) + "月" + i2 + "日";
    }
},c.get(Calendar.YEAR),c.get(Calendar.MONTH),c.get(Calendar.DAY_OF_MONTH)).show();

时间选择器-时分

Calendar c = Calendar.getInstance();
new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
    
    
    @Override
    public void onTimeSet(TimePicker timePicker, int i, int i1) {
    
    
     String time = i + "点" + i1 + "分";
    }
},c.get(Calendar.HOUR_OF_DAY),c.get(Calendar.MINUTE),true).show();

保留两位小数

private String keep2decimal(float f){
    
    
    DecimalFormat df = new DecimalFormat("#.00");
    return df.format(f);
}

ListView(子元素为一条文本)

活动布局xml中加控件:ListView
String[] data = {
    
    "","","","",""};
ArrayAdapter adapter = new ArrayAdapter(XXActivity.this,android.R.layout.simple_list_item_1,data);
ListView list = (ListView)findViewById(R.id.list);
list.setAdapter(adapter);
//点击获取子元素的值
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    
    
    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {
    
    
        String string = ((TextView)view).getText().toString();
    }
});

recyclerView

需要引入:implementation 'com.android.support:recyclerview-v7:28.0.0'
活动布局xml中加控件:RecyclerView
布局xml中加子元素布局;
新建adapter:
public class XXAdapter extends RecyclerView.Adapter{
    
    
    private List<XX> list;
    private Context context;
    public XXAdapter(List<XX> list, Context context){
    
    
        this.list = list;
        this.context = context;
    }
    @Override
    public int getItemCount(){
    
    
     //根据获取到的list显示希望显示的子元素个数
        return list.size();
    }
    @Override
    public int getItemViewType(int position){
    
    
     //position为list的角标,根据业务逻辑返回不同的值
        return 1;
    }
    class AHolder extends RecyclerView.ViewHolder{
    
    
     private View aView;
        public AHolder(View itemView){
    
    
            super(itemView);
            aView = itemView;
        }
    }
    class BHolder extends RecyclerView.ViewHolder{
    
    
        private TextView bTV;
        public BHolder(View itemView){
    
    
            super(itemView);
            bTV = (TextView)itemView.findViewById(R.id.b);
        }
    }
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
    
    
     //根据getItemViewType返回的值返回不同的holder
        if(viewType == 1){
    
    
        return new AHolder(LayoutInflater.from(context).inflate(R.layout.a_item,null));
        }else{
    
    
            return new BHolder(LayoutInflater.from(context).inflate(R.layout.b_item,null));
        }
    }
    //点击子元素监听的接口
    public interface OnItemClickListener {
    
    
        void onClick(XX xx);
    }
    private OnItemClickListener listener;
    public void setOnItemClickListener(OnItemClickListener listener) {
    
    
        this.listener = listener;
    }
    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder,final int position){
    
    
        if(holder instanceof AHolder){
    
    
            ((AHolder) holder).aView.setOnClickListener(new View.OnClickListener() {
    
    
                @Override
                public void onClick(View v) {
    
    
                    if (listener != null) {
    
    
                        listener.onClick(list.get(position));
                    }
                }
            });
        }else{
    
    
         XX xx = list.get(position);
            ((BHolder) holder).bTV.setText(xx.getB());
        }
    }
}
activity中:
private RecyclerView recyclerView;
private GridLayoutManager mLayoutManager;
private XXAdapter adapter;
recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
adapter = new XXAdapter(list,MainActivity.this);
mLayoutManager = new GridLayoutManager(MainActivity.this,1);//数字表示显示的列数
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setAdapter(adapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());//默认动画样式,可自定义
//子项的点击事件处理
adapter.setOnItemClickListener(new XXAdapter.OnItemClickListener() {
    
    
    @Override
    public void onClick(XX xx) {
    
    
        
    }
});

ImageView加载网络图片

需要引入:implementation 'com.github.bumptech.glide:glide:4.0.0'
布局xml中加入ImageView
Glide.with(context).load(url).into(imageView);

加载gif

需要引入:implementation 'com.github.bumptech.glide:glide:4.0.0'
布局xml中加入ImageView
Glide.with(context).load(url).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imageView);
//加上diskCacheStrategy的目的是为了加载更快
DiskCacheStrategy.NONE 什么都不缓存
DiskCacheStrategy.SOURCE 仅仅只缓存原来的全分辨率的图像
DiskCacheStrategy.RESULT 仅仅缓存最终的图像,即降低分辨率后的(或者是转换后的)
DiskCacheStrategy.ALL 缓存所有版本的图像(默认行为)

自定义控件组合

创建布局文件my_layout.xml,比如最外侧控件为LinearLayout,含一个TextView
创建java文件:
public class MyLayout extends LinearLayout {
    
    
    public MyLayout(Context context,AttributeSet attributeSet){
    
    
        super(context,attributeSet);
        LayoutInflater.from(context).inflate(R.layout.my_layout,this);
        //findViewById获取控件,并可添加事件监听
    }
}
xml中:直接使用MyLayout控件
java中:layout.addView(myLayout);

加载摄像头并拍照

/需要权限:android.permission.CAMERA
布局xml中:TextureView
activity中:
需要:implements TextureView.SurfaceTextureListener
定义:
private TextureView cameraView;
private Camera mCamera;
业务逻辑:
cameraView = (TextureView)findViewById(R.id.cameraView);
cameraView.setSurfaceTextureListener(MainActivity.this);
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    
    
    // 打开相机 0后置 1前置
    mCamera = Camera.open(0);
    if (mCamera != null) {
    
    
        try {
    
    
            mCamera.setDisplayOrientation(90);// 设置预览角度,并不改变获取到的原始数据方向
            // 绑定相机和预览的View
            mCamera.setPreviewTexture(surface);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
    
    }
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
    
    
    mCamera.stopPreview();
    mCamera.setPreviewCallback(null);
    mCamera.release();
    return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
    
    }
//某行为触发开启摄像头预览
mCamera.startPreview();
mCamera.autoFocus(null);
//某行为触发拍照(拍单张)
mCamera.takePicture(null,null,new Camera.PictureCallback(){
    
    
    @Override
    public void onPictureTaken(byte[] data,Camera camera){
    
    
        Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
        //业务逻辑(图片可能角度不对,需要旋转)
        releaseCamera();
    }
});
//某行为触发拍照(拍多张)
mCamera.setPreviewCallback(new Camera.PreviewCallback(){
    
    
    @Override
    public void onPreviewFrame(byte[] data,Camera camera){
    
    
     //以下可以用和上面单张一样的处理方式,也可以用下面的处理方式
        Camera.Size size = camera.getParameters().getPreviewSize();
        try{
    
    
            YuvImage image = new YuvImage(data,ImageFormat.NV21,size.width,size.height,null);
            if(image!=null){
    
    
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                image.compressToJpeg(new Rect(0,0,size.width,size.height),80,stream);
                Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(),0,stream.size());
                //业务逻辑
                stream.close();
            }
        }catch(Exception e){
    
    
            e.printStackTrace();
        }
    }
});

dialog:两个按钮

AlertDialog.Builder builder = new AlertDialog.Builder(this).setIcon(R.mipmap.图标).setTitle("标题").setMessage("内容")
.setPositiveButton("确定(积极)", new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //
    }
}).setNegativeButton("取消(消极)", new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //
    }
});
builder.create().show();

dialog:三个按钮

AlertDialog.Builder builder = new AlertDialog.Builder(this).setIcon(R.mipmap.图标).setTitle("标题").setMessage("内容")
.setPositiveButton("确定(积极)", new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //
    }
}).setNeutralButton("不选(中立)", new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //
    }
}).setNegativeButton("取消(消极)", new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //
    }
});
builder.create().show();

dialog:列表

final String[] items = {
    
    "item 1", "item 2", "item 3", "item 4", "item 5", "item 6"};
AlertDialog.Builder builder = new AlertDialog.Builder(this).setIcon(R.mipmap.图标)
.setTitle("标题")
.setItems(items, new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //(i为当前点击的项所在items脚标)
    }
});
builder.create().show();

dialog:多选

final String[] items = {
    
    "多选1", "多选2", "多选3", "多选4", "多选5", "多选6"};
boolean[] isSelect = {
    
    false, false, false, false, false, false};//默认选中状态
AlertDialog.Builder builder = new AlertDialog.Builder(this).setIcon(R.mipmap.图标)
.setTitle("标题")
.setMultiChoiceItems(items, isSelect, new DialogInterface.OnMultiChoiceClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i, boolean b) {
    
    
     //(i为当前点击的项所在items脚标,b为点击后是否为选中状态)
    }
}).setPositiveButton("确定", new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //选择时用数组记录选中的项,这里确定时循环数组处理业务
    }
});
builder.create().show();

dialog:单选

final String[] items = {
    
    "单选1", "单选2", "单选3", "单选4", "单选5", "单选6"};
AlertDialog.Builder builder = new AlertDialog.Builder(this).setIcon(R.mipmap.图标).setTitle("标题")
.setSingleChoiceItems(items, 默认选中脚标, new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //(i为当前点击的项所在items脚标)
    }
}).setPositiveButton("确定", new DialogInterface.OnClickListener() {
    
    
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    
    
        //
    }
});
builder.create().show();

dialog:圆圈加载

ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setIcon(R.mipmap.图标);
progressDialog.setTitle("标题");
progressDialog.setMessage("内容...");
//是否形成一个加载动画,true表示不明确加载进度形成转圈动画,false表示明确
progressDialog.setIndeterminate(true);
//点击返回键或者dialog四周是否关闭dialog
progressDialog.setCancelable(false);
progressDialog.show();
//加载完成后关闭dialog
progressDialog.dismiss();

dialog:进度条加载

final int MAX_VALUE = 100;
ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setIcon(R.mipmap.图标);
progressDialog.setProgress(0);
progressDialog.setTitle("标题");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMax(MAX_VALUE);
progressDialog.show();
new Thread(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        int progress = 0;
        while (progress < MAX_VALUE) {
    
    
            try {
    
    
                Thread.sleep(100);
                progress++;
                progressDialog.setProgress(progress);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        //加载完毕自动关闭dialog
        progressDialog.cancel();
    }
}).start();

dialog:自定义

第一种:纯自定义
View dialogView = View.inflate(this, R.layout.自定义布局, null);
dialogView.findViewById(R.id.xx).控件处理
AlertDialog.Builder builder = new AlertDialog.Builder(this).setView(dialogView);
AlertDialog alertDialog = builder.create();
alertDialog.show();
//完成后关闭dialog
alertDialog.dismiss();

第二种:只有中间部分是自定义,仍有标题按钮等
View dialogView = LayoutInflater.from(this).inflate(R.layout.自定义布局, null);
xx = dialogView.findViewById(R.id.xx);
AlertDialog.Builder builder = new AlertDialog.Builder(this).setView(dialogView)
.setIcon(R.mipmap.图标).setTitle("标题")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
    
    
@Override
public void onClick(DialogInterface dialogInterface, int i) {
    
    
   //根据xx控件的值处理
}
});
builder.create().show();

第三种:view是java创建的控件
final EditText editText = new EditText(this);
其他和第二种一样,只是把editText作为setView()的参数

单选框

xml中:
一个RadioGroup下放入多个RadioButton
activity中:
设置默认选中项:
radioButton.setChecked(true);
选中事件监听:
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
    
    
    @Override
    public void onCheckedChanged(RadioGroup radioGroup, int i) {
    
    
        RadioButton radioButton = (RadioButton)findViewById(radioGroup.getCheckedRadioButtonId());
        String type = radioButton.getText().toString();
        //
    }
});

多选框

xml中:
多个CheckBox
activity中:
设置默认选中项:
checkBox.setChecked(true);
选中事件监听:
activity implements CompoundButton.OnCheckedChangeListener
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
    
    
//(b为点击后是否为选中状态)
//(compoundButton为选中的CheckBox,可用getText().toString()获取值)
}

下拉框

xml中:
一个Spinner
activity中:
Spinner spinner = (Spinner) findViewById(R.id.spinner);
final String[] items = new String[]{
    
    "item1", "item2", "item3", "item4", "item5"};
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setSelection(2);//默认选中项脚标
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    
    
    @Override
    public void onItemSelected(AdapterView adapterView, View view, int i, long l) {
    
    
        //(i为当前点击的项所在items脚标)
        //view可以转换为TextView,然后设置字体样式
    }
    @Override
    public void onNothingSelected(AdapterView adapterView) {
    
    

    }
});

canvas

Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
Paint.Style.STROKE:只画边框
Paint.Style.FILL:只填充内部
Paint.Style.FILL_AND_STROKE:既画边框又填充内部
paint.setAntiAlias(true);//开启抗锯齿
paint.setColor(Color.parseColor("#FF83FA"));
paint.setStrokeWidth(20);
//设置能画渐变背景的paint
SweepGradient mSweepGradient = new SweepGradient(
    渐变中心x,
    渐变中心y,
    new int[]{
    
    颜色、颜色。。。},
    null);
paint.setShader(mSweepGradient);
//画点
canvas.drawPoint(x, y, paint);
//画线
canvas.drawLine(startX, startY, stopX, stopY, paint);
//画矩形
canvas.drawRect(left, top, right, bottom, paint);
//画圆角矩形
canvas.drawRoundRect(left, top, right, bottom, paint, x轴半径, y轴半径, paint);
//画椭圆
canvas.drawOval(left, top, right, bottom, paint);
//画圆
canvas.drawCircle(圆心x, 圆心y, 半径, paint);
//画圆弧
canvas.drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
startAngle:圆弧开始的角度
sweepAngle:圆弧扫描的角度
useCenter:是否将中心点与圆弧连起来形成扇形
//画图片
canvas.drawBitmap(bitmap, left, top, paint);
//画文字
paint.setTextSize(100);
canvas.drawText("文字",文字左侧离左边缘距离,文字下面离上边缘距离,paint);
//如果需要文字居中
paint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float distance = (fontMetrics.bottom - fontMetrics.top)/2 - fontMetrics.bottom;
canvas.drawText(currentStageName,父级中心x,父级中心y+distance,paint);

自定义view

//values下创建attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView">
        <attr name="text" format="string" />
        <attr name="size" format="integer" />
    </declare-styleable>
</resources>
//MyView类
public class MyView extends View {
    
    
    public MyView(Context context, AttributeSet attrs){
    
    
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyView);
        String text = ta.getString(R.styleable.MyView_text);
        int size = ta.getInteger(R.styleable.MyView_size, 100);
        ta.recycle();
    }
    @Override
    protected void onDraw(Canvas canvas) {
    
    
        super.onDraw(canvas);
        //canvas.drawC。。。
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
    
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //尺寸相关操作
    }
}
//布局中放入MyView
app:text="测试text属性"
app:size="200"

从手机相册获取图片

需要权限:android:name="android.permission.READ_EXTERNAL_STORAGE"
打开相册:
Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RESULT_LOAD_IMAGE);
获取图片:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
    
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
    
    
        Uri selectedImage = data.getData();
        String[] filePathColumn = {
    
    MediaStore.Images.Media.DATA};
        Cursor cursor = getContentResolver().query(selectedImage,filePathColumn,null,null,null);
        cursor.moveToFirst();
        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        Bitmap bitmap = getBitmapFromLocalImage(picturePath);
        //
        cursor.close();
    }
}
从图片地址获取bitmap:
private Bitmap getBitmapFromLocalImage(String path){
    
    
    Bitmap bitmap = null;
    try {
    
    
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
        bitmap = BitmapFactory.decodeStream(bis);
        bis.close();
    } catch (FileNotFoundException e) {
    
    
        e.printStackTrace();
    } catch (IOException e) {
    
    
        e.printStackTrace();
    }
    return bitmap;
}

动态获取权限

private void requestPermission(){
    
    
    String permissions[] = {
    
    
            Manifest.permission.READ_EXTERNAL_STORAGE,
            //...
    };
    ArrayList toApplyList = new ArrayList();
    for(String perm : permissions){
    
    
        if(PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this,perm)){
    
    
            toApplyList.add(perm);
        }
    }
    String tmpList[] = new String[toApplyList.size()];
    if(!toApplyList.isEmpty()){
    
    
        ActivityCompat.requestPermissions(this,toApplyList.toArray(tmpList),123);
    }
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    
    
    super.onRequestPermissionsResult(requestCode,permissions,grantResults);
    if (requestCode == 123) {
    
    
        for (int i = 0; i < permissions.length; i++) {
    
    
            if (grantResults[i] == PERMISSION_GRANTED) {
    
    
                Toast.makeText(this, "" + "权限" + permissions[i] + "申请成功", Toast.LENGTH_SHORT).show();
            } else {
    
    
                Toast.makeText(this, "" + "权限" + permissions[i] + "申请失败", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

TextView加载html代码

import static android.text.Html.FROM_HTML_MODE_LEGACY;
textView.setText(Html.fromHtml("HTML代码",FROM_HTML_MODE_LEGACY));

动态改变控件尺寸

ViewGroup.LayoutParams lp = view.getLayoutParams();
lp.width = 宽度;
lp.height = 高度;
view.setLayoutParams(lp);

减数定时器

private CountDownTimer cdt = new CountDownTimer(总执行时间, 每次执行时间间隔) {
    
    
    @Override
    public void onTick(long millisUntilFinished) {
    
    
        //业务逻辑
    }
    @Override
    public void onFinish() {
    
    
        cdt.cancel();
    }
};
cdt.start();

定时器

Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
    
    
    @Override
    public void run() {
    
    
        //业务逻辑
    }
};
timer.schedule(timerTask,延迟的毫秒数,定时执行的毫秒数);
if(timer != null){
    
    
    timer.cancel();
}

ImageView旋转

静态旋转:
xml设置rotation="度数"
动态旋转:
imageView.setPivotX(imageView.getWidth()/2);  
imageView.setPivotY(imageView.getHeight()/2);//支点在图片中心
imageView.setRotation("度数");

EditText内容改变监听

editText.addTextChangedListener(new TextWatcher() {
    
    
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
    
        
    }
    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
    
        
    }
    @Override
    public void afterTextChanged(Editable editable) {
    
    
        //业务逻辑
        //将光标移动到末尾
        //editText.setSelection(editText.getText().length());
    }
});

EditText焦点变化监听

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    
    
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
    
    
        //业务逻辑(hasFocus表示是否获得焦点)
    }
});

循环父布局中的子元素

for (int i = 0;i < linearLayout.getChildCount(); i++){
    
    
    if (linearLayout.getChildAt(i) instanceof TextView) {
    
    
        TextView textView = (TextView)linearLayout.getChildAt(i);
        //业务逻辑
    }
}

彩色阴影

需要引入:implementation 'com.lijiankun24:shadowlayout:1.0.0'
布局xml中:
xmlns:app="http://schemas.android.com/apk/res-auto"
com.lijiankun24.shadowlayout.ShadowLayout
属性:
app:shadowColor="#66000000" 控制阴影的颜色,注意:颜色必须带有透明度的值
app:shadowDx="0dp" 控制阴影 x 轴的偏移量
app:shadowDy="3dp" 控制阴影 y 轴的偏移量
app:shadowRadius="10dp" 控制阴影的范围
app:shadowSide="all|left|right|top|bottom" 控制阴影显示的边界,共有五个值

setText设置拼接字符串

values-strings.xml中:
例:text:字符串%1$s整数%2$d小数%3$f
    %n$s--->n表示目前是第几个参数 (比如%1$s中的1代表第一个参数),s代表字符串
    %n$d--->n表示目前是第几个参数 (比如%2$d中的2代表第二个参数),d代表整数
    %n$f--->n表示目前是第几个参数 (比如%3$f中的3代表第三个参数),f代表浮点数
textView.setText(String.format(getResources().getString(R.string.text),String,int,float));

ScrollView滑到底部或顶部

scrollView.post(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        //滑到底部
        scrollView.fullScroll(View.FOCUS_DOWN);
        //滑到顶部
        scrollView.fullScroll(View.FOCUS_UP);
    }
});

手机振动震动

权限:uses-permission android:name="android.permission.VIBRATE"
初始化:Vibrator vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
判断是否有振动器:vibrator.hasVibrator()
短振动:vibrator.vibrate(1000); // 振动1秒
节奏振动:vibrator.vibrate(new long[]{
    
    500, 1000, 500, 2000}, -1);
// 暂停500毫秒,振动1秒,暂停500毫秒,振动2秒
// 第二个参数为-1则振动一遍,第二个参数为0则重复振动
暂停振动:vibrator.cancel();

屏幕保持常亮

方法一:直接在xml顶层布局中:
android:keepScreenOn="true"

方法二:java中设置:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

从其它线程访问主线程更新UI

方法一:
Activity.runOnUiThread(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        //更新UI
    }
});
方法二:
View.post(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        //更新UI
    }
});
方法三:
view.postDelayed(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        //更新UI
    }
}, 延迟的毫秒数);
方法四:
Handler

猜你喜欢

转载自blog.csdn.net/ccb85209691/article/details/115206445