Android Studio 学习实例记录-手电筒
刚安装好Android Studio3.1.2,上网搜了一个实例进行实践学习,仅用这篇文章来记录学习过程
MainActivity.java的源码来自博客:
https://blog.csdn.net/Frakie_Kwok/article/details/66973695
一、在Android studio上建立一个新的工程
File-New-New Project
Next,
next,选择empty activity
Next,
点击Finish,工程建立完成
二、布局页面
进入app-res-layout-activity_main.xml文件
选择可视界面
当时我点击了Design之后,可视界面里面没有任何显示,这个问题和API level有关,解决方法参考我另外一篇博客:
https://blog.csdn.net/ficey/article/details/80351933
可视界面能正常显示之后,删除默认的textview控件,右键删除
然后添加一个button控件和一个toggle button控件,直接选中button和toggle butto拖拽到图上就行
button和toggle button后面的标注会是一个红色的感叹号,鼠标放在感叹号上它会提示说:This view is not constrained, it only has designtime positions, so it will jump to (0,0)...
这里报错的意思是说:这个view没有被约束,他只有设计时的位置,所以他将会跳到(0,0),除非你添加约束。也就是说组件没有锁定,可能会导致重合。所有的组件都不重叠
button控件后面标注为红色感叹号,控件提示view is not constrained...的解决方法:
1、对于Android studio3.0以前的版本,在Design中,对着活动点击右键,选择Constraint Layout----->Infer Constraints
2、对于Android studio 3.1.2版本,点击图上的这个魔法棒,也就是infer constraints工具
然后就可以看到红色感叹号的标注消失了,修改成功。
三、在MainActivity.java中添加源码
按照文章开头提到的博客地址,将源码添加到MainActivity.java中
四、添加权限
在AndroidManifest.xml添加调用摄像头的权限:
五、设置apk的名字和显示的图片
apk名字:在app-res-values-strings.xml文件中,红框标注的地方修改为我们apk的名字,如手电筒。
apk图片:在app-res-drawable里,右键点击drawable,选择New-Image Asset
在弹出的窗口里,在Path里选择自己所在图片的路径,一直next,直到Finish。(我在这里没有替换图片,直接用的默认图片,所以没有操作这一步)
六、编译程序并安装到手机
使用USB线将手机连上电脑,打开手机的USB调试,然后点击这个绿色的三角形,程序会编译并且自动将apk安装到手机,有的手机上可能会弹出一个是否安装的提示,点击确定安装,我的手机没有提示,直接就可以安装了
七、调试
以为到第六步就结束了??并没有,如果代码ok的话,那按照第六步就可以完成这次实践了。但是在编译的时候报错了!!!!
来,一起回顾一下这次遇到的问题
1、AAPT2 error:check logs for details
关于这个问题的解决方法请参考我的另外一篇博客:
https://blog.csdn.net/ficey/article/details/80496660
2、找不到符号,变量id,位置:类R
双击报错跳转到代码里报错的位置,分别是这三句:
Button open_btn = (Button) findViewById(R.id.open_btn);
Button close_btn = (Button) findViewById(R.id.close_btn);
ToggleButton toggle_btn = (ToggleButton) findViewById(R.id.toggle_btn);
查看activity_main.xml文件,可以看到button id斜线后面跟的分别是button和toggleButton
所以对应的R.id.后面要跟对应的符号,修改为:
Button open_btn = (Button)findViewById(R.id.button);
Button close_btn = (Button) findViewById(R.id.button);
ToggleButton toggle_btn = (ToggleButton)findViewById(R.id.toggleButton);
3、匿名...不是抽象的,并且未覆盖OnCheckedChangeListener中的抽象方法onCheckedChanged
报错的语句是:
ToggleButton toggle_btn = (ToggleButton)findViewById(R.id.toggleButton);
toggle_btn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
//@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
try{
manager.setTorchMode("0",isChecked);
}catch (CameraAccessException e){
e.printStackTrace();
}
}
});
遇到这个问题的时候上网搜索了相关的解答,网上的方法都试了一下,对于我的代码没有效果,最后是重新拼写了代码就正常了,可能是拼写错误,没有注意到
4、手电筒无响应,停止运行
上面的三个问题解决之后,再编译就可以编译成功并且成功安装到手机上了,有一丢丢小开心~~~,在手机上点击这个应用打开,提示手电筒无响应,停止运行,什么鬼。。。。。。
继续debug。。。。。。
手机连上电脑,使用adb抓取log
抓取log命令:
adb logcat -s "AndroidRuntime"
1)查看打印出来的log信息:
05-29 17:10:45.127 16199 16199 E AndroidRuntime: Process: com.example.wd.flashlight, PID: 16199
05-29 17:10:45.127 16199 16199 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.wd.flashlight/com.example.wd.flashlight.MainActivity}: java.lang.IllegalStateException: Already attached
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2768)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2833)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.app.ActivityThread.-wrap12(ActivityThread.java)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1561)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:110)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.os.Looper.loop(Looper.java:203)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6354)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1111)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:972)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: Caused by: java.lang.IllegalStateException: Already attached
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.attachController(FragmentManager.java:2871)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.support.v4.app.FragmentController.attachHost(FragmentController.java:104)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:317)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:85)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at com.example.wd.flashlight.MainActivity.onCreate(MainActivity.java:27)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:6694)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1121)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2721)
05-29 17:10:45.127 16199 16199 E AndroidRuntime: ... 9 more
看到
Caused by: java.lang.IllegalStateException: Already attached
AndroidRuntime: at com.example.wd.flashlight.MainActivity.onCreate(MainActivity.java:27)
在MainActivity.java文件中找到报错的位置:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
super.onCreate(savedInstanceState);
这里onCreate调用了两次,修改为:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//super.onCreate(savedInstanceState);
2)重新编译安装,仍然报无响应,停止运行,继续使用adb抓log
查看log打印信息:
05-30 11:21:54.508 9395 9395 E AndroidRuntime: Process: com.example.wd.flashlight, PID: 9395
05-30 11:21:54.508 9395 9395 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.wd.flashlight/com.example.wd.flashlight.MainActivity}: java.lang.ClassCastException: android.widget.Button cannot be cast to android.widget.ToggleButton
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2768)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2833)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.app.ActivityThread.-wrap12(ActivityThread.java)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1561)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:110)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.os.Looper.loop(Looper.java:203)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6354)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1111)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:972)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: Caused by: java.lang.ClassCastException: android.widget.Button cannot be cast to android.widget.ToggleButton
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at com.example.wd.flashlight.MainActivity.onCreate(MainActivity.java:57)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:6694)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1121)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2721)
05-30 11:21:54.508 9395 9395 E AndroidRuntime: ... 9 more
Caused by: java.lang.ClassCastException: android.widget.Button cannot be cast to android.widget.ToggleButton
at com.example.wd.flashlight.MainActivity.onCreate(MainActivity.java:57)
组件问题,在第二步布局页面的时候,其实我只添加了一个button组件,没有添加toggleButton组件,然后在这里报出错误之后,才按照第二步的操作添加了一个toggleButton组件,所以:
5、点击开关按键打不开闪光灯
上面问题解决之后,程序可以编译成功,安装在手机之后也可以进入apk了,但是点击按钮想要打开闪光灯的时候又失败了,点击按钮无反应。。。
回到代码查看:
ToggleButton toggle_btn = (ToggleButton)findViewById(R.id.toggleButton);
toggle_btn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
//@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
try{
manager.setTorchMode("1",isChecked);
}catch (CameraAccessException e){
e.printStackTrace();
}
}
});
将
manager.setTorchMode("1",isChecked);
改为:
manager.setTorchMode("0",isChecked);
八、成功
重新编译安装,打开手电筒app,点击按钮,这个时候发现我们可以正常的打开关闭闪光灯了
九、后记
虽然apk可以正常使用了,但是这里依然留下了一个问题,本来最开始在页面布局的时候,只打算添加一个button控制开关就可以了,但是在后来的调试过程中根据代码又添加了一个toggleButton控件,最后的结果就是上面那个按钮是没有用的,只有下面那个按钮可以控制开关,就造成了界面按键的多余,这个问题是根据代码编写来看的,之后还需要再研究一下代码。。。
十、各个文件源码
activity_main.xml
build.gradle(Module:app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
defaultConfig {
applicationId "com.example.wd.flashlight"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:25.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
MainActivity.java
package com.example.wd.flashlight;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ToggleButton;
//public class MainActivity extends AppCompatActivity {
public class MainActivity extends Activity {
private CameraManager manager;
private Camera camera = null;
private static boolean kaiguan = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//super.onCreate(savedInstanceState);
manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
try{
String [] cameraList = manager.getCameraIdList();
for (String str:cameraList
) {
Log.d("List", str);
}
}catch (CameraAccessException e){
Log.e("error",e.getMessage());
}
Button open_btn = (Button)findViewById(R.id.button);
open_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try{
manager.setTorchMode("0",true);
}catch(CameraAccessException e){
e.printStackTrace();
}
}
});
Button close_btn = (Button) findViewById(R.id.button);
close_btn.setOnClickListener(closeOnClickListener);
ToggleButton toggle_btn = (ToggleButton)findViewById(R.id.toggleButton);
toggle_btn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
//@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
try{
manager.setTorchMode("0",isChecked);
}catch (CameraAccessException e){
e.printStackTrace();
}
}
});
}
private View.OnClickListener closeOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
try{
manager.setTorchMode("0",false);
}catch (CameraAccessException e){
e.printStackTrace();
}
}
};
}
AndroidManifest.xml