"First Line of Code" Extended Summary

Two ways for Android to update UI - handler and runOnUiThread()

 

1. Intent transfer object method:

Serializable

Parcelable

 

2. Global Context acquisition:

Android provides an Application class, which is automatically initialized by the system whenever the application starts. We can define our own Application, some global state information in the user management program.

 

3. WebView control to display web pages

 

4. Asynchronous message processing:

Message, Handler, MessageQueue (message queue), Looper

Each thread has only one MessageQueue object, Looper object

After the message is sent through the Handler, the Message will be added to the MessageQueue queue to be processed. Looper has been trying to retrieve the pending message from the MessageQueue queue and distribute it back to the handleMessage() method of the Handler.

 

After the main thread is created, a Looper object will be created. When the Looper object is created, a messageQueue will be created , and Looper is a poller that will continuously poll the messages in the messageQueue. After getting the message, it will put this The message is handed over to the handler for processing, and a handler object is created in the main thread. This handler object can not only obtain the message for processing, but also put a message into the message queue.

 

The relationship between Message, Handler, MessageQueue, Looper

 Android message processing mechanism (Handler, Looper, MessageQueue and Message)

 

Android asynchronous message processing mechanism ~ in-depth understanding of the relationship between Looper, Handler, and Message

The Magical Use of Android Handler Asynchronous Message Processing Mechanism ~ Create a Powerful Image Loading Class

 

 

 5. There are two ways to implement asynchronous task mechanism in Android , Handler and AsyncTask.

The Handler mode needs to create a new thread for each task. After the task is completed, a message is sent to the UI thread through the Handler instance to complete the interface update. This method has finer control over the entire process, but it also has disadvantages. For example, the code is relatively It is bloated, and it is not easy to precisely control the thread when multiple tasks are executed at the same time. In order to simplify the operation, Android 1.5 provides the tool class AsyncTask abstract class, which makes it easier to create asynchronous tasks, and no longer needs to write task threads and Handler instances to complete the same tasks.

Explain the use of AsyncTask in Android (including source code analysis)

 

 

6、Service:

How to use BINDSERVICE in ANDROID

Understanding of the use of BindService in Android

<1> Create a new DownloadBind inner class that inherits the Bind class, and interacts with the active binding through the DownloadBind class object.

In the Activity, instantiate the implementation class of the ServiceConnection interface and override the onServiceConnected() and onServiceDisconnected() methods

Bind:

bindService(intent, conn,BIND_AUTO_CREATE);

 

BindService and Started Service are both Services, what's the difference:

1. The StartService() method is used in the Started Service to call the method. There is no connection between the caller and the service. Even if the caller quits, the service is still in progress [onCreate()->onStartCommand()->startService()- >onDestroy()], note that there is no onStart(), which is mainly replaced by the onStartCommand() method, and the onStart method is not recommended.

 

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

 

 

10、数据存储

<1>、文件存储

存储到或读取SdCard上文件

Android数据的四种存储方式

Android数据存储实现的5大方式

存储:openFileOutput("文件名","操作模式")

默认存储在/data/data/<package name>/files/目录下

读取:openFileInput("文件名")

new Scanner方式和new BufferReader方式

自动到/data/data/<package name>/files/目录下读取文件

 

<2>、SharedPreference存储

键值对存储

a、调用SharedPreference对象的edit()方法获取一个SharedPreference.Editor对象

b、向SharedPreference.Editor对象中添加数据 putString..putInt..

c、commit()提交

读取:SharedPreference对象提供的getString..getInt..

范例:记住密码功能

适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等)等

 

<3>、数据库存储

自定义类继承SQLiteOpenHelper抽象类

数据库文件默认存储在/data/data/<package name>/databases/目录下

调用getReadableDatabase()或getWritableDatabase()可以创建或打开一个数据库

 

查询时别忘了调用cursor的close()方法释放数据库连接

 

范例:升级数据库的最佳写法

 

 

11、广播Broadcast

Android总结篇系列:Android广播机制

Android中的广播Broadcast详解

Android入门:广播发送者与广播接收者

标准广播

没有先后顺序,所有广播接收器几乎都在同一时刻接收到该广播消息

有序广播

有先后顺序,同一时刻只有一个广播接收器可收到该消息

 

发送标准广播

Intent intent = new Intent("com.example.MY_BROADCAST");

sendBroadcast(intent);

 

发送有序广播

先后顺序判定标准遵循为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照priority属性值从大到小排序,对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。

Intent intent = new Intent("com.example.MY_BROADCAST");

sendOrderedBroadcast(intent,null);

 

创建广播接收器

自定义类继承BroadcastReceiver抽象类

默认情况下,广播接收器也是运行在UI线程,因此,onReceive方法中不能执行太耗时的操作。否则将因此ANR。一般情况下,根据实际业务需求,onReceive方法中都会涉及到与其他组件之间的交互,如发送Notification、启动service等。

当广播接收者onReceive方法需要执行很长时间时,最好将此耗时工作通过Intent发送给Service,由Service完成,并且不能使用子线程解决,因为BroadcastReceiver是接收到广播后才创建的,并且生命周期很短,因此子线程可能在没有执行完就已经被杀死了。

 

截断广播

在广播接收器的onReceive()中使用abortBroadcast()

 

注册广播方式

动态注册:在代码里注册

必须程序启动才能接收广播

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); //网路发生变化时,系统发出的值为该Action的系统广播

NetworkChangeReceiver receiver = new NetworkChangeReceiver();//自定义的广播接收器类

registerReceiver(receiver,intentFilter);

 

注意在onDestory()方法中取消注册:unregisterReceiver(receiver);

 

静态注册:在AndroidManifest.xml里注册

程序不启动也可接收广播

 

<receiver android:name=".NetworkChangeReceiver">
	<intent-filter android:priority="100">  <!-- 有序广播需要加该参数-->
		<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
	</intent-filter>
</receiver>
  

使用本地广播

使用LocalBroadcastManager来对广播进行管理

对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册的ContextReceiver才有可能接收到(静态注册或其他方式动态注册的ContextReceiver是接收不到的)。

 

LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);

manager.sendBroadcast(intent);

manager.unregisterReceiver(receiver);

..

  

范例:广播最佳实践-实现强制下线功能

思路:在界面上弹出一个对话框,让用户无法进行其他操作,必须点击对话框中的确定按钮,然后回到登录界面即可

在LoginActivity登录后,跳转到登录成功主界面MainActivity,在MainActivity中点击按钮发出强制下线广播,跳转到登录界面

LoginActivity   -> MainActivity    ->   ForceOfflineReceiver  ->   LoginActivity

 

 

12、

 

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

天气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里并启动

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326654346&siteId=291194637