Android学习笔记(二)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:

1. Handler的使用

       1.Handler类是android.os下的一个类,handler.post(Runnable r)可以将一个线程添加到消息队列中;handler.postDelay(Runnable r, long delayTime)在延迟delayTime毫秒后,将线程添加到消息队列中;handler.removeCalbacks(Runnable r)将队列中挂起的Runnable移出。

       2.Handler.obtainMessage()可以获得一条消息,这个消息有两个整型的参数arg1和arg2,利用它可以传递消息。在创建Handler的时候,如果用

?
1
2
3
4
5
6
Handler handler =  new  Handler(){
    @Override
    public  void  handleMessage(Message msg){
       ……
    }
}

  来创建的话,该handler可以从消息队列(MessageQueue)中取出消息并在handleMessage方法中处理。而在另一个地方,也可以使用handler.sendMessage(Message msg)来向消息队列中发送消息。

  Handler对于线程的处理并不是另外开启一个线程,而是在原有线程的基础上调用另一个Runnable的run函数。HanlderThread类实现了Looper来处理消息队列的功能,这个类由Android操作系统提供。利用该类,可以使用getLooper()(在使用getLooper()方法之前,必须调用该类的start()方法,否则这个Looper是null)方法来获取这个Looper,之后,将这个Looper以参数的形式传递给Handler的构造函数,此时这个Handler的handleMessage()方法就可以由另一个线程来处理了,就不会阻塞Activity。

       可以把Bundle看作一个特殊的Map,只是它的键固定为String类型,值也只有几种基本的数据类型。

       在使用Message传递数据的时候,发送之前可以使用Message.obj来传递一个数据,这个数据是一个Object即可。处理消息的时候,也可以使用Message.obj来获取,此时需要向下转型。如果需要传递大量数据,可以使用Message.setData(Bundle data)。

       Message.sendToTarget();方法可以讲这个message发送给创建这个Message的Handler,在这个Handler里面可以接收该Message。

2. SQLite的使用

       1. SQLiteOpenHelper类的使用

    public abstract class SQLiteOpenHelper类中有几个函数:

    onCreate(SQLiteDatabase db);当数据库第一次创建的时候调用这个方法

    onOpen(SQLiteDatabase db);当数据库被打开的时候调用这个方法

    onUpgrade(SQLiteDatabase db);当数据库需要升级的时候调用这个方法

    getReadableDatabase();获得可以读的数据库

    getWritbaleDatabase();获得可以写的数据库

       我们一般继承这个类,然后调用构造函数(父类没有默认构造函数)。数据库的版本为整数,从1开始,每次升级数据库版本的时候,这个值依次递增。当发现这个值变化的时候,就意味着数据库已经进行了版本升级。

       使用SQLiteDatabase.execSQL(String sql)来执行SQL语句。

       2.adb工具的使用

可以使用adb工具(在cmd中输入adb即可,在这之前需要为它配置环境变量,在sdk/platform-tools下面,另一个就是要保证模拟器AVD是打开的,否则会报错)来查看数据库中的变化:

       adb shell:进入Linux命令行(android操作系统是以Linux为核心的)

       ls –l:以完整的形式显示文件和文件夹

       cd data:进入data

       cd data:再进入data

       这里面有很多文件夹(以应用程序的包名命名),每一个应用程序都有一个文件夹

       cd com.example.sqlite3:进入我们当前的应用程序

       创建数据库后,这里面会多一个叫databases的文件夹

       cd databases:进入这个文件夹,这里面可以看到刚刚创建的数据库

       sqlite3 mydb:使用SQLite打开数据库mydb

       然后就可以像Mysql一样使用数据库了:

       select * from table_name;……

       3.插入数据

       使用ContentValues类来帮助插入数据:

?
1
2
3
4
5
6
7
8
ContentValues values =  new  ContentValues();
values.put(“id”, 1 ); //第一个参数为列名,第二个参数为列的值
values.put(“name”,”alvis”);
//DatabaseHelper类继承于SQLiteOpenHelper类
DatabaseHelper dbHelper =  new  DatabaseHelper(MainActivity. this ,”mydb”);
//得到一个数据库对象
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.insert(“user”, null ,values); //调用insert方法插入数据。

  insert方法的第一个参数为表名,第二个直接填null即可。第三个为带有数据的ContentValues对象。

  4.更新数据  

