Android实验
实验一 音乐播放器
一、实验目的
1、掌握Activity工作机制。
2、掌握ListView、MediaPlayer等用法。
二、实验内容
设计一个音乐播放器,用ListView显示手机中MP3格式音乐,支持播放、暂停、继续、上一首、下一首等功能。
四、程序源代码
1、布局页面
在res的layout的activity_music.xml中
<?xml version="1.0" encoding="utf-8"?><LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.lenovo.myapplication.MusicActivity">
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_below="@+id/btn_test"
android:layout_marginTop="20dp">
</ListView>
<SeekBar
android:id="@+id/seekBar"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@android:color/background_light"
android:backgroundTint="@android:color/background_light"
android:progressBackgroundTint="@color/bg" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageButton
android:id="@+id/previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:background="@android:color/background_light"
android:src="@drawable/rewind" />
<ImageButton
android:id="@+id/btn_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_marginLeft="100dp"
android:layout_marginRight="100dp" android:layout_weight="1" android:background="@android:color/background_light" android:src="@drawable/pause11" /> <ImageButton android:id="@+id/next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:background="@android:color/background_light" android:src="@drawable/forward" /> </LinearLayout> </LinearLayout>
2、MusicActivity代码
A、添加SD卡访问权限
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE">
</uses-permission>
权限请求和兼容性
if (ActivityCompat.checkSelfPermission(MusicActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MusicActivity.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 123);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
B、获取mp3音乐文件路径代码
final ArrayList<String> list = new ArrayList<String>(); //音乐列表File sdpath = Environment.getExternalStorageDirectory();//获得手机SD卡路径
File path = new File(sdpath + "//mp3//"); //获得SD卡的mp3文件夹
//返回以.mp3结尾的文件 (自定义文件过滤)
File[] songFiles = path.listFiles(new MyFilter(".mp3"));
for (File file : songFiles) {
list.add(file.getAbsolutePath());//获取文件的绝对路径
}
其中MyFilter:自定义的文件过滤器类
MyFilter代码:
package com.example.lenovo.myapplication;
import java.io.File;
import java.io.FilenameFilter;
/**
* Created by lenovo on 2018/4/12.
*/
public class MyFilter implements FilenameFilter {
private String type;
public MyFilter(String type) {//构造函数
this.type = type;
}
@Override //实现FilenameFilter接口accept()方法
public boolean accept(File dir, String name) {
//dir当前目录, name文件名
return name.endsWith(type);
//返回true的文件则合格
}
}
C、ListView适配器数据填充
ArrayAdapter<String> adapter =new ArrayAdapter<String>(
MusicActivity.this,
android.R.layout.simple_list_item_single_choice,
list );
ListViewli=(ListView)findViewById(R.id.listView);
li.setAdapter(adapter);
li.setChoiceMode(ListView.CHOICE_MODE_SINGLE); //单选
D、音乐播放
MediaPlayer mp=new MediaPlayer();
String song_path = "";
int id;
private int currentposition;//当前音乐播放的位置
private boolean isChanging=false;//歌曲改变
private SeekBar seekBar;//进度条
private Timer timer;
private TimerTask timerTask;//定时器
ListView li;//ListView选取元素
//音乐播放
li.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
currentposition=position;
TextView music_url=(TextView)view.findViewById(R.id.music_url);
try{
mp.reset(); //重置
mp.setDataSource( music_url.getText().toString());
mp.prepare(); //准备
mp.start(); //播放
}catch (Exception e){ }
}
});
E、音乐停止播放
//音乐停止播放
@Override
protected void onDestroy() {
super.onDestroy();
if(mp!=null ){
mp.stop();
mp.release();
}
Toast.makeText(getApplicationContext(), "退出啦", Toast.LENGTH_SHORT).show();
}
F、音乐的暂停和播放以及进度条的实现
seekBar=(SeekBar)findViewById(R.id.seekBar);
seekBar.setOnSeekBarChangeListener(new Myseekbar());//拖动的事件监
听
final ImageButton btnpause=(ImageButton)findViewById(R.id.btn_pause);
btnpause.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if( song_path.isEmpty() )
Toast.makeText(getApplicationContext(), "先选收歌曲先听听", Toast.LENGTH_SHORT).show();
if( mp.isPlaying() ){
mp.pause();
btnpause.setImageResource(R.drawable.play11);
}else if( !song_path.isEmpty() ){
mp.start();
btnpause.setImageResource(R.drawable.pause11);
seekBar.setMax(mp.getDuration());//设置seekbar最大值为音乐文件持续时间
//Time线程实现和执行一个任务,实现TimeTask的子类,
timer=new Timer();
timerTask=new TimerTask() {
@Override
public void run() {
if(isChanging)
{
return;
}
seekBar.setProgress(mp.getCurrentPosition());//更新进度条
}
};
timer.schedule(timerTask,0,10);
//从0毫秒以后,每隔10毫秒执行一次。
}
} });
public void onProgressChanged(SeekBarseekbar,int progress,boolean formUser){}
@Override
public void onStartTrackingTouch(SeekBarseekBar) {
isChanging=true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { mp.seekTo(seekBar.getProgress());//seekbar确认位置后调到指定位置 isChanging=false; } }
G、实现上一首、下一首
ImageButtonprevious=(ImageButton)findViewById(R.id.previous);
previous.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
if(currentposition==li.getCount()-1)
{
currentposition=-1;
}
if( song_path.isEmpty() )
Toast.makeText(getApplicationContext(),"先选收歌曲先听听", Toast.LENGTH_SHORT).show();
else{
int id = list.indexOf(song_path);
if(id==list.size()-1)
id=id-1;
else
id=id-1;
li.setItemChecked(id,true);
song_path=list.get(id);
try{
mp.reset(); //重置
mp.setDataSource(song_path);
mp.prepare(); //准备
mp.start(); //播放
}catch (Exception e){ }
}
} });
ImageButton next=(ImageButton)findViewById(R.id.next);
next.setOnClickListener(new View.OnClickListener() {//实现下一首
@Override
public void onClick(View v) {
if(currentposition==li.getCount()+1)
{
currentposition=-1;
}
if( song_path.isEmpty() )
Toast.makeText(getApplicationContext(), "先选收歌曲先听听", Toast.LENGTH_SHORT).show();
else{
id = list.indexOf(song_path);
if(id==list.size()-1)
id=0;
else
id=id+1;
li.setItemChecked(id,true);
song_path=list.get(id);
try{
mp.reset(); //重置
mp.setDataSource(song_path);
mp.prepare(); //准备
mp.start(); //播放
}catch (Exception e){ }
}
} });
}
五、运行截图
六、实验小结
此次试验,懂得了
1、adapter:是数据和视图之间的桥梁,数据在adapter中做处理,然后显示到视图上面。ListView适配器数据的填充。
2、必须添加SD卡访问权限
<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE" />
才可以访问SD卡;
3、想要启动xxactivity时在该AndroidManifest.xml中
<intent-filter>
<actionandroid:name="android.intent.action.MAIN" />
<categoryandroid:name="android.intent.category.LAUNCHER" />
</intent-filter>
4、要注意细节,比如界面的美观,不能单纯的完成实验而不顾美观,这一点需要改进。
5、最主要的还是音乐播放器功能的实现模块,上一首、下一首、播放、暂停、音乐进度条。
其中关乎进度条的这一块使用到了线程这一知识点。Time线程实现和执行一个任务,实现TimeTask的子类,当进度条发生改变时利用到的回调函数。
实验二 广播+服务编程
一、实验目的
1、掌握Broadcast Receiver编程基本方法。
2、掌握本地Service编程基本用法。
二、实验内容
设计一个电话监听录音APP,完成如下主要功能:
(1)用广播机制监听电话(只要求监听去电电话),启动服务完成录音功能,当结束通话时使用手工方式结束录音。
四、程序源代码
新建module testbroadcast
1、在AndroidManifest.xml中添加权限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permissionandroid:name="android.permission.RECORD_AUDIO" />
<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2、BootReceiver.java
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
// throw new UnsupportedOperationException("Not yet implemented");
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
String phoneNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Toast.makeText(context, "监听到拨打电话:" + phoneNum, Toast.LENGTH_LONG).show();
}
Intent intent1=new Intent(context,RecorderService.class);
if (intent.getAction().equals("BC_")){
Toast.makeText(context,"结束录音",Toast.LENGTH_LONG).show();
context.stopService(intent1);
}
else {
Toast.makeText(context,"开始录音",Toast.LENGTH_LONG).show();
context.startService(intent1);
}
}
}
3、MainActivity
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (ActivityCompat.checkSelfPermission( MainActivity.this, Manifest.permission.PROCESS_OUTGOING_CALLS) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions( MainActivity.this, new String[] { Manifest.permission.PROCESS_OUTGOING_CALLS }, 123); return; } final Intent intent=new Intent(MainActivity.this,RecorderService.class); Button bt1=(Button)findViewById(R.id.button1); bt1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(intent); } }); } }
4、RecorderService
private MediaRecorder recorder; //录音的一个实例
//创建保存录音的目录
private void createRecorderFile(){
String absolutePath =Environment.getExternalStorageDirectory().getAbsolutePath();
String filePath=absolutePath+"/recorder";
File file=new File(filePath);
if (!file.exists()){
file.mkdir();//创建文件夹
}
}
private StringgetCurrentTime(){//获取当前时间,以其为名来保存录音
SimpleDateFormatformat=new SimpleDateFormat("yyyyMMddHHmmss");//创建日期化格式化对象
Date date=new Date();//创建时间
return str;
}
public RecorderService() {
}
@Override
public IBinder onBind(Intentintent) {
// TODO: Return thecommunication channel to the service.
//throw newUnsupportedOperationException("Not yet implemented");
return null;
}
@Override
public void onCreate() {
super.onCreate();
if(recorder==null) {//获得电话管理器
recorder = new MediaRecorder();//初始化录音对象
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置录音的输入源(麦克)
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//设置音频格式(3gp)
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//设置音频编码
createRecorderFile();//创建保存录音的文件夹
recorder.setOutputFile("sdcard/recorder"+ "/" + getCurrentTime() + ".3gp"); //设置录音保存的文件
try {
recorder.prepare();//准备录音
recorder.start();//开始录音
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public int onStartCommand(Intentintent, int flags, int startId) {
return super.onStartCommand(intent,flags, startId);
} @Override public void onDestroy() { super.onDestroy(); if(recorder!=null){ recorder.stop();//停止播放 recorder.release();//回收 } } } 5、app的MainActivity
String recorder_path="";
MediaPlayer mp=new MediaPlayer();//定义类成员
ArrayList<String>recorderList=new ArrayList<String>();//录音列表
class MyFilter implements FilenameFilter {
private String type;
public MyFilter(Stringtype){//构造函数
this.type=type;
}
@Override//实现FilenameFilter接口accept方法
public boolean accept(File dir,String name){//dir当前目录,name文件名
return name.endsWith(type);//返回true的文件则合格
}
}
private void getFileFromRecord() {
recorderList = new ArrayList<String>();
File sdpath = Environment.getExternalStorageDirectory();//获得手机SD卡路径
final File path = new File(sdpath + "//recorder//");//获得SD卡的recorder文件夹,返回以.3gp结尾的文件夹(自定义文件过滤)
File[] songFiles =path.listFiles(new MyFilter(".3gp"));//返回以.3gp结尾的文件(自定义文件过滤)
for (File file :songFiles) {
//recorderList.add(file.getAbsolutePath().substring(29));
recorderList.add(file.getAbsolutePath());//获取文件的绝对路径
}
//ListView适配器数据填充
ArrayAdapter<String>adapter = new ArrayAdapter<String>(
MainActivity.this,
android.R.layout.simple_list_item_single_choice,
recorderList);
ListViewli=(ListView)findViewById(R.id.lv);
li.setAdapter(adapter);
li.setChoiceMode(ListView.CHOICE_MODE_SINGLE);//单选
//录音播放
li.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?>parent, View view, int position, long id) {
recorder_path=((TextView)view).getText().toString();
try{
mp.reset();//播放器重置
mp.setDataSource(recorder_path);
mp.prepare();//准备播放
}catch(Exception e){
e.printStackTrace();
}
mp.start();//播放
}
});
}
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFileFromRecord();//获取当前文件路径
Buttonbt=(Button)findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
getFileFromRecord();
}
});
}
//录音停止播放 按返回键结束Activity时触发OnDestroy()
@Override
protected void onDestroy() {
super.onDestroy();
if(mp!=null){
mp.stop();
mp.release();
}
Toast.makeText(getApplicationContext(), "退出啦", Toast.LENGTH_SHORT).show();
}
}
五、运行截图
六、实验小结
1、本次实验涉及到多种权限设置,要注意很多地方,调试多次。
2、界面有待美化,需要改进。
3、录音使用MediaRecorder类编程,录音文件用当前系统时间命名。
这一块功能的实现在网上百度了很多例子, 创建保存录音的目录,获取当前时间,以其为名来保存录音、创建日期化格式化对象、创建时间、格式化时间并返回。获取电话管理器,设置音频文件、创建保存录音的文件夹以及设置录音保存的文件。学到了很多。
4、此次完成的电话录音功能两个App界面,一个界面结束录音,另外一个界面显示已有录音列表,界面有待优化,放在一个App界面应该更好。
实验三 数据存储与访问
一、实验目的
1、掌握SQLite数据库编程基本方法。
2、掌握SimpleCursorAdapter和上下文菜单基本用法。
二、实验内容
三、工作流程图
四、程序源代码
1. ListView显示数据库数据(ShowActivity)
(1)ListView自定义layout布局
新建一个名为listview.xml布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<TextView
android:id="@+id/txtID"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:text="id"
android:textSize="20dp"
android:gravity="center"/>
<TextView
android:id="@+id/txtName"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:text=" name" android:textSize="20dp"
android:gravity="center"/>
<TextView
android:id="@+id/txtAge"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=" age"
android:textSize="20dp"
android:gravity="center"/>
</LinearLayout>
(2)使用SimpleCursorAdapter填充ListView
SimpleCursorAdapter基本方法:
String[ ] from = {"_id", "name", "age" };
int[ ] to = { R.id.txtID,R.id.txtName, R.id.txtAge };
SimpleCursorAdapteradapter =
newSimpleCursorAdapter(this, R.layout.listview, cursor, from, to);
ShowAcitvity的OnCreate()主要代码:
DBHelper helper = newDBHelper(getApplicationContext(), "test.db", null,1); SQLiteDatabasedb=helper.getWritableDatabase(); Cursor cursor = db.rawQuery( "SELECT idas _id, name,age FROM person",null);
String[] from = {"_id", "name", "age" }; int[] to = { R.id.txtID,R.id.txtName, R.id.txtAge }; SimpleCursorAdapter adapter = newSimpleCursorAdapter( this, R.layout.listview, cursor, from, to);
//cursor.close();
ListViewli=(ListView)findViewById(R.id.listView1); li.setAdapter(adapter); TextViewtv=(TextView)findViewById(R.id.textView1); tv.setText("查询到"+cursor.getCount()+"条记录");
2、
DBHelper
public class DBHelper extends SQLiteOpenHelper { private static int DB_VERSION=1; public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS person (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "name VARCHAR(20)," + "age SMALLINT)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS person"); onCreate(db); } }
Person
public class Person {
public int id;
public String name;
public int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
3、添加记录(InsertActivity)
ShowActivity ”添加”按钮
Button bt1= (Button)findViewById(R.id.button1); // 注意 id 值
bt1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent=new Intent(ShowActivity.this,InsertActivity.class);
startActivityForResult(intent, 100);
}
});
InsertActivity “保存”按钮
Button bt1 = (Button) findViewById(R.id.newRec); bt1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { EditText et1 = (EditText) findViewById(R.id.editText1); EditText et2 = (EditText) findViewById(R.id.editText2); Person person = new Person(et1.getText().toString(), Integer.parseInt(et2.getText().toString())); insert(person); setResult(RESULT_OK, null); finish(); } });
InsertActivity “取消”按钮
Button bt2= (Button)findViewById(R.id.button2);
bt2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
finish();
}
});
其中insert()方法
public void insert(Person person){
DBHelper helper = new DBHelper(getApplicationContext(), "test.db", null,1);
SQLiteDatabase db=helper.getWritableDatabase(); String sql="INSERT INTO person VALUES (NULL, ?, ?)";
db.execSQL(sql, new Object[ ] { person.name, person.age } );
db.close();
Toast.makeText(getApplicationContext(), " 记录添加成功 ", Toast.LENGTH_SHORT).show();
}
ShowActivity接收回传信息
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==100)
if(resultCode==RESULT_OK){
onCreate(null);
}
}
4、ListView添加ContextMenu(ShowActivity)
第1步:新建菜单资源
(1)在res下新建menu目录
(2)在menu目录下新建一个manage.xml文件,代码:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/delete" android:title="删除"></item>
<item android:id="@+id/update" android:title="修改"></item>
</menu>
第2步:创建上下文菜单
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { menu.setHeaderTitle("操作"); getMenuInflater().inflate(R.menu.manage, menu); }
第3步:添加上下文菜单选中项方法
@Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.delete: delete(item); return true; case R.id.update: update(item); return true; default: return false; } }
第4步:将上下文菜单注册到ListView上
ListView li=(ListView)findViewById(R.id.listView1);
registerForContextMenu( li );
5、ShowActivity删除和修改方法
public void delete(MenuItem item){ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); if(info.id>0){ new AlertDialog.Builder(this).setTitle("删除" + info.id) .setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { DBHelper helper = new DBHelper(getApplicationContext(), "test.db", null,1); SQLiteDatabase db=helper.getWritableDatabase(); db.execSQL( "Delete from person where id=?", new Object[ ]{ info.id } ); db.close(); Toast.makeText(getApplicationContext(), " 记录删除成功 ", Toast.LENGTH_SHORT).show(); onCreate(null); //重新加载一次Activity,刷新 } }) .setNegativeButton("取消", null) .show(); } } public void update(MenuItem item){ final AdapterView.AdapterContextMenuInfo info= (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); Intent intent =new Intent(ShowActivity.this, UpdateActivity.class); Bundle bundle=new Bundle(); bundle.putString("id", String.valueOf(info.id)); bundle.putString("username",((TextView)info.targetView.findViewById(R.id.txtName)).getText().toString()); bundle.putString("age",((TextView)info.targetView.findViewById(R.id.txtAge)).getText().toString()); intent.putExtras(bundle); startActivityForResult(intent, 200); }
6、UpdateActivity方法
public class UpdateActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_update); Intent intent=getIntent(); Bundle bundle=intent.getExtras(); String id=bundle.getString("id"); String name=bundle.getString("username"); String age=bundle.getString("age"); final EditText et1=(EditText)findViewById(R.id.editText1); final EditText et2=(EditText)findViewById(R.id.editText2); final EditText et3=(EditText)findViewById(R.id.editText3); et1.setText(id); et2.setText(name); et3.setText(age); Button bt1= (Button)findViewById(R.id.newRec); bt1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { DBHelper helper = new DBHelper(getApplicationContext(), "test.db", null,1); SQLiteDatabase db=helper.getWritableDatabase(); //更新数据,id值不能修改 db.execSQL("Update person set name=? , age=? where id=?", new Object[ ]{ et2.getText().toString(),et3.getText().toString(),et1.getText().toString() } ); db.close(); Toast.makeText(getApplicationContext(), " 记录修改成功 ", Toast.LENGTH_SHORT).show(); setResult(RESULT_OK, null); finish(); //不能少 } }); Button bt2= (Button)findViewById(R.id.button2); bt2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { finish(); } }); } }
五、运行截图
主界面
添加数据页面
六、实验小结
1、利用数据库增删改查是非常方便的,在以后的学习中必然还会用到相关的知识,因此这一章节的内容一定要掌握牢固,记住一些重要的SQL语句。
2、设计APP的时候考虑输入的合理性,在输入年龄的时候应该限定输入的字符只可以是数字,id值是不可以被改变的。
3、如何将数据库和界面联系起来也是这个APP制作成功的关键,上课的时候这个程序的代码我基本都是复制粘贴的,只是感觉到SQLite很强大,下课后仔细敲了一遍才领会到代码的工作原理,不过还没有达到灵活运用的地步,但是我觉得这一节的知识用处很大,在我自己设计APP的时候很可能会用到。
实验四 网络爬虫程序
一、实验目的
1、掌握HttpURLConnection编程基本方法。
2、掌握jsoup HTML解析器基本用法。
二、实验内容
制作一个简易的Android新闻客户端。
三、工作流程图
四、程序源代码
1、在AndroidManifest.xml添加权限
<uses-permission android:name="android.permission.INTERNET" />
2、res下的layout布局
List_item.xml自定义布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="60dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="80dp" android:orientation="vertical"> <TextView android:id="@+id/tv_url" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="TextView" android:visibility="gone" /> <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="20dp" android:textColor="@android:color/background_dark" android:textSize="15dp" android:textStyle="bold" /> <TextView android:id="@+id/tv_comment" android:layout_width="match_parent" android:layout_height="60dp" android:scrollbars="vertical" android:singleLine="false" android:textColor="@android:color/background_dark" android:textSize="12dp" /> </LinearLayout> </LinearLayout> </LinearLayout>
Activity_http_client.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.httpurlconnection.HttpClientActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
activity_detail.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.httpurlconnection.DetailActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:scrollbars="vertical" android:singleLine="false" /> </LinearLayout> </LinearLayout>
3、HttpClientActivity
定义类成员
TextView result;
ListView tv;
URL url;
Handler mHandler = new Handler();
HttpURLConnection conn;
String title, href, time, content;
String myurl1 = "https://www.csdn.net/api/articles?type=more&category=newarticles&shown_offset=1527860608000000";
Document doc = null;
定义爬虫函数,从服务器读取网页内容
public String crawler(String httpUrl) {
String msg = "";
try {
//创建URL对象
URL url = new URL(httpUrl); //创建HttpURLConnection对象
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); //设置连接相关属性
httpURLConnection.setConnectTimeout(5000); //设置连接超时为5秒
httpURLConnection.setRequestMethod("GET"); //设置请求方式(默认为get)
httpURLConnection.setRequestProperty("Charset", "UTF-8"); //设置uft-8字符集 //建立到连接(可省略)
httpURLConnection.connect(); //获得服务器反馈状态信息 //200:表示成功完成(HTTP_OK), 404:请求资源不存在(HTTP_NOT_FOUND)
int code = httpURLConnection.getResponseCode();
if (code == HttpURLConnection.HTTP_OK) { //接收服务器返回的信息(输入流)
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(httpURLConnection.getInputStream()));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
msg += line + "\n";
} //关闭缓冲区和连接
bufferedReader.close();
httpURLConnection.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
return msg;
}
自定义list2
ArrayList<blog> list2 = new ArrayList<>();
利用JSON调用接口动态爬取页面
new Thread(new Runnable() { @Override public void run() { final String r = crawler(myurl1); mHandler.post(new Runnable() { @Override public void run() { Gson gson = new Gson(); Map<String, Object> map = new HashMap<>(); map = gson.fromJson(r, map.getClass()); ArrayList<Object> list = (ArrayList<Object>) map.get("articles"); for (int i = 0; i < list.size(); i++) { Map<String, String> map2 = (Map<String, String>) list.get(i); Log.v("info2", map2.get("title").toString()); blog temp_blog = new blog(map2.get("title").toString(), map2.get("summary").toString(), map2.get("url").toString()); list2.add(temp_blog); } blogAdapter blogAdapter = new blogAdapter(getApplicationContext(), R.layout.listview_item, list2); tv = (ListView) findViewById(R.id.tv); tv.setAdapter(blogAdapter); tv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { blog blog1 = list2.get(i); Toast.makeText(HttpClientActivity.this, "" + blog1.getURL(), Toast.LENGTH_SHORT).show(); Intent intent = new Intent(getApplicationContext(), DetailActivity.class); Bundle bundle = new Bundle(); String url_build = "https" + list2.get(i).getURL().substring(4); bundle.putString("url", url_build); intent.putExtras(bundle); startActivity(intent); } }); } }); } }).start();
4、blog
public class blog {
private String title;
private String comment;
private String URL;
public blog(String title, String comment, String URL) {
this.title = title;
this.comment = comment;
this.URL = URL;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getURL() {
return URL;
}
public void setURL(String URL) {
this.URL = URL;
}
@Override
public String toString() {
return "blog{" +
"title='" + title + '\'' +
", comment='" + comment + '\'' +
", URL='" + URL + '\'' +
'}';
}
}
5、blogAdapter
public class blogAdapter extends ArrayAdapter { private int resourceId; public blogAdapter(Context context, int textViewResourceID, ArrayList<blog> object) { super(context,textViewResourceID,object); resourceId = textViewResourceID; } @Override public View getView(int position, View convertView, ViewGroup parent) { blog blog_temp = (blog) getItem(position); View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false); TextView blog_title = (TextView)view.findViewById(R.id.tv_title); blog_title.setText(blog_temp.getTitle()); TextView comment = (TextView)view.findViewById(R.id.tv_comment); comment.setText(blog_temp.getComment()); TextView item_url = (TextView)view.findViewById(R.id.tv_url); item_url.setText(blog_temp.getURL()); return view; } }
6、DetailActivity
tv=(TextView)findViewById(R.id.text);
tv.setMovementMethod(ScrollingMovementMethod.getInstance());
Intent intent=getIntent();
Bundle bundle=intent.getExtras();
final String myurl=bundle.getString("url");
// httpUrl=myurl; Log.v("test",myurl);
Jsoup静态解析页面
String art_content = "";
Document doc= Jsoup.parse(r);
Elements elems = doc.getElementsByClass("article_content");
for(Element elem : elems)
{
Elements p_s = elem.getElementsByTag("p");
for(Element p : p_s)
{
art_content+=p.text();
//Log.v("content",);
}
}
tv.setText(art_content);
六、实验小结
最后一个爬虫实验在老师给的实验代码基础上完成了从服务器获取的数据进行解析功能这一块的实现,jsoup静态解析网页,以及json调用动态接口,以及最后将获取的信息加以处理,自定义布局的实现,这一过程中对于网页有了更近一步的了解,调试代码log发挥了很大的作用。网络爬虫是大数据重要的组成部分,在这次实验过程中我学习到了一些网络爬虫的相关知识,感觉到了它的强大,也对它产生了浓厚的兴趣,如果以后没有遇到更感兴趣的东西我会选择向大数据的方向发展。