Android学习笔记(二)

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的时候,如果用

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类来帮助插入数据:

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.更新数据  

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.查询数据     

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类来输出调试信息:

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对象

URL url = new URL(String urlStr);

  2).创建一个HttpURLConnection

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

  3).获得一个InputStream对象

InputStream inputStream = urlConn.getInputStream();

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

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

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

       源代码:

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以后对这部分程序进行了优化,也就是说访问网络的代码不能写在主线程中了。

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

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

String path = Environment.getExternalStorageDirectory();

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

 <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  

SAXParserFactory factory = SAXParserFactory.newInstance();

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

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

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

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

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

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

reader.setContentHandler(new MyContentHandler());

       //4.开始解析文件

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

6. 广播机制

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

<receiver android:name=”.TestReceiver”>
    <inteng-filter>
        <action androi:name=”andriod.intent.action.EDIT”/>
    </intent-filter>
</receiver>

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

class TestReceiver extends BroadcastReceiver{
    @Override
    public void onReceiver(Context context, Intent intent){
         //这里写处理流程
    }
}

       注意蓝色部分的匹配。

       而在发送方,可以使用:

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只做一次处理,如果处理过了,那么这个对象就没用了,如果再有同样的广播发送出来,那么操作系统会再生成这样一个对象来处理。


你可能感兴趣的:(android,笔记)