admin管理员组

文章数量:1531754

转载请注明本文出自Cym的博客(http://blog.csdn/cym492224103),谢谢支持!


前言

最近才开的博客,希望大家多多关注,andorid开发也做了3年有余了,也面试多家企业,借此机会分享一下,我们中遇到过的问题以及解决方案吧,希望能够对正在找工作的andoird程序员有一定的帮助。学完本人博客发表《ym--andorid从零开始教程》+面试题目全理解,年薪18w以上绝对没问题。

特别献上整理过的50道面试题目

1.listView的优化方式

重用convertView
viewHolder
static class viewHolder
在列表里面有图片的情况下,监听滑动不加载图片
多个不同布局,可以创建不同的viewHolder和convertView进行重用
2.listView展示数据几种形式

从sqlite拉取数据源显示
从xml使用pull解析拉取数据源显示
从网络上拉取数据源显示
3.ipc

进程间通信主要包括管道, 系统IPC(Inter-Process Communication,进程间通信)(包括消息队列,信号,共享存储), 套接字(SOCKET).
目的:
l 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。
l 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
l 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。
l 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
进程通过与内核及其它进程之间的互相通信来协调它们的行为。Linux支持多种进程间通信(IPC)机制,信号和管道是其中的两种。除此之外,Linux还支持System V 的IPC机制(用首次出现的Unix版本命名)。 

4. Parcel 的机制

Android中的Parcel机制
    实现了Bundle传递对象
    使用Bundle传递对象,首先要将其序列化,但是,在Android中要使用这种传递对象的方式需要用到Android Parcel机制,即,Android实现的轻量级的高效的对象序列化和反序列化机制。

    JAVA中的Serialize机制,译成串行化、序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象。主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。
    
    Android中的新的序列化机制
        在Android系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中采用了新的IPC(进程间通信)机制,必然要求使用性能更出色的对象传输方式。在这样的环境下,
        Parcel被设计出来,其定位就是轻量级的高效的对象序列化和反序列化机制。
        Android中序列化有以下几个特征:
        1. 整个读写全是在内存中进行,所以效率比JAVA序列化中使用外部存储器会高很多;
        2. 读写时是4字节对齐的
        3. 如果预分配的空间不够时,会一次多分配50%;
        4. 对于普通数据,使用的是mData内存地址,对于IBinder类型的数据以及FileDescriptor使用的是mObjects内存地址。后者是通过flatten_binder()和unflatten_binder()实现的,目的是反序列化时读出的对象就是原对象而不用重新new一个新对象。

代码:
activity代码:
 Intent mIntent =newIntent(this,ParcelableDemo.class);   
        Bundle mBundle =newBundle();   
        mBundle.putParcelable(PAR_KEY, mPolice);   
        mIntent.putExtras(mBundle);   

实体类:
public class Police implements Parcelable {
       
    private String name;
    private int workTime;
   
    public String getName() {
        returnname;
    }
   
    public void setName(String name) {
        this.name = name;
    }
   
    public int getWorkTime() {
        returnworkTime;
    }
   
    public void setWorkTime(int workTime) {
        this.workTime = workTime;
    }
       
    public static final Parcelable.Creator<Police> CREATOR =newCreator<Police>() {
   
        @Override
        public Police createFromParcel(Parcel source) {
            Police police =newPolice();
            police.name = source.readString();
            police.workTime = source.readInt();
            returnpolice;
        }
   
        @Override
        public Police[] newArray(int size) {
            returnnewPolice[size];
        }
    };
   
    @Override
    public int describeContents() {
        return0;
    }
   
    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(name);
        parcel.writeInt(workTime);
    }
}
5.JNI调用

(1) Eclipse中新建android工程 
工程名 JNItest 
Package名com.ura.test 
Activity名 JNItest 
应用程序名 JNItest 
(2) 编辑main.xml 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:androfont-family:Helvetica; font-size:14px; color:#42eee">http://schemas.android/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView 
    android:
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/JNITest"
    />
</LinearLayout>
 (3)编辑java文件 
package com.ura.test;
 

 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.TextView;
 public class JNITest extends Activity {
     /** Called when the activity is first created. */
    static {
             System.loadLibrary("JNITest");
    }
    public native String GetTest();
          @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
         String str =GetTest();
         TextView JNITest = (TextView)findViewById(R.id.JNITest);
         JNITest.setText(str);
     }
 }
 (4)生成head文件 
编译上面工程声称class文件,然后用javah工具生成c/c++ 头文件 
javah -classpath bin -d jni com.ura.test.JNItest
生成的头文件如下 
/* DO NOT EDIT THIS FILE - it is machine generated */
 #include <jni.h>
 /* Header for class com_ura_test_JNITest */
 

 #ifndef _Included_com_ura_test_JNITest
 #define _Included_com_ura_test_JNITest
 #ifdef __cplusplus
 extern "C" {
 #endif
 /*
 * Class:     com_ura_test_JNITest
 * Method:    GetTest
 * Signature: ()Ljava/lang/String;
 */
 JNIEXPORT jstring JNICALL Java_com_ura_test_JNITest_GetTest
   (JNIEnv *, jobject);
 

 #ifdef __cplusplus
 }
 #endif
 #endif
 (5)编写c/c++文件如下 
include "com_ura_test_JNITest.h"

#define LOG_TAG "JNITest"
#undef LOG
#include <utils/Log.h>

 JNIEXPORT jstring JNICALL Java_com_ura_test_JNITest_GetTest
   (JNIEnv * env, jobject obj)
 {
     return (*env)->NewStringUTF(env, (char *)"JNITest Native String");
     LOGD("Hello LIB!\n");
 

 }