?
1
2
3
4
5
6
DatabaseHelper dbHelper =  new  DatabaseHelper(MainActivity. this ,”mydb”);
//得到一个数据库对象
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values =  new  ContentValues();
values.put(“name”,”alvis”);
db.update(“user”,values,”id=?”, new  String[]{“ 1 ”}); //这里使用占位符来设置参数

  整个这几句其实就组成了一句话:

  update user set name=’alvis’ where id=1;

  update方法第一个参数是要更新的表名,第二个参数是带有要更新值的ContentValues对象,第三个参数是where字句的条件(可以有多个),第四个参数为where字句的值,类型为String[]。

       5.查询数据     

?
1
2
3
4
5
6
7
8
DatabaseHelper dbHelper =  new  DatabaseHelper(MainActivity. this ,”mydb”);
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query(“user”,  new  String[]{“id”,”name”}, ”id=?”,  new  String[]{“ 1 ”}, null , null ,”id” );
while (cursor.moveToNext()){
     //这里处理获得的数据
     String result = cursor.getString(cursor.getColumnIndex(“name”));
     System.out.println(result);
}

       cursor.moveToNext()方法有两个作用: 将游标下移看是否有下一条记录,有就返回true,否则返回false,就是说把指针移到下一个位置的同时还判断是否还有值。

       query方法的参数依次为(后面三个参数均为字符串):

表名,查询的字段,查询条件,条件的参数,groupBy,having,orderBy

其实就是把一条select语句分解成了很多部分。

       使用cursor获取数据的时候,参数一定要是要查询所在列的索引,这个索引可以通过cursor.getColumn(String columnName)来获得,于是就有了上面的写法。

       建议不要太多的依赖于数据库,也不要在SQLite数据库中存入太多的数据,因为在开发的时候可能会出现很多奇怪的问题。

3. Android程序调试

       可以使用Log类来输出调试信息:

?
1
2
3
4
5
Log.i(String tag,String message); //Info级别的
Log.v(String tag,String message); //致命的
Log.w(String tag,String message); //警告
Log.e(String tag,String message); //错误
Log.d(String tag,String message); //调试

4. 文件下载

  1.下载文件的步骤:

  1).创建一个URL对象

?
1
URL url =  new  URL(String urlStr);

  2).创建一个HttpURLConnection

?
1
HttpURLConnection urlConn = (HttpURLConnection)url.openConnection();

  3).获得一个InputStream对象

?
1
InputStream inputStream = urlConn.getInputStream();

  然后就可以使用流操作读取这个inputStream了

  4).访问网络的权限:在Manifest.xml中声明:

?
1
< uses-permission  android:name = "android.permission.INTERNET" />

       源代码:

?
1
2
3
4
5
6
7
class  DownloadMP3Listener  implements  OnClickListener{
     @Override
     public  void  onClick(View v) {
         HttpDownloader httpDownloader =  new  HttpDownloader();
         int  status = httpDownloader.downFile( "http://192.168.2.104:8080/source/ yiwangeshebude.mp3" "Download" "一万个舍不得.mp3" );
     }
}

       错误:android.os.NetworkOnMainThreadException

  这个异常大概意思是在主线程访问网络时出的异常。 Android在4.0之前的版本 支持在主线程中访问网络,但是在4.0以后对这部分程序进行了优化,也就是说访问网络的代码不能写在主线程中了。

  解决办法:重新开启一个线程去跑网络相关的代码。  

?
1
2
3
4
5
6
7
8
9
10
11
12
class  DownloadMP3Listener  implements  OnClickListener{
     @Override
     public  void  onClick(View v) {
         new  Thread(){       //重新开启一个线程去访问网络
             @Override
             public  void  run(){
                 HttpDownloader httpDownloader =  new  HttpDownloader();
                 int  status = httpDownloader.downFile( "http://192.168.2.104:8080/source/ yiwangeshebude.mp3" "Download" "一万个舍不得.mp3" );
             }
         }.start();
     }
}

       2.访问SD卡

       1).得到当前设备SD卡的目录:一般就是 /SDCARD

?
1
String path = Environment.getExternalStorageDirectory();

       2).在Manifest.xml文件中设置访问SD卡的权限(和application标签同级)  

?
1
  < uses-permission  android:name = "android.permission.INTERNET" />

5. ContentProvider初步

       1.每一个ContentProvider都有一个公共的URI,这个URI表示这个ContentProvider所提供的数据。Android提供的ContentProvider都在android.provider包中。

       2.ContentProvider所提供的函数:

       query():查询             insert():插入                    update():更新

   delete():删除            getType():得到数据类型  onCreate():创建时的回调函数

  3.实现ContentProvider的过程:

       1).定义一个CONTENT_URI常量

       2).定义一个类,继承ContentProvider类

       3).实现query,insert,update,delete,getType和onCreate方法

       4).在AndroidManifest.xml中进行声明

