《第一行代码》小结

《第一行代码》总结

Android更新UI的两种方法——handler与runOnUiThread()

 

1、Intent传递对象方式:

Serializable

Parcelable

 

2、全局Context获取:

Android提供了一个Application类,每当应用程序启动时,系统会自动将这个类初始化。我们可以定义个一个自己的Application,用户管理程序内的一些全局状态信息。

 

3、WebView控件展示网页

 

4、异步消息处理:

Message、Handler、MessageQueue(消息队列)、Looper

每个线程只有一个MessageQueue对象、Looper对象

通过Handler发送了消息后,该Message会被添加到MessageQueue队列中等待被处理,Looper一直尝试从MessageQueue队列取出待处理消息,分发回Handler的handleMessge()方法中。

 

在主线程创建之后会创建一个Looper对象,创建Looper对象的时候会去创建一个messageQueue,而Looper是一个轮询器,会不停的轮询messageQueue中的消息,在获取到消息之后就会把这个消息交给handler来进行处理,在主线程中创建一个handler对象,这个handler对象不仅可以获取到消息进行处理,也可以把一个消息放到消息队列中。

 

Message、Handler、MessageQueue、Looper之间的关系

 Android消息处理机制(Handler、Looper、MessageQueue与Message)

 

Android异步消息处理机制~深入理解 Looper、Handler、Message三者关系

Android Handler 异步消息处理机制的妙用~创建强大的图片加载类

 

 

 5、在Android中实现异步任务机制有两种方式,Handler和AsyncTask。

Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。为了简化操作,Android1.5提供了工具类AsyncTask抽象类,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。

详解Android中AsyncTask的使用(包含源码解析)

 

 

6、Service:

ANDROID中BINDSERVICE的使用方法

Android中BindService方式使用的理解

<1>、新建一个DownloadBind内部类继承Bind类,通过DownloadBind类对象实现与活动绑定交互。

在Activity里,实例化ServiceConnection接口的实现类,重写onServiceConnected()和onServiceDisconnected()方法

绑定:

bindService(intent, conn,BIND_AUTO_CREATE);

 

BindService和Started Service都是Service,有什么地方不一样呢:

1. Started Service中使用StartService()方法来进行方法的调用,调用者和服务之间没有联系,即使调用者退出了,服务依然在进行【onCreate()-  >onStartCommand()->startService()->onDestroy()】,注意其中没有onStart(),主要是被onStartCommand()方法给取代了,onStart方法不推荐使用了。

 

2. BindService中使用bindService()方法来绑定服务,调用者和绑定者绑在一起,调用者一旦退出服务也就终止了【onCreate()->onBind()->onUnbind()->onDestroy()】。

 

bindService()启动service的生命周期和调用bindService()方法的Activity的生命周期是一致的,也就是如果Activity如果结束了,那么Service也就结束了。Service和调用bindService()方法的进程是同生共死的。好的编程习惯,都是在Activity的onStop()方法中加上unBindService(ServiceConnection conn)代码

 

<2>、前台服务

服务的优先级比较低,当内存不足时,系统会回收掉正在后台运行的服务。如果希望服务一直保持运行状态,就需要用前台服务。

譬如墨迹天气一直在通知栏展示天气情况

 

<3>、异步的自动停止的服务

服务默认运行在主线程中,如果处理的任务比较耗时,就会出现ANR(Application Not Responding)所以需要在服务的处理方法中开启一个线程。

public int onStartCommand(Intent intent,int flags, int startId){
	new Thread(new Runnable(){		
		public void run(){
			
		     //执行完毕后自动停止
		     stopSelf();
		}
	}).start();
	return super.onStartCommand(intent,flags,startId);
}

 

这种方法容易忘记开启线程,或者容易忘记执行stopSelf(),所以Android提供了IntentService类,继承其即可。

 

<4>、Android定时任务的两中方式:JavaAPI里的Timer类,Android的Alarm机制。

Timer方法不适合长期在后台运行的定时任务,因为手机CPU会休眠,就无法执行。

Alarm机制可以唤醒CPU。

启动服务后,定时跳转到一个广播接收器中,接收到时再跳转到服务中。

 

 

7、Handler、HandlerThread

Handler:

一般来说在子线程中执行耗时任务,当任务完成时,会返回UI线程,一般是更新UI。这时有两种方法可以达到目的。

一种是子线程handler.sendMessage发一个消息主线程接收,然后更新UI

另一种是handler.post(r)。r是要执行的任务代码。意思就是说r的代码实际是在UI线程执行的。可以写更新UI的代码。(子线程是不能更新UI的)   

  

handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), 也就是说Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定。

handler.post(r)同一个线程的疑惑

Handler handler = new Handler(); 

/**该方法的内部类将在handler.sendMessage(msg)后执行
Handler handler = new Handler(){ 	
	@Override
	public void handleMessage(Message msg){ 	
		System.out.println("msg:"+msg.arg1); 
	} 
};*/

  

HandlerThread

Android HandlerThread 完全解析

HandlerThread三种不同的传值方式1

HandlerThread三种不同的传值方式2

HandlerThread三种不同的传值方式3

Android中Handler的使用,一般都在UI主线程中执行,因此在Handler接收消息后,处理消息时,不能做一些很耗时的操作,否则将出现ANR错误。Android中专门提供了HandlerThread类,来解决该类问题。

HandlerThread类继承自Thread,专门处理Hanlder的消息,依次从Handler的队列中获取信息,逐个进行处理,保证安全,不会出现混乱引发的异常。HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它有个Looper成员变量。

首先Handler和HandlerThread的主要区别是:Handler与Activity在同一个线程中,HandlerThread与Activity不在同一个线程,而是在新的线程中(Handler中不能做耗时的操作)。

 