(6)编写android.mk文件 
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
    com_ura_test_JNITest.c
LOCAL_C_INCLUDES := \
    $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libJNITest
include $(BUILD_SHARED_LIBRARY) 
(7)编译生成动态库 
新建文件夹 
~/mydroid/external/libJNITest 
把上面编写好的头文件,c/c++源文件,make文件拷贝进上面目录中 
* 需要注意的是把PRELINK_MOUDULE设置成false 
否则需要重新做成img文件再烧入。 
在 ubuntu中执行 
cd
cd mydroid/build/
envsetup.sh
cd ~/mydroid
cd external/libJNITest/
mm 
编译成功的后会在下面目录中生成libJNITest.so文件 
~mydroid/out/target/product/generic/system/lib/ 
(8)在模拟器中执行程序 
首先要把动态库拷进/system/lib中。 
启动模拟器 
adb shell
adb remount
adb push libJNITest.so /system/lib 
确认拷贝成功
 cd /system/lib
 ls
然后不要关闭模拟器(关掉再开动态库就没了,因为模拟器rom是只读) 
执行java程序JNITest 
会看到屏幕上打印出 
JNITest Native String 
6.细谈四大组件

     activity

     1.什么是activity?

四大组件之一,一般的,一个用户交互界面对应一个activity
setContentView() ,// 要显示的布局
button.setOnclickLinstener{
}
, activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件.
 
里面不能进行耗时操作
 
我开发常用的的有ListActivity  , PreferenceActivity ,TabAcitivty等…
 
如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity.
     2.activity生命周期?

Activity生命周期
1 完整生命周期
  onCreate()  
  --> onStart()
  --> onResume()
   可以在手机上看见activity
  ---> onPause()
  --> onStop()
   看不见了
  ---> onDestory()
   销毁了

2 前台生命周期
  onstart()  ---> onStop()之间进行切换
  onCreate() --> onStart() --> onResume()
   现在有一个activity完全覆盖
  onPause()  ----> onStop()
   如果上面的activity关闭
  onRestart() ---> onStart() --> onResume()
   
3 可视生命周期
   onResume()  ---> onPause()之间进行切换
  onCreate() --> onStart() --> onResume()
   现在有一个activity没有完全覆盖
  onPause()
   如果上面的activity关闭
  onResume() 

     3.横竖屏切换时候activity的生命周期?

 这个生命周期跟清单文件里的配置有关系
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期
默认首先销毁当前activity,然后重新加载
 
2、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
 
游戏开发中, 屏幕的朝向都是写死的.
    
      4.如何将一个activity设置成窗口的样式?
 可以自定义一个activity的样式,详细见手机卫士的程序详细信息
android:theme="@style/FloatActivity" 
E:\day9\mobilesafe\res\values\style
 

     5.activity启动模式?
Activity启动模式任务堆栈
Activity中的任务是与用户交互的一组Activity的集合,Activity会被按打开顺序安排在一个堆栈里。
任务栈:并不是Activity是Activity的引用(内存地址) 
standard 标准模式
每次激活Activity时都会创建Activity,并放入任务栈中
默认模式
  singleTop 独享堆栈顶端
如果在任务的栈顶正好存在该Activity的实例,就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)
浏览器的书签
  singleTask 独享任务堆栈
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中
浏览器的主页
  singleInstance单例
在一个新栈中创建该Activity实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity的实例存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中
通话界面
Singletop:如果重复使用上一次的Activity,就重用。
singleTask:如果使用已经实例化Activity,就重用,并且删除重用Activity前面的Activity,重用的Activity置顶任务栈。
singleInstance:在一个新栈中创建该Activity实例,并让多个应用共享该栈中的该Activity实例。(调用Activity和重用Activity不在一个栈中)
singleTop 、singleTask 、singleInstance 优化性能、重用Activity
     6.后台activity被系统回收了怎么办?如果后台activity由于某种原因被系统回收了,如何保存之前状态?
除了在栈顶的activity,其他的activity都有可能在内存不足的时候被系统回收,一个activity越处于栈底,被回收的可能性越大.
protected void onSaveInstanceState(Bundle outState) {
       super.onSaveInstanceState(outState);
       outState.putLong("id", 1234567890);
}
public void onCreate(Bundle savedInstanceState) {
//判断savedInstanceState是不是空.
//如果不为空就取出来
        super.onCreate(savedInstanceState);
}
     7.如何退出activity,如何安全退出已调用多个activity的application?
退出activity 直接调用 finish () 方法 . //用户点击back键 就是退出一个activity
退出activity 会执行 onDestroy()方法 .
1、抛异常强制退出:
该方法通过抛异常,使程序Force Close。
验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
 
       //安全结束进程        android.os.Process.killProcess(android.os.Process.myPid());
2、记录打开的Activity:
每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
 
                     List<Activity> lists ; 在application 全集的环境里面
              lists = new ArrayList<Activity>();
 
lists.add(activity);
 
for(Activity activity: lists)
{
       activity.finish();
}
 
3、发送特定广播:
在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
//给某个activity 注册接受接受广播的意图   
       registerReceiver(receiver, filter)
 
//如果过接受到的是 关闭activity的广播  就调用finish()方法 把当前的activity finish()掉
 
4、递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
 
 
上面是网上的一些做法.
 
其实 可以通过 intent的flag 来实现.. intent.setFlag(FLAG_ACTIVITY_CLEAR_TOP)激活一个新的activity,然后在新的activity的oncreate方法里面 finish掉.
     8.两activity之间怎么传递数据?
