深入Android线程的相关问题解惑

所属分类: 软件编程 / Android 阅读数: 1327
收藏 0 赞 0 分享
一个应用只有一个线程
在默认情况下,更确切的讲一个进程中只有一个线程,这跟其他语言,比如C/C++,Java等是一致。也就是说在Android应用程序里面一个进程只有一个线程,所有组件都运行在一个线程里面!

当应用程序启动时,系统会为其创建一个进程,也会创建一个线程名字叫做main,所有其所属组件的创建,系统事件的处理,系统的回调等一切应用相关的事情都运行在此名叫main的线程中。此线程即为常说的主线程(main thread)。俗称的UI线程(UI thread)也是它,因为只有主线程可以操作UI相关的事情,所以有人把主线程也称作UI线程,但这并不是正确的说法,因为Service所属的线程也可以操作Toast,但是Service并没有UI。为什么非主线程不能操作UI呢?因为对UI操作常常会引发系统的回调,所以如果允许第三线程来操作可能会引发系统回调的紊乱,进而会打乱整个框架的时序!
这里要特别注意的就是同一个进程中的所有组件运行在同一个线程中,Activiy,Service,BoradcastReceiver和ContentProvider都运行在主线程中。

最容易引起误解的就是Service,文档和常识都会认为Service是放在后台用于操作费时运算的,但是实则不然,如果你在Service中做费时操作,同样会引发臭名昭著的ANR(Application Not Responding)。所以如果想把Service当做一个Server,必须在Service用HandlerThread或Thread创建一个Worker线程!
Activity也是一样的,你startActivity()后,开启了一个新的Activity,但它们都运行在同一个线程中,所以你还是不能在原Activity中做费时操作!也即在调用startActivity()开启了一个新的Activity后,或者在onPause(), onStop(), onDestroy()中做费时操作会引发ANR。

对于ContentProvider也是一样的,如果跟其他组件在同一进程内,那么调用ContentResolver的方法会相当于直接调用ContentProvider的方法。如果是在另外一个进程中,虽是通过IPC,但也是同步的,因为IBinder的同步的,也即调用ContentResolver时会把调用者的进程挂起,等待ContentProvider的进程操作结束,再把结果传给调用者进程!所以,如果ContentProvider中有费时操作,或者会同步锁数据库等,也一定要注意ANR的发生!
所以一定要记住:一个进程只有一个线程,所有组件都运行在主线程中。
因此,如果有费时操作,必须要创建Worker线程!

实例
下面有一个小实例,一个应用中有五个组件:2个Activity,一个Service,一个ContentProvider和一个BroadcastReceiver。在每个组件的方法中都有打印所属线程信息,另外对于Activity,Service和ContentProvider如果做费时操作会引发ANR,对于BroadcastReceiver更是如此,这个大家都懂得的!
复制代码 代码如下:

public class ActivityDemo extends Activity {
    private static final String TAG = "ActivityDemo";
    private Handler mMainHandler = new Handler(new Handler.Callback() {
 public boolean handleMessage(Message msg) {
     dumpThreadInfo();
     return false;
 }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
 dumpThreadInfo();
 super.onCreate(savedInstanceState);

 // add four buttons
 LinearLayout layout = new LinearLayout(getApplication());
 layout.setOrientation(LinearLayout.VERTICAL);
 Button startService = new Button(getApplication());
 startService.setText("Start a Service");
 startService.setOnClickListener(new View.OnClickListener() {
     public void onClick(View v) {
  Intent i = new Intent(getApplication(), ServiceDemo.class);
  startService(i);
     }
 });
 layout.addView(startService);
 Button startAnother = new Button(getApplication());
 startAnother.setText("Start another Activity");
 startAnother.setOnClickListener(new View.OnClickListener() {
     public void onClick(View v) {
  Intent i = new Intent(getApplication(), AnotherActivity.class);
  startService(i);
     }
 });
 layout.addView(startAnother);
 Button startContentProvider = new Button(getApplication());
 startContentProvider.setText("Start a ContentProvider");
 startContentProvider.setOnClickListener(new View.OnClickListener() {
     public void onClick(View v) {
  getContentResolver().query(ContentProviderDemo.CONTENT_URI, null, null, null, null);
     }
 });
 layout.addView(startContentProvider);
 Button startReceiver = new Button(getApplication());
 startReceiver.setText("Start a BroadcastReceiver");
 startReceiver.setOnClickListener(new View.OnClickListener() {
     public void onClick(View v) {
  Intent i = new Intent("android.action.start_broadcastreceiver_demo");
  sendBroadcast(i);
     }
 });
 layout.addView(startReceiver);
 setContentView(layout);

 mMainHandler.sendEmptyMessageDelayed(0, 500);
    }

    public void dumpThreadInfo() {
 Thread.dumpStack();
 Log.e(TAG, Thread.currentThread().toString());
 Log.e(TAG, " " + getMainLooper());
    }
}

复制代码 代码如下:

public class AnotherActivity extends Activity {
    private static final String TAG = "AnotherActivity";
    private Handler mMainHandler = new Handler(getMainLooper(), new Handler.Callback() {
        public boolean handleMessage(Message msg) {
            // this will cause ANR
            Log.e(TAG, "you know what this is very slow slow slow slow");
            SystemClock.sleep(20 * 1000);
            dumpThreadInfo();
            return false;
        }
    });
    @Override
    protected void onCreate(Bundle savedInstanceState) {
 dumpThreadInfo();
 super.onCreate(savedInstanceState);

 setTitle("this is another activity");
 mMainHandler.sendEmptyMessageDelayed(0, 500);
    }
    @Override
    protected void onDestroy() {
 dumpThreadInfo();
 super.onDestroy();
    }
    public void dumpThreadInfo() {
 Thread.dumpStack();
 Log.e(TAG, Thread.currentThread().toString());
 Log.e(TAG, " " + getMainLooper());
    }
}

复制代码 代码如下:

public class ServiceDemo extends Service {
    private Handler mMainHandler = new Handler(new Handler.Callback() {
        public boolean handleMessage(Message msg) {
            // this will cause ANR, too
            Log.e(TAG, "this is very slow you know, slow slow");
            SystemClock.sleep(20 * 1000);
            dumpThreadInfo();
            return false;
        }
    });
    private static final String TAG = "ServiceDemo";
    @Override
    public IBinder onBind(Intent arg0) {
 dumpThreadInfo();
 return null;
    }
    @Override
    public void onCreate() {
 dumpThreadInfo();
 super.onCreate();
 mMainHandler.sendEmptyMessageDelayed(0, 500);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
 dumpThreadInfo();
 return super.onStartCommand(intent, flags, startId);
    }

