4.0debug调试
1、debug调试的作用
1)跟踪程序的代理,找出问题出现的地方,更快的解决问题
2)梳理已有功能代码的运行逻辑流程
2、如何进行debug调试
1). 开启Debug的一般步骤:
a. 设置断点 : 在某个方法体的特定行打断点
b. Debug运行
c. 进入Debug视图模式, 运行至断点处悬停
2).Debug视图的组成
1 : 常用debug操作工具栏
2 : 线程堆栈视图
3 : 变量视图、断点视图
4 : 代码视图
3). debug常用操作工具栏
1 :代表执行完当前断点区域进入下一个断点或结束
2 : 中断程序
3 : 进入当前行的方法(单步跳入)
4 : 执行完当前行, 进入下一行(单步跳过)
5 : 跳出当前方法执行(单步跳出)
4.1理论概述
1、Android数据存储方式
2.测试用例
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="数据存储方式"
android:textSize="20sp"
android:textColor="#ff0000"
android:layout_margin="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickSP"
android:text="SharedPreference存储" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickIF"
android:text="内部文件存储" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickOF"
android:text="外部文件存储" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickDB"
android:text="数据库存储" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickNW"
android:text="网络存储存储" />
</LinearLayout>
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 测试sp存储
public void onClickSP(View v) {
startActivity(new Intent(this, SpActivity.class));
}
// 测试手机内部文件存储
public void onClickIF(View v) {
startActivity(new Intent(this, IFActivity.class));
}
// 测试手机外部文件存储
public void onClickOF(View v) {
startActivity(new Intent(this, OFActivity.class));
}
// 测试Sqlite数据库存储
public void onClickDB(View v) {
startActivity(new Intent(this, DBActivity.class));
}
public void onClickNW(View v) {
startActivity(new Intent(this, NetworkActivity.class));
}
}
2、测试用例
4.2sp存储说明
SP存储专门用来存储一些单一的小数据
存储数据的类型: boolean, float, int, long,String
数据保存的路径: /data/data/packageName/shared_prefs/yyy.xml
可以设置数据只能是当前应用读取, 而别的应用不可以
应用卸载时会删除此数据
1) SharedPreferences: 对应sp文件的接口
a) context. getSharedPreferences (String name, int mode): 得到SP对象
i. name: 文件名(不带.xml)
ii. mode: 生成的文件模式(是否是私有的,即其它应用是否可以访问)
b) Editor sp.edit() : 得到Editor对象
c) Xxx sp.getXxx(name,defaultValue): 根据name得到对应的数据
2) Editor : 能更新sp文件的接口
a) Editor put(name, value) : 保存一个键值对, 没有真正保存到文件中
b) Editor remove(name)
c) commit(): 提交, 数据真正保存到文件中了
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/et_sp_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="存储的key" />
<EditText
android:id="@+id/et_sp_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="存储的value" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="save"
android:text="保 存" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="read"
android:text="读 取" />
</LinearLayout>
</LinearLayout>
4.3sp存储_保存数据
1、分析思路
1. 得到sp对象
2. 得到editor对象
3. 得到输入的key/value
4. 使用editor保存key-value
5. 提示
2、源码
package com.xiongpan.l04_datastorage;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
/**
* 测试sp存储的界面
*/
public class SpActivity extends Activity {
private EditText et_sp_key;
private EditText et_sp_value;
private SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sp);
et_sp_key = (EditText) findViewById(R.id.et_sp_key);
et_sp_value = (EditText) findViewById(R.id.et_sp_value);
//1. 得到sp对象
sp = getSharedPreferences("xiongpan", Context.MODE_PRIVATE);
}
public void save(View v) {
//2. 得到editor对象
Editor edit = sp.edit();
//3. 得到输入的key/value
String key = et_sp_key.getText().toString();
String value = et_sp_value.getText().toString();
//4. 使用editor保存key-value
edit.putString(key, value).commit();
//5. 提示
Toast.makeText(this, "保存完成!", 0).show();
}
4.4sp存储_读取数据
##测试sp存储_读取
1. 得到输入的key
2. 根据key读取对应的value
3. 显示
public void read(View v) {
//1. 得到输入的key
String key = et_sp_key.getText().toString();
//2. 根据key读取对应的value
String value = sp.getString(key, null);
//3. 显示
if(value==null) {
Toast.makeText(this, "没有找到对应的value", 0).show();
} else {
et_sp_value.setText(value);
}
}
}
4.5手机内部文件存储_说明
1、说明
应用运行需要的一些较大的数据或图片可以用文件保存的手机内部
文件类型: 任意
数据保存的路径: /data/data/projectPackage/files/
可以设置数据只能是当前应用读取, 而别的应用不可以
应用卸载时会删除此数据
4.6手机内部文件存储_保存文件
1、思路分析
测试手机内部文件存储_保存
1. 得到InputStream-->读取assets下的logo.png
2. 得到OutputStream-->/data/data/packageName/files/logo.png
3. 边读边写
4. 提示
2、布局源码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="1. 将asserts下的logo.png保存到手机内部\n2. 读取手机内部图片文件显示"
android:textColor="#ff0000"
android:textSize="15sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/btn_if_save"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="save"
android:text="保 存" />
<Button
android:id="@+id/btn_if_read"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="read"
android:text="读 取" />
</LinearLayout>
<ImageView
android:id="@+id/iv_if"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
</LinearLayout>
package com.xiongpan.l04_datastorage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
/**
* 测试手机内部文件存储
*
* @author 张晓飞
*
*/
public class IFActivity extends Activity {
private ImageView iv_if;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_if);
iv_if = (ImageView) findViewById(R.id.iv_if);
}
public void save(View v) throws IOException {
//1. 得到InputStream-->读取assets下的logo.png
//得到AssetManager
AssetManager manager = getAssets();
//读取文件
InputStream is = manager.open("logo.png");
//2. 得到OutputStream-->/data/data/packageName/files/logo.png
FileOutputStream fos = openFileOutput("logo.png", Context.MODE_PRIVATE);
//3. 边读边写
byte[] buffer = new byte[1024];
int len = -1;
while((len=is.read(buffer))!=-1) {
fos.write(buffer, 0, len);
}
fos.close();
is.close();
//4. 提示
Toast.makeText(this, "保存完成", 0).show();
}
4.7手机内部文件存储_读取文件
1、思路分析
##测试手机内部文件存储_读取
1. 得到图片文件的路径
2. 读取加载图片文件得到bitmap对象
3. 将其设置到imageView中显示
2、相关API
读取文件
FileInputStream fis = openFileInput("logo.png");
保存文件
FileOutputStream fos = openFileOutput("logo.png",MODE_PRIVATE)
得到files文件夹对象
File filesDir = getFilesDir();
操作asserts下的文件
得到AssetManager : context.getAssets();
读取文件: InputStream open(filename);
加载图片文件
Bitmap BitmapFactory.decodeFile(StringpathName) // .bmp/.png/.jpg
public void read(View v) {// /data/data/packageName/files/logo.png
//1. 得到图片文件的路径
// /data/data/packageName/files
String filesPath = getFilesDir().getAbsolutePath();
String imagePath = filesPath+"/logo.png";
//2. 读取加载图片文件得到bitmap对象
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
//3. 将其设置到imageView中显示
iv_if.setImageBitmap(bitmap);
}
}
4.8_手机外部文件存储_说明
1、说明
• 应用运行用到的数据文件(如图片)可以保存到sd卡中
• 文件类型: 任意
• 数据保存的路径:
– 路径1: /storage/sdcard/Android/data/packageName/files/
– 路径2: /storage/sdcard/xxx/
• 路径1 :其它应用可以访问,应用卸载时删除
• 路径2 : 其它应用可以访问, 应用卸载时不会删除
• 必须保证sd卡挂载在手机上才能读写, 否则不能操作
2、相关API
• Environment : 操作SD卡的工具类
– 得到SD卡的状态:Environment.getExternalStorageState()
– 得到SD卡的路径:Environment.getExternalStorageDirectory()
– SD卡可读写的挂载状态值:Environment.MEDIA_MOUNTED
– context. getExternalFilesDir():
– 得到/mnt/sdcard/Android/data/pageckage_name/files/xxx.txt
– 操作SD卡的权限:
– android.permission.WRITE_EXTERNAL_STORAGE
• /mnt/sdcard/Android/data/pageckage_name/files/
• /mnt/sdcard/Android/data/pageckage_name/files/music/
• /mnt/sdcard/Android/data/pageckage_name/files/images/
4.9_手机外部文件存储_保存文件
1、思路分析
1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
2. 读取输入的文件名/内容
3. 得到指定文件的OutputStream
1).得到sd卡下的files路径
2).组成完整路径
3). 创建FileOutputStream
4. 写数据
5. 提示
2、布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/et_of_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="存储的文件名" />
<EditText
android:id="@+id/et_of_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="存储的文件内容" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="save"
android:text="保 存" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="read"
android:text="读 取" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="save2"
android:text="保 存2" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="read2"
android:text="读 取2" />
</LinearLayout>
</LinearLayout>
3、操作SD卡需要注意的问题
<!--操作sd卡 -->
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
4、源码
package com.xiongpan.l04_datastorage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
/**
* 测试手机外部文件存储
*
* @author 张晓飞
*
*/
public class OFActivity extends Activity {
private EditText et_of_name;
private EditText et_of_content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_of);
et_of_name = (EditText) findViewById(R.id.et_of_name);
et_of_content = (EditText) findViewById(R.id.et_of_content);
}
public void save(View v) throws IOException {
//1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//2. 读取输入的文件名/内容
String fileName = et_of_name.getText().toString();
String content = et_of_content.getText().toString();
//3. 得到指定文件的OutputStream
//1).得到sd卡下的files路径
String filesPath = getExternalFilesDir(null).getAbsolutePath();
//2).组成完整路径
String filePath = filesPath+"/"+fileName;
//3). 创建FileOutputStream
FileOutputStream fos = new FileOutputStream(filePath);
//4. 写数据
fos.write(content.getBytes("utf-8"));
fos.close();
//5. 提示
Toast.makeText(this, "保存完成", 0).show();
} else {
Toast.makeText(this, "sd卡没有挂载", 0).show();
}
}
4.10手机外部文件是存储_读取文件
public void read(View v) throws Exception {
// 1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// 2. 读取输入的文件名
String fileName = et_of_name.getText().toString();
// 3. 得到指定文件的InputStream
// 1).得到sd卡下的files路径
String filesPath = getExternalFilesDir(null).getAbsolutePath();
// 2).组成完整路径
String filePath = filesPath + "/" + fileName;
// 3). 创建FileInputStream
FileInputStream fis = new FileInputStream(filePath);
// 4. 读取数据, 成String
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while((len=fis.read(buffer))!=-1) {
baos.write(buffer, 0, len);
}
String content = baos.toString();
// 5. 显示
et_of_content.setText(content);
} else {
Toast.makeText(this, "sd卡没有挂载", 0).show();
}
}
4.11手机外部文件存储_保存读取
// /storage/sdcard/xiongpan/xxx.txt
public void save2(View v) throws IOException {
//1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//2. 读取输入的文件名/内容
String fileName = et_of_name.getText().toString();
String content = et_of_content.getText().toString();
//3. 得到指定文件的OutputStream
//1). /storage/sdcard/
String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
//2). /storage/sdcard/xiongpan/(创建文件夹)
File file = new File(sdPath+"/xiongpan");
if(!file.exists()) {
file.mkdirs();//创建文件夹
}
//3). /storage/sdcard/xiongpan/xxx.txt
String filePath = sdPath+"/xiongpan/"+fileName;
//4). 创建输出流
FileOutputStream fos = new FileOutputStream(filePath);
//4. 写数据
fos.write(content.getBytes("utf-8"));
fos.close();
//5. 提示
Toast.makeText(this, "保存完成", 0).show();
} else {
Toast.makeText(this, "sd卡没有挂载", 0).show();
}
}
public void read2(View v) throws Exception {
// 1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// 2. 读取输入的文件名
String fileName = et_of_name.getText().toString();
// 3. 得到指定文件的InputStream
String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
String filePath = sdPath+"/xiongpan/"+fileName;
FileInputStream fis = new FileInputStream(filePath);
// 4. 读取数据, 成String
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while((len=fis.read(buffer))!=-1) {
baos.write(buffer, 0, len);
}
String content = baos.toString();
fis.close();
// 5. 显示
et_of_content.setText(content);
} else {
Toast.makeText(this, "sd卡没有挂载", 0).show();
}
}
}
4.12_应用练习1_界面布局与流程分析
修改防盗的名称
• 功能描述:
1. 长按手机防盗, 显示修改的Dialog
2. 通过dialog修改手机防盗名称
• 关键技术点:
1. SharedPreferences的使用
2. AlertDialog的使用
3.GridView+BaseAdapter的使用
1. 给gridView的item添加长按监听(只能第一个有响应)
2. 在回调方法中显示AlertDialog
3. 处理点击修改
1). 界面更新
2). 将名称保存到sp中
4. 如何保证退出后再进入显示修改过的名称
4.13_应用练习1_修改防盗名称
1、布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="80dp"
android:layout_height="80dp"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/iv_item_icon"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/tv_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="名称"
android:textSize="16sp"/>
</LinearLayout>
2、源码
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
public class MainActivity extends Activity implements OnItemLongClickListener {
private GridView gv_main;
private MainAdapter adapter;
String[] names = new String[] { "手机防盗", "通讯卫士", "软件管理", "流量管理", "进程管理",
"手机杀毒", "缓存清理", "高级工具", "设置中心" };
int[] icons = new int[] { R.drawable.widget01, R.drawable.widget02,
R.drawable.widget03, R.drawable.widget04, R.drawable.widget05,
R.drawable.widget06, R.drawable.widget07, R.drawable.widget08,
R.drawable.widget09 };
private SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gv_main = (GridView) findViewById(R.id.gv_main);
adapter = new MainAdapter(this, names, icons);
gv_main.setAdapter(adapter);
//给gridView的Item设置点击监听
gv_main.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//得到当前点击的名称
String name = names[position];
//提示
Toast.makeText(MainActivity.this, name, 1).show();
}
});
//给gridView的item添加长按监听(只能第一个有响应)
gv_main.setOnItemLongClickListener(this);
sp = getSharedPreferences("xfzhang", Context.MODE_PRIVATE);
}
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
if(position==0) {
//得到当前显示的名称
final TextView textView = (TextView) view.findViewById(R.id.tv_item_name);
String name = textView.getText().toString();
//为dialog准备输入框对象
final EditText editText = new EditText(this);
editText.setHint(name);
//显示AlertDialog
new AlertDialog.Builder(this)
.setTitle("修改名称")
.setView(editText)
.setPositiveButton("修改", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String newName = editText.getText().toString();
//1). 界面更新
textView.setText(newName);
//2). 将名称保存到sp中
sp.edit().putString("NAME", newName).commit();
}
})
.setNegativeButton("取消", null)
.show();
}
return true;
}
}
package com.xiongpan.app04_gridview;
import android.content.Context;
import android.content.SharedPreferences;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MainAdapter extends BaseAdapter {
private String[] names;
private int[] icons;
private Context context;
private SharedPreferences sp;
public MainAdapter(Context context, String[] names, int[] icons) {
super();
this.context = context;
this.names = names;
this.icons = icons;
sp = context.getSharedPreferences("xfzhang", Context.MODE_PRIVATE);
}
@Override
public int getCount() {
return names.length;
}
@Override
public Object getItem(int position) {
return names[position];
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null) {
convertView = View.inflate(context, R.layout.item_main, null);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_item_icon);
TextView textView = (TextView) convertView.findViewById(R.id.tv_item_name);
imageView.setImageResource(icons[position]);
textView.setText(names[position]);
if(position==0) {
//从sp中读取保存的名称, 如果存在显示
String savedName = sp.getString("NAME", null);
if(savedName!=null) {
textView.setText(savedName);
}
}
return convertView;
}
}