基本数据类型可以通过.  Intent 传递数据 
在A activity中
Intent intent = new Intent();
intent.putExtra(name, value) 
      Bundle bundle = new Bundle();
      bundle.putBoolean(key,value);
      intent.putExtras(bundle);
extras.putDouble(key, value)
// 通过intent putExtra 方法 基本数据类型 都传递
     
      Intent i = getIntent();
      i.getExtras();
 
intent.getStringExtra("key","value");
intent.getBooleanExtra("key","value")
      Bundle bundle = new  Bundle();
       bumdle.putShort(key, value);
       intent.putExtras(bumdle);
intent.putExtras(bundle)
--------------
Application 全局里面存放 对象 ,自己去实现自己的application的这个类,
基础系统的application , 每个activity都可以取到
-----------------
 
让对象实现 implements  Serializable 接口把对象存放到文件上. 
让类实现Serializable 接口,然后可以通过ObjectOutputStream              //对象输出流 
            File file = new File("c:\1.obj");
            FileOutputStream fos  = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
           
            Student stu = new Student();
            oos.writeObject(stu);
           
           
            //从文件中把对象读出来 
            ObjectInputStream ois = new ObjectInputStream(arg0);
             Student stu1 = (Student) ois.readObject();
 
文件/网络
 
intent.setData(Uri)
Uri.fromFile();  //大图片的传递

     9.讲一讲对activity的理解?
把上面的几点用自己的心得写出来
     
     service

     1.什么是Service以及描述下它的生命周期。Service有哪些启动方法,有什么区别,怎样停用Service?
在Service的生命周期中,被回调的方法比Activity少一些,只有onCreate, onStart, onDestroy,
onBind和onUnbind。
通常有两种方式启动一个Service,他们对Service生命周期的影响是不一样的。
1 通过startService
    Service会经历 onCreate 到onStart,然后处于运行状态,stopService的时候调用onDestroy方法。
   如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。
  2 通过bindService  
    Service会运行onCreate,然后是调用onBind, 这个时候调用者和Service绑定在一起。调用者退出了,Srevice就会调用onUnbind->onDestroyed方法。
   所谓绑定在一起就共存亡了。调用者也可以通过调用unbindService方法来停止服务,这时候Srevice就会调用onUnbind->onDestroyed方法。
需要注意的是如果这几个方法交织在一起的话,会出现什么情况呢?
一个原则是Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又bindService,Service只被创建一次。
如果先是bind了,那么start的时候就直接运行Service的onStart方法,
 
如果先是start,那么bind的时候就直接运行onBind方法。
 
如果service运行期间调用了bindService,这时候再调用stopService的话,service是不会调用onDestroy方法的,service就stop不掉了,只能调用UnbindService, service就会被销毁
 
 
如果一个service通过startService 被start之后,多次调用startService 的话,service会多次调用onStart方法。多次调用stopService的话,service只会调用一次onDestroyed方法。
 
 
如果一个service通过bindService被start之后,多次调用bindService的话,service只会调用一次onBind方法。
 
多次调用unbindService的话会抛出异常。

     2.service是否在main thread中执行, service里面是否能执行耗时的操作?
默认情况,如果没有显示的指定service所运行的进程, Service和activity是运行在当前app所在进程的main thread(UI主线程)里面 
service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )
在子线程中执行 new Thread(){}.start();
 
特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让service在另外的进程中执行

     3.怎么让在启动一个Activity是就启动一个service?
在activity的onCreate()方法里面 startService();

     4.Activity怎么和service绑定,怎么在activity中启动自己对应的service?
startService() 一旦被创建  调用着无关   没法使用service里面的方法
bindService () 把service 与调用者绑定 ,如果调用者被销毁, service会销毁
bindService() 我们可以使用service 里面的方法
       bindService().  让activity能够访问到 service里面的方法
       构建一个intent对象,
Intent service = new Intent(this,MyService.class);
 通过bindService的方法去启动一个服务,
    bindService(intent, new MyConn(), BIND_AUTO_CREATE);
       ServiceConnection 对象(重写onServiceConnected和OnServiceDisconnected方法) 和BIND_AUTO_CREATE.
       private class myconn implements ServiceConnection
 
       {
 
              public void onServiceConnected(ComponentName name, IBinder service) {
                     // TODO Auto-generated method stub
                     //可以通过IBinder的对象 去使用service里面的方法
              }
 
              public void onServiceDisconnected(ComponentName name) {
                     // TODO Auto-generated method stub
                    
              }
             
       }

     5.不用service,B页面为音乐播放,从A跳转到B,再返回,如何使音乐继续播放?
 这个问题问的很山寨.默认不做任何处理,B里面的音乐都能播放.
遇到问题, 可以随机应变,灵活发挥,多考虑些细节,比如说这个题就可以这样说,说说你对startActivityForResult的理解()
B的结束的时候 setResult()
 
A会调用到onActivityResult()
就会获取到resultCode 
A开启B的时候,用startActivityForResult()方法, B返回的时候把播放的状态信息返回给A ,A继续播放音乐.
seekTo(resultCode)
     6.什么是IntentService?有何优点?
普通的service ,默认运行在ui main 主线程
    Sdk给我们提供的方便的,带有异步处理的service类,
       可以在OnHandleIntent() 处理耗时的操作

     7.什么时候使用Service?
后台操作,耗时操作的时候
 
       拥有service的进程具有较高的优先级
    官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。
