android AsyncTask和contentObserver分析

     在Android中有这么一个策略,当长时间玩大型游戏导致cpu温度过高或者说板子过热时会提示Throttling brightness due to Thermal event,此时会减弱屏幕亮度,最近客户报了一个问题,说虽然屏幕亮度减弱了,但SystemUI上的brightness并没有随着改变。本文主要讲解这个问题,并分析AsyncTask和contentObserver机制。

    SystemUI上的brightness没有随着改变,其根本原因是brightness的值没有更新到settings.db。settings.db是系统维护的一个数据库,其源码在frameworks/base/packages/SettingsProvider/,主要类是SettingsProvider.java,它继承contentProvider。settings.db在data/data/com.android.providers.settings/databases/下,一般在pc端安装SQLiteManager,将adb pull下来的settings.db用SQLiteManager打开可以查看具体内容。

   adb shell---> cd data/data/com.android.providers.settings/databases/---> ls,显示如下:

root@byt_t_ffrd8:/data/data/com.android.providers.settings/databases #ll
-rw-rw---- system   system      90112 2015-03-19 21:41 settings.db
-rw------- system   system      90800 2015-03-19 21:41 settings.db-journal

     对应的数据库settings.db只有用户system和用户组system才有读写权限,这是android的安全策略,防止其它进程改变settings.db。但这又有些不现实,如果有某个应用进程想访问settings.db,怎么办呢,这就是contentProvider的功劳,contentProvider相当于数据适配层,能够将settings.db中可以让客户访问的数据提供给用户使用。

      还是继续分析brightness吧, 在package/apps/Settings下面有brightnessPreference.java,类的定义如下:

public class BrightnessPreference extends Preference {

    public BrightnessPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onClick() {
        Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
        getContext().sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF);
    }
}

当点击该preference,会发送一个广播Intent.ACTION_SHOW_BRIGHTNESS_DIALOG,在frameworks/ base/packages/SystemUI/下面有settingsUI.java文件,它注册了该广播,代码如下:

        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG)) {
                if (DEBUG) Log.d(TAG, "showing brightness dialog");

                if (mBrightnessDialog == null) {
                    mBrightnessDialog = new BrightnessDialog(mContext);
                    mBrightnessDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                        @Override
                        public void onDismiss(DialogInterface dialog) {
                            mBrightnessDialog = null;
                        }
                    });
                }

                if (!mBrightnessDialog.isShowing()) {
                    mBrightnessDialog.show();
                }

            }
————————————————
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
        filter.addAction(Intent.ACTION_THERMAL_STATE_CHANGED);
        mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, mHandler);


当settingsUI.java收到广播后会创建BrightnessDialog对象,并将其显示出来,传递的参数SystemUI的上下文。然后进入BrightnessDialog的onStart()函数,代码如下:

    protected void onStart() {
        super.onStart();
        mBrightnessController = new BrightnessController(getContext(),
                (ImageView) findViewById(R.id.brightness_icon),
                (ToggleSlider) findViewById(R.id.brightness_slider));
        dismissBrightnessDialog(mBrightnessDialogLongTimeout);
        mBrightnessController.addStateChangedCallback(this);
    }

该函数创建BrightnessController对象,并将ImageView和ToggleSlider传递给BrightnessController。在BrightnessController中定义了一个类BrightnessObserver,它继承自contentObserver。这里就讲讲contentObserver类。

1、在调用contentObserver之前,必须获得当前上下文的contentResolver接口,即调用final ContentResolver cr = mContext.getContentResolver();

2、将需要监听的URI注册,即调用cr.registerContentObserver(BRIGHTNESS_MODE_URI, false, this, UserHandle.USER_ALL),其中BRIGHTNESS_MODE_URI表示需要监听的uri,this表示contentObserver地址。

3、然后实现contentObserver中的onChange函数,当需要监听的uri数据发生变化后会回调contentObserver中的onChange函数,从而在ui上更新slider。

综上得出,为什么屏幕亮度发生了改变但ui进度条没有变化,就是因为brightness数据未更新到settings.db,如果更新了,肯定会调用onChange函数从而更新进度条。

还有一个问题,数据该怎么更新到settings.db,BrightnessController中的代码是

                AsyncTask.execute(new Runnable() {
                        public void run() {
                            Settings.System.putIntForUser(mContext.getContentResolver(),
                                    Settings.System.SCREEN_BRIGHTNESS, val,
                                    UserHandle.USER_CURRENT);
                        }
                    });

为什么要这么写,因为更新数据库是一个耗时的操作,为了不使主线程阻塞从而引起anr,需要将更新数据库的操作另起一个线程运行。这里就要讲到AsyncTask。

在我们打开一个应用程序的时候会首先创建一个线程,这就是我们说的主线程,它会完成系统和UI之间的交互,并将交互后的结果显示在UI上,所以主线程也叫UI线程。其它的线程称为工作线程。这里会涉及两条重要的规则。

1、显示/更新UI的工作只能在主线程中进行,不能让其它的线程完成ui操作

2、绝对不能在ui线程中进行耗时的操作,比如网络访问或者数据库查询,否则会导致anr

问题就来了,如何处理主线程和工作线程之间的通信,有Hander和AsyncTask两种方法,这里介绍AsyncTask。AsyncTask注意三个泛型,四个步骤。

三个泛型即AsyncTask的三个形参,AsyncTask(Params, Progress, Result), 分别代表UI线程传递给异步任务的参数,异步任务在执行过程中将执行进度返回给ui线程的参数,异步任务完成后的返回结果。

