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);
    }
    
posted @ 2022-11-02 21:14  z5onk0  阅读(146)  评论(0编辑  收藏  举报