1. 如果service正在调用onCreate,  onStartCommand或者onDestory方法,那么用于当前service的进程相当于前台进程以避免被killed。
2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
3. 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
4. 如果service可以使用startForeg round(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
       1.Service的特点可以让他在后台一直运行,可以在service里面创建线程去完成耗时的操作.
new Thread(){
TimerTask // 循环的执行一个定时的任务
 
}.start();    
       2.Broadcast receiver捕获到一个事件之后,可以起一个service来完成一个耗时的操作.
ANR  new Service()
 
       3.远程的service如果被启动起来,可以被多次bind, 但不会重新create.  索爱手机X10i的人脸识别的service可以被图库使用,可以被摄像机,照相机等程序使用.
画廊 摄像机 照相机  bindService()  Ibinder的对象, 访问service

     8.如何在让Service杀不死?
Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,然后在onStartCommand方法中做一些处理。
从Android官方文档中,我们知道onStartCommand有4种int返回值,首先简单地讲讲int返回值的作用。
一、onStartCommand有4种返回值:
START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
 
二、创建不被杀死的service
1.在service中重写下面的方法,这个方法有三个返回值, START_STICKY(或START_STICKY_COMPATIBILITY)是service被kill掉后自动重写创建
@Override  public int onStartCommand(Intent intent, int flags, int startId)  {   return START_STICKY_COMPATIBILITY;    //return super.onStartCommand(intent, flags, startId);  }

 @Override  public int onStartCommand(Intent intent, int flags, int startId)  {   flags = START_STICKY;   return super.onStartCommand(intent, flags, startId);   // return START_REDELIVER_INTENT;  }
@Override public void onStart(Intent intent, int startId) { // 再次动态注册广播 IntentFilter localIntentFilter = new IntentFilter("android.intent.action.USER_PRESENT"); localIntentFilter.setPriority(Integer.MAX_VALUE);// 整形最大值 myReceiver searchReceiver = new myReceiver(); registerReceiver(searchReceiver, localIntentFilter); super.onStart(intent, startId); }
2.在Service的onDestroy()中重启Service.
 public void onDestroy()  {   Intent localIntent = new Intent();   localIntent.setClass(this, MyService.class); // 销毁时重新启动Service   this.startService(localIntent);  }
3.创建一个广播
public class myReceiver extends BroadcastReceiver {  @Override  public void onReceive(Context context, Intent intent)  {   context.startService(new Intent(context, Google.class));  } }
4.AndroidManifest.xml中注册广播myReceiver及MyService服务
<receiver android:name=".myReceiver" >             <intent-filter android:priority="2147483647" ><!--优先级加最高-->                 <!-- 系统启动完成后会调用 -->                 <action android:name="android.intent.action.BOOT_COMPLETED" />                                <!-- 解锁完成后会调用 -->                 <action android:name="android.intent.action.USER_PRESENT" />                 <!-- 监听情景切换 -->                 <action android:name="android.media.RINGER_MODE_CHANGED" />                            </intent-filter> </receiver>
<service android:name=".MyService" >
注:解锁,启动,切换场景激活广播需加权限,如启动完成,及手机机状态等。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
 亲测ZTE U795手机Android 4.0.4版本adb push到system\app下android:persistent="true" 变成核心程序,在360杀掉进程的时候,myReceiver照样有效,保证service重生。呃
KILL问题: 1. settings 中stop service onDestroy方法中,调用startService进行Service的重启。 2.settings中force stop 应用 捕捉系统进行广播(action为android.intent.action.PACKAGE_RESTARTED) 3. 借助第三方应用kill掉running task 提升service的优先级,程序签名,或adb push到system\app下等
相较于/data/app下的应用,放在/system/app下的应用享受更多的特权,比如若在其Manifest.xml文件中设置persistent属性为true,则可使其免受out-of-memory killer的影响。如应用程序'Phone'的AndroidManifest.xml文件:
    <application android:name="PhoneApp"
                 android:persistent="true"
                 android:label="@string/dialerIconLabel"
                 android:icon="@drawable/ic_launcher_phone">
         ...
    </application>
设置后app提升为系统核心级别
     Broadcast Receiver

     1.什么是Broadcast Receiver

下面是Android Doc中关于BroadcastReceiver的概述:①广播接收器是一个专注于接收广播通知信息,并做出对应处理的组件。很多广播是源自于系统代码的──比如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以进行广播──比如说,通知其它应用程序一些数据下载完成并处于可用状态。
②应用程序可以拥有任意数量的广播接收器以对所有它感兴趣的通知信息予以响应。所有的接收器均继承自BroadcastReceiver基类。
③广播接收器没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

有很多广播接收者 ,系统已经实现了.
广播分两种 有序广播
无序广播
 指定接收者的有序广播 .
 sendOrderedBroadcast(intent,receiverPermission,resultReceiver,scheduler,initialCode,initialData,initialExtras)
   接受者一定会获取到 广播的事件 
 
sendStickyBroadcast(intent)  //阴魂不散
广播接受者在onReceive 方法获取到广播的事件
 
Wifi设置  等待wifi状态更新完毕
 
  是不可以被拦截掉的 
<intent-filter android:priority="1000"> -1000 - 1000
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
 abortBroadcast();
 
 
代码配置优先级比xml配置优先级的级别高,因为代码运行在内存中,而清单在系统中
 
 手机卫士中自定义一个broadcast receiver
<intent-filter  android:> <action> sms_received </action>  </intent-filter>
 
来获取短信到来的广播, 根据黑名单来判断是否拦截该短信.
 画画板生成图片后,发送一个sd挂载的通知,通知系统的gallery去获取到新的图片.
Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file://"+Environment.getExternalStorageDirectory()));
                        sendBroadcast(intent);

     2.什么时候使用Broadcast Receiver
用于接收系统的广播通知, 系统会有很多sd卡挂载,手机重启,广播通知,低电量,来电,来短信等….

     3.如何使用Broadcast Receiver
设置广播接收者的优先级,设置广播接受者的action名字 等…
详细见工程代码.
         <intent-filter android:priority="1000">
                 <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>        
         </intent-filter>
        </receiver>
              <receiver android:name=".SmsReceiver">
                     <intent-filter android:priority="1000">
                            <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
                     </intent-filter>
              </receiver>
              <receiver android:name=".BootCompleteReceiver">
                     <intent-filter >
                            <action android:name="android.intent.action.BOOT_COMPLETED"      />           
                            </intent-filter>
              </receiver>
 
可以通过代码   registerReceiver(receiver,filter)
     ContentProvider

     1.什么是ContentProvider
ContentProvider内容提供者
ContentProvider 进程间通讯,进程间数据的访问/对外共享数据用
优点:提供了统一的访问方式
原理分析图


     2.什么时候使用ContentProvider
需要访问别人的数据的时候

     3.如何使用ContentProvider
1.先是提供的数据类型等数据的类。package org.juetion.cp;

import android.Uri;
import android.provider.BaseColumns;

/**
 * 提供的数据类型等数据。
 * Created by juetionke on 13-12-21.
 */
public class MyProviderMetaData {


    public static final String AUTHORIY = "org.juetion.cp.MyContentProvider";
    /**
     * 数据库名称
     */
    public static final String DATABASE_NAME = "MyProvider.db";
    /**
     * 数据库版本
     */
    public static final int DATABASE_VERSION = 1;
    /**
     * 表名
     */
    public static final String USERS_TABLE_NAME = "users";

    /**
     * 继承了BaseColumns,所以已经有了_ID
     */
    public static final class UserTableMetaData implements BaseColumns {
        /**
         * 表名
         */
        public static final String TABLE_NAME = "users";
        /**
         * 访问该ContentProvider的URI
         */
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORIY + "/users");
        /**
         * 该ContentProvider所返回的数据类型定义
         */
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/org.juetion.user";
        public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/org.juetion.user";
        /**
         * 列名
         */
        public static final String USER_NAME = "name";
        public static final String USER_AGE = "age";
        /**
         * 默认的排序方法
         */
        public static final String DEFAULT_SORT_ORDER = "_id desc";
    }
}
2,继承ContentProvider的类:
package org.juetion.cp;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.Uri;
import android.text.TextUtils;
import android.util.Log;

import org.juetion.sqlite3.DatabaseHelper;

import java.util.HashMap;

/**
 * Created by juetionke on 13-12-21.
 */
public class MyContentProvider extends ContentProvider {

    /**
     * 定义规则
     */
    public static final UriMatcher uriMatcher;
    public static final int USERS_COLLECTION = 1;//用于标记
    public static final int USERS_SINGLE = 2;//用于标记
    private DatabaseHelper databaseHelper;//这里的数据共享是共享Sqlite里的数据,当然,可以试用其他,如文本数据共享。
    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);//试用一个没有规则的Uri。然后下面自己匹配。
        uriMatcher.addURI(MyProviderMetaData.AUTHORIY,"/users",USERS_COLLECTION);//自己定义的规则,有点像路由器,是uri匹配的方案。
        uriMatcher.addURI(MyProviderMetaData.AUTHORIY,"/users/#",USERS_SINGLE);//同上。
    }

    /**
     * 为列定义别名
     */
    public static HashMap<String,String> usersMap;
    static {
        usersMap = new HashMap<String, String>();
        usersMap.put(MyProviderMetaData.UserTableMetaData._ID, MyProviderMetaData.UserTableMetaData._ID);
        usersMap.put(MyProviderMetaData.UserTableMetaData.USER_NAME, MyProviderMetaData.UserTableMetaData.USER_NAME);
        usersMap.put(MyProviderMetaData.UserTableMetaData.USER_AGE, MyProviderMetaData.UserTableMetaData.USER_AGE);
    }


    @Override
    public boolean onCreate() {
        Log.i("juetion","onCreate");
        databaseHelper = new DatabaseHelper(getContext(), MyProviderMetaData.DATABASE_NAME);//这里的实现,常见前篇关于Sqlite的文章。
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Log.i("juetion","query");
        SQLiteQueryBuilder sqLiteQueryBuilder = new SQLiteQueryBuilder();//写入查询条件,有点像Hibernate。
        switch (uriMatcher.match(uri)) {//判断查询的是单个数据还是多个数据。
            case USERS_SINGLE:
                sqLiteQueryBuilder.setTables(MyProviderMetaData.UserTableMetaData.TABLE_NAME);//需要查询的表
                sqLiteQueryBuilder.setProjectionMap(usersMap);//列的别名定义
                sqLiteQueryBuilder.appendWhere(MyProviderMetaData.UserTableMetaData._ID + "=" + uri.getPathSegments().get(1));
                //查询条件,uri.getPathSegments().get(1),getPathSegments是将内容根据/划分成list。
                break;
            case USERS_COLLECTION:
                sqLiteQueryBuilder.setTables(MyProviderMetaData.UserTableMetaData.TABLE_NAME);
                sqLiteQueryBuilder.setProjectionMap(usersMap);
                break;
        }
        String orderBy;//判断sortOrder是否为空,加入默认。
        if (TextUtils.isEmpty(sortOrder)) {
            orderBy = MyProviderMetaData.UserTableMetaData.DEFAULT_SORT_ORDER;
        } else {
            orderBy = sortOrder;
        }
        SQLiteDatabase sqLiteDatabase = databaseHelper.getWritableDatabase();
        Cursor cursor = sqLiteQueryBuilder.query(sqLiteDatabase, projection, selection, selectionArgs, null, null, sortOrder);//可以使用下面的方法,不过此时sqLiteDatabase将会没有用。
        //Cursor cursor = sqLiteDatabase.query(MyProviderMetaData.UserTableMetaData.TABLE_NAME, projection, selection, selectionArgs, null, null, orderBy);
        cursor.setNotificationUri(getContext().getContentResolver(),uri);
        return cursor;
    }

    /**
     * 根据传入的URI,返回URI说表示的数据类型
     * @param uri
     * @return
     */
    @Override
    public String getType(Uri uri) {
        Log.i("juetion","getType");
        switch (uriMatcher.match(uri)) {//匹配uri的规则
            case USERS_COLLECTION:
                return MyProviderMetaData.UserTableMetaData.CONTENT_TYPE;
            case USERS_SINGLE:
                return MyProviderMetaData.UserTableMetaData.CONTENT_TYPE_ITEM;
            default:
                throw new IllegalArgumentException("Unknown URI" + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Log.i("juetion","insert");
        SQLiteDatabase sqLiteDatabase = databaseHelper.getWritableDatabase();
        long rowId = sqLiteDatabase.insert(MyProviderMetaData.UserTableMetaData.TABLE_NAME, null, values);
        if (rowId > 0) {
            Uri insertUserUri = ContentUris.withAppendedId(MyProviderMetaData.UserTableMetaData.CONTENT_URI, rowId);//简单来说就是字符串拼凑一下。只不过是uri专用的。
            //通知监听器
            getContext().getContentResolver().notifyChange(insertUserUri,null);
            return insertUserUri;
        }else
            throw new IllegalArgumentException("Failed to insert row into" + uri);
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        Log.i("juetion","delete");
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        Log.i("juetion","update");
        return 0;
    }
}
还有重要的一点,再第二个APP的AndroidManifest.xml里面需要添加
<!-- provider name填写ContentProvider那个类的全称,authorities填写MyProviderMetaData里的AUTHORIY -->
        <provider
            android:authorities="org.juetion.cp.MyContentProvider"
            android:name="org.juetion.cp.MyContentProvider”/>


以下代码是在第一个APP里面的。
关于使用。只需要将uri的string提供给第一个APP。
例如在第一个APP的Activity调用数据插入:
ContentValues contentValues = new ContentValues();
                    contentValues.put("name","zhangsan");
                    contentValues.put("age",19);
                    Uri uri = getContentResolver().insert(Uri.parse("content://org.juetion.cp.MyContentProvider/users"),contentValues);
                    Log.i("juetion", "insert uri-->" + uri.toString()); 

例如在第一个APP的Activity调用数据的查询:
Cursor cursor = getContentResolver().query(Uri.parse("content://org.juetion.cp.MyContentProvider/users"),
                            new String[]{"name", "age"},
                            null, null, null);
                    while (cursor.moveToNext()) {
                        Log.i("juetion", cursor.getString(cursor.getColumnIndex("name")));
                    }

     4.请介绍下 ContentProvider 是如何实现数据共享的。
ContentProvider 可以屏蔽数据操作的细节 文件 xml
MyContentProvider 可以在不同应用程序之间共享数据  sharedpreference db
       把自己的数据通过uri的形式共享出去
android  系统下 不同程序 数据默认是不能共享访问
      
       需要去实现一个类去继承ContentProvider
       public class PersonContentProvider extends ContentProvider{
       public boolean onCreate(){
              //..
       }
query(Uri, String[], String, String[], String)
insert(Uri, ContentValues)
update(Uri, ContentValues, String, String[])
delete(Uri, String, String[])
 
联系人的信息 sms的内容content://sms/
}
     安全共同点
android安全学习 
签名作用
1.sharedUserId 一样并且签名一次 可以实现数据共享
2.升级应用
权限:细粒度的特权管理
权限与操作关联
应用需要显式申请权限
用户对权限可知(不可控)
对特权权限单独控制
四大组件
exported = true 等于public
exported = false 等于private
默认组件private
如果该组件设置了intent-filter默认是public
如果同时希望是private,就需要主动设置expoted=false
Securing Activities
可知指定权限才能启动activity
service同上
BoradcastReceiver可以设置接发的权限
ContentPrivider 可设置读写Permission
7.多线程管理

本篇随笔将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信。
一、Android当中的多线程
在Android当中,当一个应用程序的组件启动的时候,并且没有其他的应用程序组件在运行时,Android系统就会为该应用程序组件开辟一个新的线程来执行。默认的情况下,在一个相同Android应用程序当中,其里面的组件都是运行在同一个线程里面的,这个线程我们称之为Main线程。当我们通过某个组件来启动另一个组件的时候,这个时候默认都是在同一个线程当中完成的。当然,我们可以自己来管理我们的Android应用的线程,我们可以根据我们自己的需要来给应用程序创建额外的线程。
二、Main Thread 和 Worker Thread
在Android当中,通常将线程分为两种,一种叫做Main Thread,除了Main Thread之外的线程都可称为Worker Thread。
当一个应用程序运行的时候,Android操作系统就会给该应用程序启动一个线程,这个线程就是我们的Main Thread,这个线程非常的重要,它主要用来加载我们的UI界面,完成系统和我们用户之间的交互,并将交互后的结果又展示给我们用户,所以Main Thread又被称为UI Thread。
Android系统默认不会给我们的应用程序组件创建一个额外的线程,所有的这些组件默认都是在同一个线程中运行。然而,某些时候当我们的应用程序需要完成一个耗时的操作的时候,例如访问网络或者是对数据库进行查询时,此时我们的UI Thread就会被阻塞。例如,当我们点击一个Button,然后希望其从网络中获取一些数据,如果此操作在UI Thread当中完成的话,当我们点击Button的时候,UI线程就会处于阻塞的状态,此时,我们的系统不会调度任何其它的事件,更糟糕的是,当我们的整个现场如果阻塞时间超过5秒钟(官方是这样说的),这个时候就会出现 ANR (Application Not Responding)的现象,此时,应用程序会弹出一个框,让用户选择是否退出该程序。对于Android开发来说,出现ANR的现象是绝对不能被允许的。
另外,由于我们的Android UI控件是线程不安全的,所以我们不能在UI Thread之外的线程当中对我们的UI控件进行操作。因此在Android的多线程编程当中,我们有两条非常重要的原则必须要遵守:
绝对不能在UI Thread当中进行耗时的操作,不能阻塞我们的UI Thread
不能在UI Thread之外的线程当中操纵我们的UI元素
 三、如何处理UI Thread 和 Worker Thread之间的通信
既然在Android当中有两条重要的原则要遵守,那么我们可能就有疑问了?我们既不能在主线程当中处理耗时的操作,又不能在工作线程中来访问我们的UI控件,那么我们比如从网络中要下载一张图片,又怎么能将其更新到UI控件上呢?这就关系到了我们的主线程和工作线程之间的通信问题了。在Android当中,提供了两种方式来解决线程直接的通信问题,一种是通过Handler的机制(这种方式在后面的随笔中将详细介绍),还有一种就是今天要详细讲解的 AsyncTask 机制。
四、AsyncTask
AsyncTask:异步任务,从字面上来说,就是在我们的UI主线程运行的时候,异步的完成一些操作。AsyncTask允许我们的执行一个异步的任务在后台。我们可以将耗时的操作放在异步任务当中来执行,并随时将任务执行的结果返回给我们的UI线程来更新我们的UI控件。通过AsyncTask我们可以轻松的解决多线程之间的通信问题。
怎么来理解AsyncTask呢?通俗一点来说,AsyncTask就相当于Android给我们提供了一个多线程编程的一个框架,其介于Thread和Handler之间,我们如果要定义一个AsyncTask,就需要定义一个类来继承AsyncTask这个抽象类,并实现其唯一的一个 doInBackgroud 抽象方法。要掌握AsyncTask,我们就必须要一个概念,总结起来就是: 3个泛型,4个步骤。
3个泛型指的是什么呢?我们来看看AsyncTask这个抽象类的定义,当我们定义一个类来继承AsyncTask这个类的时候,我们需要为其指定3个泛型参数:
AsyncTask <Params, Progress, Result>
Params: 这个泛型指定的是我们传递给异步任务执行时的参数的类型
Progress: 这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
Result: 这个泛型指定的异步任务执行完后返回给UI线程的结果的类型
 我们在定义一个类继承AsyncTask类的时候,必须要指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void,例如:
AsyncTask <Void, Void, Void>
4个步骤:当我们执行一个异步任务的时候,其需要按照下面的4个步骤分别执行
onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出要给ProgressDialog
doInBackground(Params... params): 在onPreExecute()方法执行完之后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行我们的这个方法,所以这个方法是在worker thread当中执行的,这个方法执行完之后就可以将我们的执行结果发送给我们的最后一个 onPostExecute 方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作
onProgressUpdate(Progess... values): 这个方法也是在UI Thread当中执行的,我们在异步任务执行的时候,有时候需要将执行的进度返回给我们的UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新我们的进度。这个方法在调用之前,我们需要在 doInBackground 方法中调用一个 publishProgress(Progress) 的方法来将我们的进度时时刻刻传递给 onProgressUpdate 方法来更新
onPostExecute(Result... result): 当我们的异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上
 为什么我们的AsyncTask抽象类只有一个 doInBackground 的抽象方法呢??原因是,我们如果要做一个异步任务,我们必须要为其开辟一个新的Thread,让其完成一些操作,而在完成这个异步任务时,我可能并不需要弹出要给ProgressDialog,我并不需要随时更新我的ProgressDialog的进度条,我也并不需要将结果更新给我们的UI界面,所以除了 doInBackground 方法之外的三个方法,都不是必须有的,因此我们必须要实现的方法是 doInBackground 方法。
五、通过AsyncTask来从网络上下载一张图片
下面我们就通过两个代码示例,来看看如何通过AsyncTask来从网络上下载一张图片,并更新到我们的ImageView控件上。
①下载图片时,弹出一个ProgressDialog,但是不显示实时进度
我们来看看布局文件:

<RelativeLayoutxmlns:android="http://schemas.android/apk/res/android"
    xmlns:tools="http://schemas.android/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"]]
>


    <ImageView
       android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="200dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:scaleType="fitCenter"/>

    <Button
       android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/imageView"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="41dp"
        android:text="从网络上下载一张图片"/>

</RelativeLayout]]
>


