一.Activity的启动模式 两种方式四种模式
(1)在清单文件中,标签中配置android:launchMode=""属性
四个属性值:
<1>standard:
默认的 可以实例化多次,每次启动都会创建一个新的实例
<2>singleTop:
可以实例化多次,当其在栈顶时,只能创建一个实例
当栈顶存在要启动的Activity实例时,系统会调用onNewIntent()方法
把Intent对象传递给已经存在的Activity实例,从而重用栈顶的Activity
<3>singleTask:
栈内部只能有一个Activity实例,
解释一:当第二次启动该Activity时,系统会从上到下依次寻找该Activity已有的实例,
找到会移除它之上的所有Activity实例,并重用该Activity实例
解释二:当栈中存在要启动的Activity实例时,系统会调用onNewIntent() 方法
把Intent对象传递给已经存在的Activity实例,从而重用该Activity实例
<4>singleInstance:
系统会单独分配一个任务栈,并把它的实例放到栈底,不和别的Activity共享一个栈
(2)在Activity类中通过Intent对象设置启动模式,优先级高于上面的方式
Intent intent = new Intent();
intent.setFlags(Intent.参数);
参数:
默认 等同于standard
FLAG_ACTIVITY_SINGLE_TOP 等同于singleTop
FLAG_ACTIVITY_CLEAR_TOP 等同于singleTask
FLAG_ACTIVITY_NEW_TASK 等同于singleInstance
如果是代码中设置启动模式:NEW_TASK,则必须在清单文件中加上下面属性
android:taskAffinity="com.other"
android:allowTaskReparenting="true"
否则不起作用
二.Intent七大属性
(1)Intent的作用
包装android的组件
启动Activity ,启动Service,发送广播
组件之间的传值
(2)显示意图------setClass()
------setComponent();
明确指定要跳转到哪个Activity(通常用于启动应用内部的Activity)
写法一: Intent intent = new Intent(MainActivity.this,InfoActivity.class);
写法二: Intent intent= new Intent();
intent.setClass(MainActivity.this,InfoActivity.class);
写法三: ComponentName 包装Android组件
Intent intent = new Intent();
ComponentName cn = new ComponentName(MainActivity.this,InfoActivity.class);
intent.setComponent(cn);
(3)隐身意图------action
不明确指定目标Activity,而是通过Intent的动作action(通常用于多个应用程序之间的跳转)
必须在android应用中保持唯一
目标Activity中必须声明action属性
注意:action属性一般需要和category属性一起使用
访问者:
方式一: Intent intent=new Intent();
Intent();intent.setAction("com.qf.day06_lunchmode.CActivity");
方式二:
Intent intent = new Intent("com.qf.day06_lunchmode.CActivity");
android.setting.SETTINGS 设置页面
Intent.ACTION_DIAL 拨号页面
Intent.ACTION_CALL 拨打电话(直接呼出)
(4)category:表示action组件启动的类型
一般android.intent.category.DEFAULT 代表普通的Activity组件
(5)data属性:指定action后,将必须的属性设置在此属性中
如:打电话 必须提供电话号码
打开网页 网址
URI 统一资源标识
打电话: tel:53435343443
发短信: smsto:760439045
网址: http://www.baidu.com
(6)type属性:
如果data属性是文件的路径,必须通过type来指定文件的类型
图片: image/*
文本: text/*
视频: video/*
音频: audio/*
(7)extra 属性:除了必须的属性之外的扩展信息的属性
常用于Android组件之间传递数据
(8)flag:组件的启动模式 (参考Activity的启动模式)
广播接收器,启动Activity组件式,必须指定flag属
性:FLAG_ACTIVITY_NEW_TASK
三.AsyncTask的使用
(1)定义一个类,继承AsyncTask类,同时声明三个泛型
public class MyAsyncTask extends AsyncTask
第一个参数: 子线程执行方法的参数类型,对应doinbackground的参数
第二个参数: 子线程执行方法的进度, 对应onProgressUpdate的参数 可以为空,Void首字母应该大写
第三个参数: 子线程执行任务的结果返回类型,对应onPostExecute的参数和doInbackground的返回值
(2)AsyncTask的四个核心方法(重写)
//运行在主线程中,执行异步任务时,首先调用的方法,用于初始化
<1>protected void onPreExecute()//运行在子线程中,执行耗时的操作(后台线程)
<2>protected byte[] doInBackground(String... params)//运行在主线程中,用于更新 进度,更新前必须先手动 调用publishProgress()方 法
<3>protected void onProgressUpdate(Integer...values)//运行在主线程中,在 doInbackground方法之后 执行,系统自动调用
<4>protected void onPostExecute(byte[] result)
(3)利用回调接口来实时更新进度
<1>定义一个回调接口
public interface CallBack{
public void callBack(int progress);回调方法,参数为进度的百分比
}
<2>在访问网络的工具中声明回调接口(HttpUtils工具类)
public static String getJson(String path,CallBack callback){//以加载json字符串为例
//获取网络资源的代码
//调用CallBack接口中的回调方法传回进度
callback.callBack(progress);
}
<3>在doInBackground方法中调用getJson方法,同实例化一个CallBack接口的匿名内部类
protected byte[] donInBackground(String ... params){
HttpUtils.getJson(params[0],new CallBack(){
public void callBack(int progress){
//当获取网络资源的代码中调用此回调接口时,触发此处代码,并 传回进度
//拿到进度值,更新进度条
publishProgress(progress); //该方法将触发 onProgressUpdate(Integer..values);方法
}
});
}
(4)取消异步任务
(1)调用task.cancel(true);//true表示暴力取消,false温柔取消
(2)温柔取消时系统会自动执行onCancelled()方法
protected void onCancelled() {
if(isCancelled()){
Toast.makeText(MainActivity.this, "任务被取消!", Toast.LENGTH_LONG).show();
}
}
四.ListView的总结
(1)主要属性:
android:divider = "#rgb" Item之间的分割线的颜色,也可以是一张图片
android:dividerHeight = "1dp" Item之间的距离,通常为1dp
android:entries="@array/name" 用数组填充Item
(2)填充方式:
<1>属性填充:
step1:先在strings.xml中定义数组
step2:在listView中添加entries属性
android:entries="@array/citys"
<2>在Activity中通过适配器填充
①ArrayAdapter填充,适用于Item中只有一个文本 数据源为:List
②SimpleAdapter填充,可以实现图文混排的效果,但图片必须是本地的(不能是从网络获取的) 数据源为:List
③自定义Adapter,创建自己的Adapter类继承BaseAdapter抽象类,实现抽象方法 数据源为:List
Step1:定义一个类继承BaseAdapter
Step2:实现四个抽象方法
getCount()得到数据源的总长度
getItem(int position)得到下标对应的Item
getItemId(int position)得到下标对应的Item的Id
getView(int position,View convertView,ViewGrioup parent)
step3:在getView方法中为每个Item配置布局和数据
(3)ListView的事件监听器
①Item单击响应事件
OnItemClickListener
②Item长按响应事件
OnItemLongClickListener
③ListView滚动事件
listview.setOnScrollListener(new OnScroolListener()){
//该方法监听listView滚动状态的改变
//AbsListView ----- listView
//int scrollState----滚动的状态
//三种滚动状态对应三个状态码
//OnScrollListener.SCROLL_STATE_TOUCH_SCROLL------1 listView正 在滑动且手指还在屏幕上
//OnScrollListener.SCROLL_STATE_FLING --------2 listView惯性滑动
//OnScrollListener.SCROLL_STATE_IDLE --------0 listView停止滑动
public void onScrollStateChanged(AbsListView view,int scrollState){
}
//该方法监听listView滚动的方法
//AbslistView view------listView
//int firstVisibleItem ------当前屏幕最上方显示的Item的下标
//int visibleItemCount ------当前屏幕显示Item的个数,半个也算
//int totalItemCount -------当前所有Item的总数
public void onScroll(AbsListView view,int firstVisibleItem,
int visibleItemCount,int totalItemCount){
//小技巧:判断是否滑动到最底部
Boolean islast = (firstVisible+visibleItemCount==totalItemCount);
}
}
(4)ListView 的优化
①属性优化:
android:layout_width="match_parent"
android:layout_height="match_parent"
如果是wrap_content,加载时每条Item会执行多次来计算ListView的宽高
②重用convertView对象,将Item布局缓存起来从而复用
③定义ViewHolder类,减少findViewById的次数
参考代码:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = View.inflate(context, R.layout.item_listview, null);
holder.textViewName = (TextView) convertView.findViewById(R.id.name);
holder.textViewDescription = (TextView) convertView.findViewById(R.id.description);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.textViewName.setText(list.get(position).getName());
holder.textViewDescription.setText(list.get(position).getDescription());
return convertView;
}
(5)ListView加载网络图片,实现图文混排
通常图片地址在Json数据中或者XML文件中.(以json为例)
<1>通过网络加载json数据,然后解析封装成类
<2>在ListView的Adapter中构建Item时,
如果是文本内容则直接设置,如果为图片内容则开启异步任务去网络中加载
<3>对加载好的图片进行缓存,当第二次需要展示的时候,直接在内存中加载而不用访问网络
此处用Map来缓存(只是模拟),其他缓存方式后续更新
<4>由于convertView的复用,和异步任务形成的时间差,会造成图片错位现象
通过为ImageView打标签可以解决图片错位的问题
代码:
Map
ViewHolder holder;
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
holder = new ViewHolder();
convertView = View.inflate(context, R.layout.item_listview, null);
holder.imageView = (ImageView) convertView.findViewById(R.id.image);
holder.textViewName = (TextView) convertView
.findViewById(R.id.name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.imageView.setImageResource(R.drawable.ic_launcher);//用于清空被 重用的holder中携带的图片内容
String curImageUrl = list.get(position).getCoverUrl();
holder.imageView.setTag(curImageUrl);//为ImageView打标签,用此 imageView要显示图片的地址最为标签
if (!map.containsKey(curImageUrl)) {//判断Map中是否存有该地址(图片资源)
//如果Map中没有缓存,说明是第一次加载此图片,需要从网络获取
new ImageAsyncTask(new CallBack() {//开启异步任务加载图片
@Override
public void callBack(String path, Bitmap bitmap) {
//通过回调方法返回加载图片资源和其地址
//将加载好的图片资源和地址存入Map进行缓存
map.put(path, bitmap);
ImageView imageView = (ImageView) listView.findViewWithTag(path);
//通过标签在ListView中找到对应的imageView,并为其 设置图片资源
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}).execute(curImageUrl);
} else {
//如果Map中缓存的有需要的图片,则直接拿过来使用
holder.imageView.setImageBitmap(map.get(curImageUrl));
}
holder.textViewName.setText(list.get(position).getName());
return convertView;
}
class ViewHolder {
ImageView imageView;
TextView textViewName;
}