6. XML文件解析

       ContentHandler接口

       ContentHandler是Java类包中一个特殊的SAX接口,位于org.xml.sax包中,该接口封装了一些对事件处理的方法,当XML解析器开始解析XML输入文档时,它会遇到某些特殊的事件,比如文档的开头和结束、元素的开头和结束、以及元素中的字符数据等事件。当遇到这些事件时,XML解析器会调用ContentHandler接口中相应的方法来响应该事件。

       ContentHandler接口的方法有以下几种:

       void startDocument()

       void endDocument()

       void startElement(String uri,String localName,String qName,Attributes atts)

       void endElement(String uri,String localName,String qName)

       void characters(char[] ch,int start,int length)读取到中间的字符的时候调用

       通常的处理流程如下:

       1).创建事件处理程序

       2).创建SAX解析器

       3).将事件处理程序分配给解析器

       4).对文档进行解析,将每个时间发送给处理程序

       如下面的例子:

   //1.创建一个SAXParserFactory  

?
1
SAXParserFactory factory = SAXParserFactory.newInstance();

       //2.通过这个factory获得一个XMLReader

?
1
  XMLReader reader = factory.newSAXParser().getXMLReader();

       //3.为XMLReader设置内容处理器

       //注意这个方法的参数是一个ContentHander,但是由于ContentHandler里面的

       //方法太多,因此这里使用适配器模式,MyContentHandler是继承于DefaultHandler

   //的,而DefaultHandler实现了ContentHanlder接口。

?
1
reader.setContentHandler( new  MyContentHandler());

       //4.开始解析文件

?
1
reader.parse( new  InputSource( new  StringReader(xml)));

6. 广播机制

       如果要监听某一类事件,则需要在Manifest.xml文件中声明:

?
1
2
3
4
5
< receiver  android:name=”.TestReceiver”>
     < inteng-filter >
         < action  androi:name=”andriod.intent.action.EDIT”/>
     </ intent-filter >
</ receiver >

  同时接收方需要继承BroadcastReceiver类,并复写onReceiver方法:

?
1
2
3
4
5
6
class  TestReceiver  extends  BroadcastReceiver{
     @Override
     public  void  onReceiver(Context context, Intent intent){
          //这里写处理流程
     }
}

       注意蓝色部分的匹配。

       而在发送方,可以使用:

?
1
2
3
Intent intent =  new  Intent();
intent.setAction(Intent.ACTION_EDIT);
TestActivity. this .sendBrodcast(intent);

       注意intent的ACTION需要匹配,否则接收不到这个消息。

       这个程序的大体流程是:TestActivity广播了一个action为ACTION_EDIT的 intent,TestReceiver因为继承了BroadcastReceiver,因此是一个广播的接收器,但是至于接不接收由TestActivity广播的intent,就要看在Manifest.xml文件中对TestReceiver的配置了。

在Manifest.xml文件中对于TestReceiver的配置里,<intent-filter>的<action>标签指明了TestReceiver监听的哪种action,只有当TestActivity广播的intent中的action和这里的action相同的时候,才会接收到,此时会生成一个TestReceiver,并调用该类的onReceiver方法。

       注意:TestReceiver只做一次处理,如果处理过了,那么这个对象就没用了,如果再有同样的广播发送出来,那么操作系统会再生成这样一个对象来处理。


目录
相关文章
|
7月前
|
架构师 网络协议 算法
Android高级架构师整理面试经历发现?(大厂面经+学习笔记(1)
Android高级架构师整理面试经历发现?(大厂面经+学习笔记(1)
|
7月前
|
消息中间件 缓存 架构师
2024年阿里Android高级面试题分享,附学习笔记+面试整理+进阶书籍
2024年阿里Android高级面试题分享,附学习笔记+面试整理+进阶书籍
|
缓存 安全 数据库
Android学习笔记4
Android学习笔记4
63 0
|
XML 数据库 数据安全/隐私保护
Android学习笔记3
Android学习笔记3
167 0
|
XML Java Android开发
Android学习笔记2
Android学习笔记2
77 0
|
XML Java Linux
Android学习笔记1
Android学习笔记1
61 0
|
存储 Java API
Android逆向 | 基础篇 - Java 学习笔记03
Android逆向 | 基础篇 - Java 学习笔记03
|
Java 编译器 Android开发
Android逆向 | 基础篇 - Java 学习笔记02
Android逆向 | 基础篇 - Java 学习笔记02
|
Java 编译器 Android开发
Android逆向 | 基础篇 - Java 学习笔记01
Android逆向 | 基础篇 - Java 学习笔记01
|
Java 开发工具 Android开发
Android中的Binder学习笔记
Android中的Binder学习笔记
Android中的Binder学习笔记