    public void dumpThreadInfo() {
 Thread.dumpStack();
 Log.e(TAG, Thread.currentThread().toString());
 Log.e(TAG, " " + getMainLooper());
    }
}

复制代码 代码如下:

public class ContentProviderDemo extends ContentProvider {
    public static final Uri CONTENT_URI = Uri.parse("content://com.hilton.effectiveandroid.app/content");
    private static final String TAG = "ContentProviderDemo";
    @Override
    public int delete(Uri arg0, String arg1, String[] arg2) {
 dumpThreadInfo();
 return 0;
    }
    @Override
    public Uri insert(Uri uri, ContentValues values) {
 dumpThreadInfo();
 return null;
    }
    @Override
    public boolean onCreate() {
 dumpThreadInfo();
 return false;
    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
 dumpThreadInfo();
 // it will cause ANR of course
 Log.e(TAG, "this is very slow, you know that");
 SystemClock.sleep(20 * 1000);
 return null;
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
 dumpThreadInfo();
 return 0;
    }

    public void dumpThreadInfo() {
 Thread.dumpStack();
 Log.e(TAG, Thread.currentThread().toString());
    }
    @Override
    public String getType(Uri arg0) {
 return null;
    }
}

复制代码 代码如下:

public class BroadcastReceiverDemo extends BroadcastReceiver {
    private static final String TAG = "BroadcastReceiverDemo";
    @Override
    public void onReceive(Context context, Intent intent) {
 Log.e(TAG, "intent is " + intent);
 dumpThreadInfo();
    }

    public void dumpThreadInfo() {
 Thread.dumpStack();
 Log.e(TAG, Thread.currentThread().toString());
    }
}

更多精彩内容其他人还在看

使用ViewPager实现android软件使用向导功能实现步骤

现在的大部分android软件,都是使用说明,就是第一次使用该软件时,会出现向导,可以左右滑动,然后就进入应用的主界面了,下面我们就实现这个功能
收藏 0 赞 0 分享

android在异步任务中关闭Cursor的代码方法

android在异步任务中如何关闭Cursor?在我们开发应用的时候,很多时候会遇到这种问题,下面我们就看看代码如何实现
收藏 0 赞 0 分享

Android自定义桌面功能代码实现

android自定义桌面其实很简单,看一个例子就明白了
收藏 0 赞 0 分享

android将图片转换存到数据库再从数据库读取转换成图片实现代码

有时候我们想把图片存入到数据库中,尽管这不是一种明智的选择,但有时候还是不得以会用到,下面说说将图片转换成byte[]数组存入到数据库中去,并从数据库中取出来转换成图像显示出来
收藏 0 赞 0 分享

TextView显示系统时间(时钟功能带秒针变化

用System.currentTimeMillis()可以获取系统当前的时间,我们可以开启一个线程,然后通过handler发消息,来实时的更新TextView上显示的系统时间,可以做一个时钟的功能
收藏 0 赞 0 分享

Android用ListView显示SDCard文件列表的小例子

本文简单实现了用ListView显示SDCard文件列表,目录的回退等功能暂不讨论,获取文件列表,files即为所选择目录下的所有文件列表
收藏 0 赞 0 分享

Android拦截外拨电话程序示例

这篇文章主要介绍了Android拦截外拨电话的示例,大家参考使用吧
收藏 0 赞 0 分享

通过Html网页调用本地安卓(android)app程序代码

如何使用html网页和本地app进行传递数据呢?经过研究,发现还是有方法的,总结了一下,大致有一下几种方式
收藏 0 赞 0 分享

android Textview文字监控(Textview使用方法)

以手机号充值为例,当用户输入最后一位数时候,进行汇率的变换,本文就实现类似这样的功能
收藏 0 赞 0 分享

Android ListView长按弹出菜单二种实现方式示例

这篇文章主要介绍了Android ListView长按弹出菜单的方法,大家参考实现
收藏 0 赞 0 分享
查看更多