四个步骤为onPreExecute、doInBackground、 onProgressUpdate、 onPostExecute。这里在工作线程中工作的只有doInBackground函数,其它三个都是在ui线程中完成。

AsyncTask的完成用法参考frameworks/base/services/..../ThermalNotifier.java,网页:http://www.cnblogs.com/xiaoluo501395377/p/3430542.html


AsyncTask下载图片的代码:

 

package com.example.gethttpresource;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
//import org.apache.http.util.EntityUtils;

import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.os.AsyncTask;

import android.util.Log;
import android.os.SystemClock;

public class MainActivity extends Activity {
	
	private Button showButton, saveButton;
	private ImageView mImageView;
	private byte[] mByte;
	private Bitmap mBitmap;
	private ProgressDialog mProgressDialog;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		showButton = (Button)findViewById(R.id.showPicture);
		saveButton = (Button)findViewById(R.id.savePicture);
		mImageView = (ImageView)findViewById(R.id.myImageView);
		showButton.setOnClickListener(mClickListener);
		saveButton.setOnClickListener(mClickListener);
		
		mProgressDialog = new ProgressDialog(this);
		mProgressDialog.setTitle("进度提示");
		mProgressDialog.setMessage("正在下载,请稍后");
		mProgressDialog.setCancelable(false);
		mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
	}
	
	private View.OnClickListener mClickListener = new View.OnClickListener() {
		
		@SuppressLint("NewApi")
		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			if(v == showButton){
				/*mProgressDialog.show();
				AsyncTask.execute(new Runnable(){
					@Override
					public void run(){
						URI uri = null;
						try {
							uri = new URI("https://img-my.csdn.net/uploads/201402/24/1393242467_3999.jpg");
						} catch (URISyntaxException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						HttpGet mHttpGet = new HttpGet();
						mHttpGet.setURI(uri);
						HttpClient mHttpClient = new DefaultHttpClient();
						try {
							HttpResponse mHttpResponse = mHttpClient.execute(mHttpGet);
							HttpEntity mHttpEntity = mHttpResponse.getEntity();
							if(mHttpEntity != null && mHttpResponse.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
								mByte = EntityUtils.toByteArray(mHttpEntity);
								mBitmap = BitmapFactory.decodeByteArray(mByte, 0, mByte.length);
							}
						} catch (ClientProtocolException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}

					}
				});
				if(mBitmap != null){
					mImageView.setImageBitmap(mBitmap);
				}*/
				String str = "https://img-my.csdn.net/uploads/201402/24/1393242467_3999.jpg";
				new DownloadPicture().execute(str);
			} else if (v == saveButton){
				
			}
		}
	};
	
	private class DownloadPicture extends AsyncTask<String, Integer, byte[]>{

		@Override
        protected void onPreExecute(){
        	super.onPreExecute();
        	mProgressDialog.show();
        }
		@Override
		protected byte[] doInBackground(String... arg0) {
			// TODO Auto-generated method stub
			URI uri = null;
			byte[] mByte = null;
			InputStream inputStream = null;
			HttpEntity mHttpEntity = null;
			ByteArrayOutputStream mOutput = new ByteArrayOutputStream();
			try {
				uri = new URI(arg0[0]);
			} catch (URISyntaxException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			HttpGet mHttpGet = new HttpGet();
			mHttpGet.setURI(uri);
			HttpClient mHttpClient = new DefaultHttpClient();
			HttpResponse mHttpResponse = null;
			try {
				Log.d("Yangmin", "HttpClient execute begin: " + SystemClock.uptimeMillis());
				mHttpResponse = mHttpClient.execute(mHttpGet);
				Log.d("Yangmin", "HttpClient execute end: " + SystemClock.uptimeMillis());
			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			finally{
				//Log.d("Yangmin", "mHttpClient shutdown");
				//mHttpClient.getConnectionManager().shutdown();
			}
			
			if(mHttpResponse == null){
				return null;
			}
			
			if(mHttpResponse != null){
				Log.d("Yangmin", "HttpResponse not null");
				mHttpEntity = mHttpResponse.getEntity();
			}
			
			if(mHttpEntity != null && mHttpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
				long file_length = mHttpEntity.getContentLength();
				long total_len = 0;
				int length = 0;
				byte[] data= new byte[1024];
				try {
					inputStream = mHttpEntity.getContent();
				} catch (IllegalStateException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				try {
					while((length = inputStream.read(data))!= -1){
						Log.d("Yangmin", "HttpClient execute: " + SystemClock.uptimeMillis());
						total_len += length;
						mOutput.write(data, 0, length);
						int progress = (int)(total_len/(float)file_length*100);
						Log.d("Yangmin", "progress : " + progress);
						publishProgress(progress);
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			mByte = mOutput.toByteArray();
			try {
				inputStream.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				mOutput.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return mByte;
		}
		
		@Override
		protected void onProgressUpdate(Integer... values){
			super.onProgressUpdate(values);
			Log.d("Yangmin", "update : " + values[0]);
			mProgressDialog.setProgress(values[0]);
		}
		
		@Override
		protected void onPostExecute(byte[] Byte){
			if(Byte != null ){
				mByte = Byte;
				mBitmap = BitmapFactory.decodeByteArray(mByte, 0, mByte.length);
				mImageView.setImageBitmap(mBitmap);
				if(mProgressDialog != null){
					mProgressDialog.dismiss();
				}
			}

		}
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}


 


 

 



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值