Android遇到的问题整理
1、从同一个Activiy的一个Fragment跳转到另外一个Fragment
2、从一个Activity的Fragment跳转到另外一个Activity
3、从一个Activity跳转到另外一个Activity的Fragment上
4、从一个Activity的Fragment跳转到另外一个Activity的Fragment上
2.从A Activity跳转到B Activity B完成操作后返回A 并刷新A页面
使用 DialogFragment显示对话框,而非Dialog/AlertDialog
XRecyclerView父级item镶嵌子级XRecyclerView
1. 全局配置
-
安卓9请求网络适配问题
AndroidManifest.xml文件的application标签里加上
android:networkSecurityConfig="@xml/network_security_config"
<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
xml下的network_security_config文件
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:android="http://schemas.android.com/apk/res/android">
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
<!-- 安卓9.0适配通知栏 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-
添加权限
<!-- 引入的第三方库最低支持版本高于我的项目的最低支持版本 -->
<uses-sdk tools:overrideLibrary="com.acker.simplezxing" />
//自动更新允许安装的权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
-
安卓12中部分属性说明
android:exported属性
Android 12 中包含
<intent-filter>
的activity
、service
或receiver
必须为这些应用组件显示声明android:exported
属性。android:exported
属性的默认值取决于是否包含<intent-filter>
,如果包含<intent-filter>
那么默认值为 true,否则 false。
android:exported="true"
如果不做任何处理,可以接受来自其他 App 的访问android:exported="false"
限制为只接受来自同一个 App 或一个具有相同user ID
的 App 的访问
android:allowBackup属性
android:allowBackup
属性默认值为 true,为了提供 App 数据备份和恢复功能。发布的 Apk 中一定要将android:allowBackup
属性设置为 false,来关闭应用程序的备份和恢复功能,以免造成信息泄露。
-
获取全局context
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext(){
return context;
}
2. 页面跳转
防止快速点击,打开重复页面
//BaseActivity定义一个变量,用来控制是否可以打开页面
private boolean switchPage;
/**
* 防止快速点击
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
if (switchPage) {
return true;
}
}
return super.dispatchTouchEvent(ev);
}
@Override
public void startActivity(Intent intent, Bundle bundle) {
switchPage = true;
super.startActivity(intent, bundle);
}
@Override
protected void onResume() {
switchPage = false;
super.onResume();
}
Activity-Fragment的跳转
1、从同一个Activiy的一个Fragment跳转到另外一个Fragment
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.xx, new XxxFragment(), null)
.addToBackStack(null)
.commit();
说明:
R.id.xx:Fragment对应的Activity布局中FragmentLayout的id
new XxxFragment():要跳转到的Fragment
addToBackStack(null):可以省略不写(不写表示为非压栈式添加)
2、从一个Activity的Fragment跳转到另外一个Activity
此跳转与Activity之间的跳转如出一辙,只是引用上下文的时候,写成getActivity()即可!
Intent intent = new Intent(getActivity(),OtherActivity.class);
startActivity(intent);
3、从一个Activity跳转到另外一个Activity的Fragment上
例如我们要从OtherActivity跳转到MainActivity的YourFragment上去:
首先,我们在OtherActivity中的跳转事件中给MainActivity传递一个名为id的参数:
Intent intent = new Intent(OtherActivity.this, MainActivity.class);
intent.putExtra("id",1);
startActivity(intent);
然后,我们在MainActivity里接收id值,对值进行判断,如果正确进行跳转操作:
int id = getIntent().getIntExtra("id", 0);
if (id == 1) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container,new YourFragment())
.addToBackStack(null)
.commit();
}
4、从一个Activity的Fragment跳转到另外一个Activity的Fragment上
这种跳转与第三种跳转极为类似
首先,在对应的Fragment跳转事件中书写
Intent intent = new Intent(getActivity(), MainActivity.class);
intent.putExtra("id",1);
startActivity(intent);
然后,我们在MainActivity里接收id值,对值进行判断,如果正确进行跳转操作:
int id = getIntent().getIntExtra("id", 0);
if (id == 1) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container,new YourFragment())
.addToBackStack(null)
.commit();
}
3. 页面传值
使用intent传递对象
A页面
intent.putExtra("key",123)
B页面
Intent intent = getIntent();
String count = intent.getStringExtra( "key" ) ;
bean类 implements Serializable 序列化
Bean bean = (Bean) getIntent().getSerializableExtra("key");
传递数组
1.单纯的传递List<String> 或者List<Integer>
intent.putStringArrayListExtra(key, value)
intent.putIntegerArrayListExtra(key, value)
2.传递List<Object>
//传递list
intent.putExtras(key, (Serializable)list)
//获取list (bean类要记得实现Serializable接口 )
(List<ListBean>) getIntent().getSerializable(key)
Bundle bundle=new Bundle();
bundle.putSerializable(key,(Serializable) list);
intent.putExtras(bundle);
EventBus的使用
添加依赖:implementation 'org.greenrobot:eventbus:3.2.0'
示例B传数据给A页面
A页面(接收数据页面)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
/**
* 事件响应方法
* 接收消息
* @param
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(List<IDBean> list) {
//带过来添加的数据列表
for (IDBean bean : list) {
mTaskList.add(bean);
}
mAdapterTask.notifyDataSetChanged();
}
B页面(发送数据页面)
EventBus.getDefault().post(taskList);
A页面
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().removeAllStickyEvents();
EventBus.getDefault().unregister(this);
}
/**
* 事件响应方法
* 接收消息
* @param
*/
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onEvent(List<FillTaskBean> list) {
//带过来添加的数据列表
for (FillTaskBean bean : list) {
mTaskList.add(0, bean);
}
mAdapterTask.notifyDataSetChanged();
}
B页面
EventBus.getDefault().postSticky(taskList);
4. 页面数据刷新
1.并未发生跳转可以通过广播来实现
A Activity
Intent intent_refresh = new Intent();
intent_refresh.setAction("action.refreshList");
sendBroadcast(intent_refresh);
B Activity(需要刷新的界面)
onCreate方法中注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("action.refreshList");
registerReceiver(mRefreshBroadcastReceiver, intentFilter);
private BroadcastReceiver mRefreshBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("action.refreshList"))
{
mXrvTaskManageNo.refresh();
Log.e( TAG, "刷新列表" );
}
}
};
onDestroy方法中注销广播
unregisterReceiver(mRefreshBroadcastReceiver);
2.从A Activity跳转到B Activity B完成操作后返回A 并刷新A页面
A Activity(需要刷新的页面)
Intent intent= new Intent(AActivity.this,BActivity.class);
startActivityForResult(intent,0);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == Activity.RESULT_OK){
switch (requestCode){
case 0:
mXrvList.refresh();
break;
}
}
}
B Activity(跳转到的页面)
执行完操作后
setResult(RESULT_OK);
finish();
5. 关于生命周期
-
onCreate
- 调用 setContentView 方法设置布局
- 定义成员变量,初始化数据
- 初始化视图、控件、UI 元素
- 配置 UI,将数据绑定到列表等
- 将 Activity 与 ViewModel 相关联
应尽量减少 onCreate 的工作量,避免程序启动太久而看不见界面。可以通过 savedInstanceState 参数恢复一些状态,如果是第一次创建则为 null 需要做判空处理
-
onStart
- 注册监听 UI 变化的广播
- 把在 onStop 中释放的资源重新创建回来
-
onResume
- 把 onPause 中停止的操作恢复回来,如 Camera 预览
- 开始动画
-
onPause
- 释放系统资源,传感器(例如 GPS)手柄、Camera 等
- 停止动画
不应该在这里保存应用或用户数据、进行网络调用或执行数据库事务;地图导航页面一般不在这里释放,因为希望它仍然能够继续工作;应最大程度减少 onPause 的工作量,避免 Activity 切换缓慢卡顿
-
onStop
释放那些不再需要的资源
按需从精确位置更新切换到粗略位置更新
关闭那些 CPU 执行相对密集的操作
将用户内容(如邮箱草稿)保存到持久性存储空间
用户首选项持久性数据或数据库中的数据
停止通过 Service 定时更新 UI 上的数据的 Service
可以在这里保存应用或用户数据、进行网络调用或执行数据库事务
-
onDestoty
- 应释放先前的回调(如 onStop )尚未释放的所有资源
不推荐在 onDestroy 里执行释放资源的工作,因为 onDestroy 执行的时机可能较晚,可根据实际需求在onPause 或 onStop 中结合 isFinishing 判断来执行
6. 接口相关
请求接口
1. .params( "参数名", 参数值 )
2. 地址拼接 ?参数名=+参数值&
3. 传json对象 { "username":"username", "type":"type"}
Map<String, Object> params = new HashMap<>();
params.put("username", username);
params.put("type", type);
JSONObject jsonObject=new JSONObject( params );
.tag( this )
.upJson( jsonObject )
4.传json数组 [{"id":"12345"},{"id":"12345"},{"id":"12345"}]
public class IDBean implements Serializable {
private String Id;
public String getId() {
return Id;
}
public void setId(String id) {
Id = id;
}
}
List<IDBean> idsList = new ArrayList<>();
IDBean iDBean = new IDBean();
iDBean.setId(list.get( i ).getId());
idsList.add(iDBean);
打印:new Gson().toJson(idsList);
JSONArray json = new JSONArray();
try {
for(IDBean bean : idsList) {
JSONObject objects = new JSONObject();
objects.put("id", bean.getId());
json.put(objects);
}
} catch (JSONException e) {
e.printStackTrace();
}
.upJson(json)
5.接口传idsList(在json里面)
List<Map<String, String>> list = new ArrayList<>();
for(IDBean bean:idsList){
Map<String, String> img = new HashMap<>();
img.put("id",bean.getId());
list.add(img);
}
Map<String, Object> params = new HashMap<>();
params.put("list", list);
JSONObject jsonObject=new JSONObject( params );
.upJson( jsonObject)
JSONArray jsonArray = new JSONArray();
JSONObject tmpObj = null;
for(int i = 0; i < idsList.size(); i++) {
try {
tmpObj = new JSONObject();
tmpObj.put("id" , idsList.get(i).id);
jsonArray.put(tmpObj);
tmpObj = null;
} catch (JSONException e) {
e.printStackTrace();
}
}
Map<String, Object> params = new HashMap<>();
params.put("list", jsonArray);
JSONObject jsonObject=new JSONObject( params );
接口返回数据解析
//如果返回的是ARRAY[] 如[{"id":"12345"},{"id":"12345"},{"id":"12345"}]
Gson gson = new Gson();
Type listType = new TypeToken<List<Bean>>() {}.getType();
ArrayList<Bean> bean = gson.fromJson(response.body(), listType);
7. 工具类
二维码扫描出现中文乱码问题
private String recode(String str) {
String formart = "";
try {
boolean ISO = Charset.forName("ISO-8859-1").newEncoder()
.canEncode(str);
if (ISO) {
formart = new String(str.getBytes("ISO-8859-1"), "GB2312");
} else {
formart = str;
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return formart;
}
延时执行一段操作
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
//这里写要执行的操作
timer.cancel();
}
}, 2000);
Handler handler = new Handler(Looper.myLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//执行操作
}
}, 2000);
隐藏软键盘
<!-- 在manifest.xml中activity中设置 -->
<!--
adjustPan --整个界面向上平移,输入框在软键盘上方
adjustResize --如果界面中没有滑动控件,获取了焦点的控件可能会被软键盘盖住
-->
<activity
android:name="LoginActivity"
android:exported="false"
android:windowSoftInputMode="stateVisible|adjustResize"/>
/**
* 动态隐藏软键盘
*/
public static void hideSoftInput(Activity activity) {
View view = activity.getWindow().peekDecorView();
if (view != null) {
InputMethodManager inputmanger = (InputMethodManager) activity
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
/**
* 动态隐藏软键盘
*/
public static void hideSoftInput(Context context, EditText edit) {
edit.clearFocus();
InputMethodManager inputmanger = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputmanger.hideSoftInputFromWindow(edit.getWindowToken(), 0);
}
/**
* 动态显示软键盘
*/
public static void showSoftInput(Context context, EditText edit) {
edit.setFocusable(true);
edit.setFocusableInTouchMode(true);
edit.requestFocus();
InputMethodManager inputManager = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(edit, 0);
}
点击屏幕空白区域隐藏软键盘
/**
* 在onTouch中处理,未获焦点则隐藏
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (null != this.getCurrentFocus()) {
InputMethodManager mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
return mInputMethodManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
}
return super.onTouchEvent(event);
}
8. 页面显示优化
NiceSpinner修改默认样式
- 设置padding
//左上右下
mSpinner.setPadding(10, 0, 10, 0);
- 设置背景边框
mSpinner.setBackgroundResource(R.drawable.shape_gray_white);
EditText的监听中setText
edittext中输入的文字不原样显示而是经过处理后显示
edittext.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (edittext.hasFocus()) {
String count = s.toString().trim();
edittext.removeTextChangedListener(this);
if ("".equals(count)) {
edittext.setText("0");
} else {
//去掉开头的0,比如输入032自动显示为32
edittext.setText(s.toString().replaceFirst("^0*", ""));
}
edittext.addTextChangedListener(this);
String count1 = edittext.getText().toString().trim();
//将光标移动至结尾
edittext.setSelection(count1.length());
}
}
});
ViewPager顶部导航分栏
Intent intent = new Intent(this,Activity.class);
intent .putExtra("item",3);
startActivity(intent );
if(getIntent().getIntExtra("item",0) == 0){
mViewPager.setCurrentItem(0); //初始化显示第一个页面
}
原生AlertDialog修改样式
原生AlertDialog修改确定按钮颜色/字号
AlertDialog.Builder builder = new AlertDialog.Builder(LoginActivity.this);
TextView tv = new TextView(LoginActivity.this);
tv.setText("标题");
tv.setTextSize(26);
tv.setTextColor( Color.parseColor("#ff4081"));
tv.setPadding(70, 60, 20, 10);
builder.setCustomTitle(tv)
.setCancelable(false)
.setMessage("内容")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
.......
}
});
AlertDialog alertDialog = builder.create();
alertDialog.show();
//修改 确定取消 按钮的字体大小
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextSize(26);
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.BLUE);
原生AlertDialog修改按钮
Button button = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
LinearLayout.LayoutParams cancelBtnPara = (LinearLayout.LayoutParams)button.getLayoutParams();
//设置按钮的大小
cancelBtnPara.height = LinearLayout.LayoutParams.WRAP_CONTENT;
cancelBtnPara.width = LinearLayout.LayoutParams.MATCH_PARENT;
//设置文字居中
cancelBtnPara.gravity = Gravity.CENTER;
//设置按钮左上右下的距离
cancelBtnPara.setMargins(100, 20, 100, 20);
button.setLayoutParams(cancelBtnPara);
button.setBackground(ContextCompat.getDrawable(this, R.drawable.food_subsidy_bg));
button.setTextColor(ContextCompat.getColor(this, R.color.white));
button.setTextSize(16)
使用 DialogFragment显示对话框,而非Dialog/AlertDialog
public void showPromptDialog(String text){
DialogFragment promptDialog = new DialogFragment() {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
View view = inflater.inflate(R.layout.fragment_prompt, container);
return view;
}
};
promptDialog.show(getFragmentManager(), text);
}
TextView设置颜色
不能直接TextView.setTextColor(R.Color.red)
TextView.setTextColor(getResources().getColor(R.Color.red))
TextView.setTextColor(ContextCompat.getColor(this,R.Color.red))
TextView.setTextColor(Color.parseColor("#e74c3c"))
TextView长按不弹出复制、粘贴框
报错提示:TextView does not support text selection. Selection cancelled.
解决方法:
1.TextView设置宽度 android:layout_width="wrap_content"
2.去掉页面中隐藏软键盘的方法
XRecyclerView父级item镶嵌子级XRecyclerView
//点击子级item跟点击父级实现相同的效果
holder.xrvItem.setOnTouchListener((v, event) -> {
if(event.getAction() == MotionEvent.ACTION_UP){
//响应父级xrv的item的点击事件
holder.itemView.performClick();
}
return false;
});
//子级点击获取父级的position
/**
* 子级item点击事件
* @param position 父级position
* @param tag 子级position
*/
public void OnPositionClickListener(int position, int tag) {
KLog.e(position + "---" + tag);
}
//子级Adapter
private class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemAdapterHolder> {
private final List<String> adapterList;
private Context mContext;
private int mPosition;
public ItemAdapter(Context context,List<String> list, int position) {
adapterList = list;
mContext = context;
mPosition = position;
}
public void setPosition(int position) {
this.mPosition = position;
}
//部分省略...
holder.itemView.setOnClickListener(v -> {
final int position = holder.getAbsoluteAdapterPosition() - 1;
((InventoryActivity) mContext).OnPositionClickListener(mPosition,position);
});
//部分省略...
}
9. 图片相关
图片着色器—ImageView的tint属性
ps:只针对单一透明的图片
<ImageView
style="@style/ImageView1"
android:background="@drawable/account"
android:backgroundTint="@color/colorAccent"/>
<ImageView
style="@style/ImageView1"
android:src="@drawable/account"
app:tint="@color/colorAccent"/>
ImageView显示问题
<!-- ImageView一边固定一边为wrap_content的时候,设置adjustViewBounds为true让ImageView的比例和原始图片一样,以达到让图片充满的ImageView的效果 -->
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:layout_centerInParent="true"
android:src="@drawable/image">
</ImageView>
10. 开发中遇到的问题及解决
- 问题描述:登录后按<home>键回到桌面,再打开app需要重新登录
-
//登录setContentView之前加上一下代码 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0){ finish(); return; } setContentView(R.layout.activity_login); }
11. 调试工具Stetho
- Stetho插件,在Chrome上查看网络请求https://github.com/facebook/stetho
implementation 'com.facebook.stetho:stetho:1.6.0'
implementation 'com.facebook.stetho:stetho-okhttp3:1.6.0'
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
Stetho.initializeWithDefaults(this);
}
}
new OkHttpClient.Builder()
.addNetworkInterceptor(new StethoInterceptor())
.build()