Android 问题整理 四
// Android限定EditText的输入类型为数字或者英文(包括大小写)
参考:Android限定EditText的输入类型为数字或者英文(包括大小写)
android:digits="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// shape 竖线
参考:Shark出品:Android Shape 实现 垂直 虚线
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<size
android:width="2dp"
android:height="@dimen/dp_60" />
<stroke
android:width="1.5dp"
android:color="#FFCB9D"
android:dashWidth="1.5dp"
android:dashGap="1.5dp" />
</shape>
</item>
<item android:left="0.5dp">
<shape android:shape="rectangle">
<solid android:color="#FFF5ED" />
</shape>
</item>
</layer-list>
// java 正则匹配方法
public static boolean check(String string) {
String regExp = "^1[3456789]{1}\\d{9}$"; // 正则表达式,这里展示的是手机号码,第一个数是1,第二个数不能是0和2 长度11位 纯数字
Pattern p = Pattern.compile(regExp);
Matcher m = p.matcher(string);
return m.find();
}
// webview 闪退
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.util.AttributeSet;
import android.webkit.WebView;
public class LollipopFixedWebView extends WebView {
public LollipopFixedWebView(Context context) {
super(getFixedContext(context));
}
public LollipopFixedWebView(Context context, AttributeSet attrs) {
super(getFixedContext(context), attrs);
}
public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(getFixedContext(context), attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(getFixedContext(context), attrs, defStyleAttr, defStyleRes);
}
public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) {
super(getFixedContext(context), attrs, defStyleAttr, privateBrowsing);
}
public static Context getFixedContext(Context context) {
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23) // Android Lollipop 5.0 & 5.1
return context.createConfigurationContext(new Configuration());
return context;
}
}
// logcat 格式化输出json
原文:https://blog.csdn.net/qingchunweiliang/article/details/51005676
import com.google.gson.Gson;
/**
* json格式化工具
* @author Young
*
*/
public class JsonFormat {
/**
* 默认每次缩进两个空格
*/
private static final String empty=" ";
public static String format(Object json){
if (json == null) {
return "null";
}
String jsonS = "{}";
try {
jsonS = new Gson().toJson(json);
int empty=0;
char[]chs=jsonS.toCharArray();
StringBuilder stringBuilder=new StringBuilder();
for (int i = 0; i < chs.length;) {
//若是双引号,则为字符串,下面if语句会处理该字符串
if (chs[i]=='\"') {
stringBuilder.append(chs[i]);
i++;
//查找字符串结束位置
for ( ; i < chs.length;) {
//如果当前字符是双引号,且前面有连续的偶数个\,说明字符串结束
if ( chs[i]=='\"'&&isDoubleSerialBackslash(chs,i-1)) {
stringBuilder.append(chs[i]);
i++;
break;
} else{
stringBuilder.append(chs[i]);
i++;
}
}
}else if (chs[i]==',') {
stringBuilder.append(',').append('\n').append(getEmpty(empty));
i++;
}else if (chs[i]=='{'||chs[i]=='[') {
empty++;
stringBuilder.append(chs[i]).append('\n').append(getEmpty(empty));
i++;
}else if (chs[i]=='}'||chs[i]==']') {
empty--;
stringBuilder.append('\n').append(getEmpty(empty)).append(chs[i]);
i++;
}else {
stringBuilder.append(chs[i]);
i++;
}
}
return stringBuilder.toString();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return jsonS;
}
}
private static boolean isDoubleSerialBackslash(char[] chs, int i) {
int count=0;
for (int j = i; j >-1; j--) {
if (chs[j]=='\\') {
count++;
}else{
return count%2==0;
}
}
return count%2==0;
}
/**
* 缩进
* @param count
* @return
*/
private static String getEmpty(int count){
StringBuilder stringBuilder=new StringBuilder();
for (int i = 0; i < count; i++) {
stringBuilder.append(empty) ;
}
return stringBuilder.toString();
}
}
// RecyclerView 设置了GridLayoutManager 空白区域点击事件
原地址:https://blog.csdn.net/u013778491/article/details/92829738
recycle_foodl.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (v.getId()!=0 && event.getAction() == MotionEvent.ACTION_UP){
//发现只有点击了空白处,v.getId,才能打印出东西
//可以在此处做文章
goodsAdapter.dimmMissll_edit();
}
return false;
}
});
// recyclerview 的 item 中包含 recyclerview ,外层 recyclerview 无法滑动
外层 recyclerview 添加父布局 ScrollView
外层 recyclerview 的外层建议添加 RelativeLayout
内层 recyclerview 添加属性
android:nestedScrollingEnabled="false"
//USB调试不能弹出授权窗口 unauthorized 的解决办法
1.检查环境变量 https://blog.csdn.net/zhouzme/article/details/51471699
ANDROID_SDK_HOME
C:\Users\Administrator\AppData\Local\Android\Sdk
2.安装Total Control尝试连接
http://download.sigma-rt.com/tc/pc/Total_Control_7_0_0_u2640018_Install_x64.zip
// 读写权限都已经授权,但是还是出现 class java.io.FileNotFoundException: open failed: EACCES (Permission denied)错误
参考:https://blog.csdn.net/tm_6666/article/details/106792314
<application
...
...
android:requestLegacyExternalStorage="true">
</application>
// 融云连接失败,可能是缺少 libsqlite.so 库
// 记录创建的 activity,与 finish() 记录中的 activity
public class ActivityManagerApplication extends Application {
private static Map<String,Activity> destoryMap = new HashMap<>();
/**
* 添加到销毁队列
*
* @param activity 要销毁的activity
*/
public void addDestoryActivity(Activity activity, String activityName) {
destoryMap.put(activityName,activity);
}
/**
*销毁指定Activity
*/
public void destoryActivity(String activityName) {
Set<String> keySet=destoryMap.keySet();
for (String key:keySet){
destoryMap.get(key).finish();
}
}
}
private ActivityManagerApplication activityManagerApplication = new ActivityManagerApplication();
activityManagerApplication.destoryActivity("SplashActivity");
activityManagerApplication.addDestoryActivity(this, "TabMainActivity");
// 隐藏软键盘,隐藏输入法
private InputMethodManager imm;
// public static final String INPUT_METHOD_SERVICE = "input_method"
imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
public void hideInput() {
if (getActivity() != null && getActivity().getCurrentFocus() != null && isInputMethodShow()) {
imm.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
}
public boolean isInputMethodShow() {
return imm.isActive();
}
// 获取 Assets 目录下指定文件的 AssetsFileDescriptor 对象
参考:https://blog.csdn.net/Greathfs/article/details/52123984
// 打开指定音乐文件,获取assets目录下指定文件的AssetFileDescriptor对象
AssetFileDescriptor afd = am.openFd(music);
mPlayer.reset();
// 使用MediaPlayer加载指定的声音文件。
mPlayer.setDataSource(afd.getFileDescriptor(),
afd.getStartOffset(), afd.getLength());
// 准备声音
mPlayer.prepare();
// 播放
mPlayer.start();
// Android 软键盘弹出时把布局顶上去或者覆盖上去需求解决方案
参考:https://blog.csdn.net/lvshuchangyin/article/details/73825933
android:windowSoftInputMode="adjustPan"
<activity
android:name=".surface.activity.EditWorksActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan" />
// Android Studio 清除未使用的资源、未使用的文件、未使用的图片
// mvp 网络请求返回 5000 访问异常,请稍后重试
参考:Gson解析错误
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 22 path $.data
// 微信登录点击同意后报错
参考:android问题:You need to use a Theme.AppCompat theme (or descendant) with this activity.
You need to use a Theme.AppCompat theme (or descendant) with this activity.
当前 Activity 继承的 Activity 与清单文件中使用的主题所使用的的 Activity 的主题不一致。
// Parcelable encountered IOException writing serializable object
参考:https://blog.csdn.net/qq_32452623/article/details/51851002
要解析的实体类以及内部包含的所有实体类都要实现接口 Serializable
// Intent 传递对象 Activity
public static void startSelf(Activity context, boolean view, XXXBean bean, double radius) {
Intent intent = new Intent(context, XXXActivity.class);
// Bundle bundle = new Bundle(1);
// bundle.putSerializable("xxx_bean", bean);
// intent.putExtras(bundle);
intent.putExtra("xxx_bean", bean);
context.startActivityForResult(intent, 1);
}
XXXActivity.startSelf(this, false, mBean, radius);
XXXBean mBean = (XXXBean) getIntent().getSerializableExtra("xxx_bean");
int xxxSize = mBean.getXxxx().size();
// java 中文转Unicode 以及 Unicode转中文
参考:java 中文转Unicode 以及 Unicode转中文
private static String unicodeToCn(String unicode) {
/** 以 \ u 分割,因为java注释也能识别unicode,因此中间加了一个空格*/
String[] strs = unicode.split("\\\\u");
String returnStr = "";
// 由于unicode字符串以 \ u 开头,因此分割出的第一个字符是""。
for (int i = 1; i < strs.length; i++) {
returnStr += (char) Integer.valueOf(strs[i], 16).intValue();
}
return returnStr;
}
// ImageLoader 加载网络图片展示 加载本地图片展示
XBanner xBanner = mItemView.findViewById(R.id.item_xbannerViewPager);
xBanner.setPageTransformer(Transformer.Stack);
xBanner.setBannerData(data.getImages());
xBanner.loadImage(new XBanner.XBannerAdapter() {
@Override
public void loadBanner(XBanner banner, Object model, View view, int position) {
// 加载网络图片展示
ImageLoader.image(context, ((ImageView) view), ((HomePageBean.ImagesBean) model).getImage_url());
// 加载本地图片展示 不需要自定义
// ((ImageView) view).setImageResource((Integer) ((HomePageBean.ImagesBean) model).getXBannerUrl());
}
});
xBanner.setAllowUserScrollable(false);
xBanner.setPointsIsVisible(false);
xBanner.setAutoPalyTime(1000);
xBanner.setAutoPlayAble(false);
/**
* 加载网络图片
*/
public static void image(Context context, ImageView imageView, String url) {
Glide.with(checkContext(context))
.load(checkUrl(url))
.into(imageView);
}
// fragment 可见与不可见
// 解决华为手机,强制离线后无法重新获取首页数据的问题
@Override
public boolean getUserVisibleHint() {//切换到其他activity,再切换回来时执行
presenter.getLocation();
return super.getUserVisibleHint();
}
@Override// 点击我的后 hidden = true 点击首页 hidden = false
public void onHiddenChanged(boolean hidden) {// 使用 show hide 方式切换 fragment,当前 fragment 可见时 hidden 为true
super.onHiddenChanged(hidden);
if (hidden) {
stop();
} else {
presenter.getLocation();
if (isAdded() && UserUtils.getInstance().isLogin()) {
presenter.getMsgNum();
}
changePlay(indexBefore);
}
}
// dialog 、自定义 dialog 自动弹出输入法
参考:https://blog.csdn.net/liang5630/article/details/43482691
public void onTextModeClick() {
if (mTextDialog == null) {
mTextDialog = new EditWorksTextDialog(this, this);
mTextDialog.setOnShowListener(this);
mTextDialog.setOnDismissListener(this);
}
mTextDialog.show();
//设置可获得焦点
mTextDialog.getViewEdit().setFocusable(true);
mTextDialog.getViewEdit().setFocusableInTouchMode(true);
//请求获得焦点
mTextDialog.getViewEdit().requestFocus();
InputMethodUtils.show(mTextDialog.getViewEdit());
}
// dispatchTouchEvent 拦截、监听是否点击了某一个view
参考1:Android dispatchTouchEvent检测多点触摸事件是否落入在某一个View区域内
参考2:Android 判断触摸点是否在某个view的区域,解决子view与parent的touch事件冲突
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
float x = event.getRawX();
float y = event.getRawY();
if (touchEventInView(text1, x, y)) {
Toast.makeText(this, "text1", Toast.LENGTH_SHORT).show();
}
if (touchEventInView(text2, x, y)) {
Toast.makeText(this, "text2", Toast.LENGTH_SHORT).show();
}
return super.dispatchTouchEvent(event);
}
/**
* 该方法检测一个点击事件是否落入在一个View内,换句话说,检测这个点击事件是否发生在该View上。
*
* @param view
* @param x
* @param y
* @return
*/
private boolean touchEventInView(View view, float x, float y) {
if (view == null) {
return false;
}
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
if (y >= top && y <= bottom && x >= left && x <= right) {
return true;
}
return false;
}
//(x,y)是否在view的区域内
private boolean isTouchPointInView(View view, int x, int y) {
if (view == null) {
return false;
}
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
//view.isClickable() &&
if (y >= top && y <= bottom && x >= left
&& x <= right) {
return true;
}
return false;
}
// 实现View的拖拽,拖动控件
public class MainActivity extends AppCompatActivity {
private TextView text;
double lastx;
double lastY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
text = (TextView) findViewById(R.id.text);
text.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
double x=event.getRawX();
double y=event.getRawY();
// Log.d(TAG, "onTouch: "+event.getAction());
if (event.getAction()==MotionEvent.ACTION_DOWN){
lastx=x;
lastY=y;
}else if (event.getAction()==MotionEvent.ACTION_MOVE){
double dx=x-lastx;
double dy=y-lastY;
// Log.d(TAG, "onTouch: dx=="+dx+",dy=="+dy);
// startAnimation(dx,dy);
// moveMethod1(dx, dy);
moveMethod2(dx, dy);
lastx=x;
lastY=y;
}
// text.setTranslationX(x);
return true;
}
});
}
//根据属性动画的原理
private void moveMethod2(double dx, double dy) {
text.setTranslationX((float) (text.getTranslationX()+dx));
text.setTranslationY((float) (text.getTranslationY()+dy));
}
//根据margin 原理
private void moveMethod1(double dx, double dy) {
ViewGroup.MarginLayoutParams marginLayoutParams= (ViewGroup.MarginLayoutParams) text.getLayoutParams();
marginLayoutParams.leftMargin+=dx;
marginLayoutParams.topMargin+=dy;
text.setLayoutParams(marginLayoutParams);
}
private void startAnimation(double dx, double dy) {
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(text,"translationX", (float) (text.getTranslationX()+dx)).setDuration(3000);
objectAnimator.start();
ObjectAnimator objectAnimator2=ObjectAnimator.ofFloat(text,"translationY", (float) (text.getTranslationY()+dy)).setDuration(3000);
objectAnimator2.start();
}
}
// 包名,Android 获取当前屏幕上显示的 activity
C:\Users\Administrator>adb shell dumpsys window | findstr mCurrentFocus
mCurrentFocus=Window{614737a u0 cn.xuexi.android/com.alibaba.android.rimet.biz
.home.activity.HomeActivity}
C:\Users\Administrator>adb uninstall cn.xuexi.android
Success
C:\Users\Administrator>
// 隐藏华为手机虚拟按键,底部虚拟按键
protected void hideBottomUIMenu() {
//隐藏虚拟按键,并且全屏
if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
View v = this.getWindow().getDecorView();
v.setSystemUiVisibility(View.GONE);
} else if (Build.VERSION.SDK_INT >= 19) {
//for new api versions.
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
}
// 启动第三方app工具类
/**
* 描述: 启动第三方app工具类
*
* @author hujw
* @date 2019/9/20 0020
*/
public final class LaunchAppUtils {
/**
* 这里是判断APP中是否有相应APP的方法
*
* @param context 上下文对象
* @param packageName 需要跳转的app包名
* @return
*/
public static boolean isAppInstalled(Context context, String packageName) {
try {
context.getPackageManager().getPackageInfo(packageName, 0);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 启动第三方app
*/
public static void launchApp(Context context,String appPackageName) {
if (isAppInstalled(context, appPackageName)){
context.startActivity(context.getPackageManager().getLaunchIntentForPackage(appPackageName));
}else{
ToastMaker.showShort("请先安装此App");
}
}
}
// Android studio 打包输出配置
// 执行配置
applicationVariants.all { variant ->
// Apk 输出配置
variant.outputs.all { output ->
def appName = "Jwcy110"
if (variant.buildType.name == 'debug') {
outputFileName = appName + '_v' + versionName + '_' + variant.buildType.name + '.apk'
} else {
outputFileName = appName + '_v' + versionName + '_' + new Date().format("yyyyMMdd") + '_' + variant.buildType.name + '.apk'
}
}
}