就是很简单的一个ImageView控件和一个Button控件,当点击Button控件时,弹出一个ProgressDialog,然后开启一个异步任务,从网络中下载一张图片,并更新到我们的ImageView上。这里还要注意一点,如果我们要使用手机访问网络,必须还要给其授权才行,在后续的学习当中,将会详细讲解Android当中的授权的知识。我们来看看
AndroidManifest.xml文件:

<?xml version="1.0" encoding="utf-8"?><manifestxmlns:android="http://schemas.android/apk/res/android"
    package="com.xiaoluo.android_asynctast"
    android:versionCode="1"
    android:versionName="1.0"]]
>


    <uses-sdk
       android:minSdkVersion="8"
        android:targetSdkVersion="18"/>
    
    <!-- 授权手机能够访问网络 -->
    <uses-permissionandroid:name="android.permission.INTERNET"/>
    
    <application
       android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"]]
>

        <activity
           android:name="com.xiaoluo.android_asynctast.MainActivity"
            android:label="@string/app_name"]]
>

            <intent-filter]]
>

               <actionandroid:name="android.intent.action.MAIN"/>

               <categoryandroid:name="android.intent.category.LAUNCHER"/>
            </intent-filter]]
>

        </activity]]
>

    </application]]
>


</manifest]]
>