<1>、创建一个HandlerThread,即创建了一个包含Looper的线程。

HandlerThread handlerThread = new HandlerThread("leochin.com");

handlerThread.start();

 //创建HandlerThread后一定要记得start()

 

<2>、获取HandlerThread的Looper

Looper looper = handlerThread.getLooper();

 

<3>、创建Handler,通过Looper初始化

Handler handler = new Handler(looper);

通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。

 

如果想让HandlerThread退出,则需要调用handlerThread.quit()。

 

 

8、通知Notification

PendingIntent延迟执行的Intent

 

在MainActivity里发出通知,点击时进入NoticationActivity中

NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
Notification notification = new Notification(R.drawable.ic_launcher,"This is ticket text",System.currentTimeMillis());  
Intent intent = new Intent(this,NoticationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);  
notification.setLatestEventInfo(this, "This is content title", "This is content text",pi);  
manager.notify(1, notification);  

 接收到通知后调用manager.cancel(1)可取消通知。

  

接收、发送、拦截短信

发送短信:

<1>、MainActivity中注册接收通知广播

为防止自定义MessageReceiver和系统默认短信程序都接收到短信,可设置自定义MessageReceiver的优先级,然后拦截短信广播即可

IntentFilter receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provicer.Telephony.SMS_RECEIVED");
//receiveFilter.setPriority(100);
MessageReceiver messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver,receiveFilter);

 

<2>、点击按钮时发送

SmsManager manager = SmsManager.getDefault();
manager.sendTextMessage(to.getText().toString(), null , msgInput,getText().toString() ,null,null);

/**
* 监控发送状态(发送时第四个参数为PendingIntent)
* SmsManager manager = SmsManager.getDefault();
* Intent sentIntent = new Intent("SEND_SMS_ACTION");
* PendingIntent pi = PendingIntent.getBroadcast(MainActivity.this,0,sentIntent,0);
* manager.sendTextMessage(to.getText().toString(), null , msgInput,getText().toString() , pi, null);
* 
* 注册时:
* IntentFilter receiveFilter = new IntentFilter();
* receiveFilter.addAction("SEND_SMS_ACTION");
* SendStatusReceiver sendStatusReceiver = new SendStatusReceiver();
* registerReceiver(sendStatusReceiver,receiveFilter);
*/

 

接收短信:

使用广播接收器BroadcastReceiver(自定义一个MessageReceiver)来接收短信

 

class MessageReceiver extends BroadcastReceiver{...}
//class SendStatusReceiver extends BroadcastReceiver{...}

调用摄像头拍照

从相册中选择图片

播放音频、视频

 

 

9、内容提供其Content Provider

为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。

ContentProvider和Uri详解

Content Provider应用实例

 

URI:

权限(authority/包名) + 路径(path/表名)

标准URI:

content://包名/表名

字符串转URI

Uri uri = Uri.parse(标准URI)

匹配内容URI:

UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

uriMatcher.addURI("权限","路径","自定义代码");

uriMatcher.match(uri):返回自定义代码

 

读取系统联系人

getContentResolver().query()..

 

创建自己的内容提供器

新建类继承ContentProvider即可,注意需要在AndroidMainTest.xml中注册

 

getType():

获取URI对象对应的MIME类型

 

URI对应的MIME字符串有三部分组成:

<1>、必须以vnd开头

<2>、如果URI以路径结尾,后接android.cursor.dir/;如果URI以ID结果,后接android.cursor.item/

<3>、最后接上 vnd.权限.路径

例:

URI: content://com.example.app.provider/table1

MIME为:vnd.android.cursor.dir/vnd.com.example.app.provider.table1

 

URI:content://com.example.app.provider/table1/1

MIME为:vnd.android.cursor.item/vnd.com.example.app.provider.table1

 

 

 

=============================================================================

天气APP总结

文件夹:

activity

db

model

service

receiver

util

 

建库:

CoolWeatherOpenHelper.java -->  SQLiteOpenHelper

 

Model:

Province.java

City.java

Country.java

  

数据库操作类:

CoolWeatherDB.java

        单例模式

        saveProvince(Province province)..

        loadProvince()..

  

服务器交互:

HttpUtil.java

        通过URL取数据

        sendHttpRequest(final String address,final HttpCallbackListener listener);

        新建一个线程发送请求

 

        HttpCallbackListener

        回调服务接口,定义两个方法onFinish、onError

 

 

工具类解析数据:

Utility.java

        返回的数据格式为"代号|城市,代号|城市"

        解析数据后保存到数据库

        handleProvincesResponse(CoolWeatherDB coolWeatherDB ,String response)

        handleCitiesResponse(CoolWeatherDB coolWeatherDB ,String response ,int provinceId)

        ...

         取到天气数据后,将数据保存到本地SharedPreferences

         handleWeatherResponse(Context context , String respone)

         saveWeatherInfo(..)

 

 

选择省、市、县活动:

CoolWeatherActivity.java

        queryFromServer(final String code , final String type )

                queryFromServer(null , "province" )

                queryFromServer(selectProvince.getProvinceCode() , "city" )

        调用HttpUtil中方法取数据,取到数据后通过runOnUiThread回到主线程处理逻辑

         runOnUiThread是Activity内部的方法

 

 展示天气活动:

        WeatherActivity.java

        有县code时直接从本地取,没有时通过URL获取

        直接显示:showWeather()

 

后台自动更新天气:

AutoUpdateService.java -> Service

        在onStartCommand里启动一个线程,通过HttpUtil取到最新的天气,然后更新updateWeather(更新SharePreferences)

        启动一个定时任务,跳转到通知AutoUpdateReceiver.java

        在通知的onReceive()方法里再跳转到服务AutoUpdateService里并启动