Android Studio编程遇到的问题和常用模式总结
起源
一个学精神医科的朋友写论文需要做交互性的实验,让我帮忙做一套APP,主要用于测试病人反应速度,需要在移动端上实现,python-for-android部署起来很折腾,做成网页版的话还需要学习js和租服务器,所以选择了Android Studio编程的解决方案,用了两天时间,简单学习了一下环境部署和开发,写了三个pygame demo级别的小游戏,程序逻辑很简单,但在环境部署和平台接口使用上踩了不少坑,比如线程里只能通过handler修改UI、让人头大的组件叠加问题和app中计时问题,耗了较多时间才找到解决方案,毕竟是对Android编程不熟悉...,总结了一下遇到的问题
坑点
创建项目后AppCompatActivity报错问题
- Android Studio的项目在代码正常的情况下有时会出现“Cannot resolve symbol ‘AppCompatActivity’”错误,相关java文件名字下会显示红色波浪线,解决方案为:
- 先在你放这些项目的文件夹下找到该项目。
- 点击该项目,找到.idea文件
- 进入.idea,把东西全选删除掉
每次打开项目时需要重新下载gradle的问题
-
需要在gradle-wrapper.properties更改
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
-
使用下载工具下载gradle
-
替换本地gradle
- 完全关闭AS,包括正在下载gradle的进程也需要关闭。进入到本地的gradle存储目录,我的是~/.gradle/wrapper/dists
- 把gradle-2.14.1-all.zip文件复制到 gradle-2.14.1-all/8bnwg5hd3w55iofp58khbp6yv 目录下,同时把该目录下的其他文件删除掉。这个8bnwg5hd3w55iofp58khbp6yv是由AS自动生成的,不能更改。
-
断开网络(一定要先断开!),重新打开AS,会自动解压并生成文件。至此gradle更新完成。
增加按钮样式的问题
-
res\drawable文件夹下,增加blue_circle.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <!-- 填充颜色 --> <solid android:color="#30CCF3" /> <!-- 设置按钮的四个角为弧形 --> <!-- android:radius 弧形的半径 --> <corners android:radius="360dip" /> <!-- padding: Button 里面的文字与Button边界的间隔 --> <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" /> </shape>
-
在activity_main.xml文件中增加引用
android:background="@drawable/blue_circle
-
如果颜色改变不了,打开 values 下面的themes.xml 文件
在 <style name="Theme.MyAppCh5" parent="Theme.MaterialComponents.DayNight.DarkActionBar">里面parent的值最后面加上 .Bridge 即改成 <style name="Theme.MyAppCh5" parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge">
设置组件属性
//字体大小
android:textSize="20sp"
//设置居中对齐
android:layout_gravity="center"
设置横屏问题
-
布局文件下
android:screenOrientation="landscape"
-
在res文件目录下,创建Android Resource File
子线程中不能修改UI的问题
-
子线程中不能修改组件布局,通过printStackTrace可以看到报错
-
如果需要修改,请使用handler的消息机制
Thread t = new Thread(){ @Override public void run(){ thisTime = System.currentTimeMillis(); if (thisTime - downTime >= randomTime) { Message msg = handler.obtainMessage(); msg.obj = "请迅速点击黄点"; handler.sendMessage(msg); } try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } }; t.start(); } Handler handler = new Handler() { //通过匿名内部类继承重写了Handler类的handleMessage方法 @Override public void handleMessage(Message msg){ super.handleMessage(msg); TextView text1 = findViewById(R.id.textView); text1.setText(String.valueOf(msg.obj)); } };
组件叠加顺序问题
-
控制组件的遮挡顺序,尝试了bringToFront、RalativeLayout、android:layout_above都不好使
-
最后使用FrameLayout和设置z轴坐标实现组件遮挡
//设置z轴坐标 android:elevation="2dp"
动态调整布局方法
//查找组件,只能在onCreate后使用
findViewByID(R.id.textView1)
//设置标题
view.setText("");
//加载资源
Drawable drawable =getContext().getResources().getDrawable(R.drawble.name)
//设置可见性
view.setVisibility(View.INVISIBLE/Gone/VISIBLE);
Layout定位组件问题
-
ConstraintLayout:将鼠标放到组件上,将四个点分别拉到边缘上,即可手动拖拽
-
RelativeLayout:需要设置组件相对位置
-
FrameLayout:首先设置边缘对齐,然后设置距离
android:layout_gravity="bottom|right" android:layout_marginRight="750px" android:layout_marginBottom="950px"
打包apk问题
- build->generate signed bundle or apk->选apk,next
- 选择jks密钥文件,如果没有,需要先生成一个,方法是notepad保存一个空的jks文件
- 随便设置一个密码,key alias生成密钥时会自动获取
- 点击next,选择relead或debug版本,实测debug版本更稳定
常用编程模式
设置按钮监听和响应事件
-
单个按钮监听,通过内部匿名类实例化onTouchListener接口,实现onTouch方法
startButton.setOnTouchListener(new View.OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event){ if (event.getAction() == MotionEvent.ACTION_DOWN){ Thread t = new Thread(){ @Override public void run(){ ...... } }; t.start(); } else { ...... } return false; } });
-
可以同时监听多个按钮,通过switch和按钮ID来区分
for(Integer buttonID:mapBigCircle.values()){ findViewById(buttonID).setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v){ if (v.getId()==randomID){ ...... } else { ...... } } }); }
获取随机组件
public void gen_random_circle(){
Random rand = new Random();
randomInt = rand.nextInt(4) + 1;
Integer ID = mapSmallCircle.get(randomInt);
randomCircle = findViewById(ID);
}
public void buildMap(){
mapSmallCircle.put(1, R.id.textView1);
mapSmallCircle.put(2, R.id.textView2);
mapSmallCircle.put(3, R.id.textView3);
}
计时器
-
尝试了线程中handler等方法不好用,最后还是Timer类好使
protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); MainActivity.this.baseTimer = SystemClock.elapsedRealtime(); timerView = (TextView) this.findViewById(R.id.textView8); final Handler startTimehandler = new Handler(){ public void handleMessage(android.os.Message msg) { if (null != timerView) { timerView.setText((String) msg.obj); } } }; new Timer("计时器").scheduleAtFixedRate(new TimerTask() { @Override public void run() { int time = (int)((SystemClock.elapsedRealtime() - MainActivity.this.baseTimer) / 1000); String hh = new DecimalFormat("00").format(time / 3600); String mm = new DecimalFormat("00").format(time % 3600 / 60); String ss = new DecimalFormat("00").format(time % 60); String timeFormat = new String(hh + ":" + mm + ":" + ss); Message msg = new Message(); msg.obj = timeFormat; startTimehandler.sendMessage(msg); } }, 0, 1000L); //一秒刷新一次 super.onCreate(savedInstanceState); }