接下来我们来看看我们的Activity代码:

publicclass MainActivityextends Activity
{
    private Button button;
    private ImageView imageView;
    private ProgressDialog progressDialog;
    privatefinal String IMAGE_PATH = "http://developer.android/images/home/kk-hero.jpg";
//    private final String IMAGE_PATH2 = "http://ww2.sinaimg/mw690/69c7e018jw1e6hd0vm3pej20fa0a674c.jpg";    @Override
    protectedvoid onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button = (Button)findViewById(R.id.button);
        imageView = (ImageView)findViewById(R.id.imageView);
        //    弹出要给ProgressDialog
        progressDialog =new ProgressDialog(MainActivity.this);
        progressDialog.setTitle("提示信息");
        progressDialog.setMessage("正在下载中,请稍后......");
        //    设置setCancelable(false); 表示我们不能取消这个弹出框,等下载完成之后再让弹出框消失
        progressDialog.setCancelable(false);
        //    设置ProgressDialog样式为圆圈的形式        progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        
        button.setOnClickListener(new View.OnClickListener()
        {
            @Override
            publicvoid onClick(View v)
            {         // 在UI Thread当中实例化AsyncTask对象,并调用execute方法
               new MyAsyncTask().execute(IMAGE_PATH);
            }
        });
    }
    
    /**
     * 定义一个类,让其继承AsyncTask这个类
     * Params: String类型,表示传递给异步任务的参数类型是String,通常指定的是URL路径
     * Progress: Integer类型,进度条的单位通常都是Integer类型
     * Result:byte[]类型,表示我们下载好的图片以字节数组返回
     *@author xiaoluo
     *
     */
    publicclass MyAsyncTaskextends AsyncTask<String, Integer,byte[]>
    {
        @Override
        protectedvoid onPreExecute()
        {
            super.onPreExecute();
            //    在onPreExecute()中我们让ProgressDialog显示出来            progressDialog.show();
        }
        @Override
        protectedbyte[] doInBackground(String... params)
        {
            //    通过Apache的HttpClient来访问请求网络中的一张图片
            HttpClient httpClient =new DefaultHttpClient();
            HttpGet httpGet =new HttpGet(params[0]);
            byte[] image =newbyte[]{};
            try
            {
                HttpResponse httpResponse = httpClient.execute(httpGet);
                HttpEntity httpEntity = httpResponse.getEntity();
               if(httpEntity !=null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
                {
                    image = EntityUtils.toByteArray(httpEntity);
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                httpClient.getConnectionManager().shutdown();
            }
            return image;
        }
        @Override
        protectedvoid onProgressUpdate(Integer... values)
        {
            super.onProgressUpdate(values);
        }
        @Override
        protectedvoid onPostExecute(byte[] result)
        {
            super.onPostExecute(result);
            //    将doInBackground方法返回的byte[]解码成要给Bitmap
            Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0, result.length);
            //    更新我们的ImageView控件            imageView.setImageBitmap(bitmap);
            //    使ProgressDialog框消失            progressDialog.dismiss();
        }
    }
    
    @Override
    publicboolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main, menu);
        returntrue;
    }

}

我们来看看效果图:
 
 
②带有进度条更新的下载一张网络图片
下面这个代码示例,将会在下载图片的时候,显示进度条的更新,配置文件都不变,我们来看看Activity代码:

publicclass MainActivityextends Activity
{
    private Button button;
    private ImageView imageView;
    private ProgressDialog progressDialog;
    privatefinal String IMAGE_PATH = "http://developer.android/images/home/kk-hero.jpg";
//    private final String IMAGE_PATH2 = "http://ww2.sinaimg/mw690/69c7e018jw1e6hd0vm3pej20fa0a674c.jpg";    @Override
    protectedvoid onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button = (Button)findViewById(R.id.button);
        imageView = (ImageView)findViewById(R.id.imageView);
        //    弹出要给ProgressDialog
        progressDialog =new ProgressDialog(MainActivity.this);
        progressDialog.setTitle("提示信息");
        progressDialog.setMessage("正在下载中,请稍后......");
        //    设置setCancelable(false); 表示我们不能取消这个弹出框,等下载完成之后再让弹出框消失
        progressDialog.setCancelable(false);
        //    设置ProgressDialog样式为水平的样式        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        
        button.setOnClickListener(new View.OnClickListener()
        {
            @Override
            publicvoid onClick(View v)
            {
               new

本文标签: 面试题ymAndorid