接到上一篇。
上一篇有3个通知主线程(UI线程),并让主线程来执行代码的方法。现在我们要接触的是稍微复杂一点的方法Handler和AsyncTask,当然,我们可以用这两个来做更多的工作。
参考:
http://www.vogella.com/articles/AndroidPerformance/article.html
http://developer.android.com/reference/android/os/Handler.html
通知主线程的方法有post(Runnable)
,postAtTime(Runnable, long)
, postDelayed(Runnable, long)
,sendEmptyMessage(int)
,sendMessage(Message)
,sendMessageAtTime(Message, long)
, andsendMessageDelayed(Message, long)
,每个都写个例子吧。
post(Runnable)
postAtTime(Runnable, long)
和postDelayed(Runnable, long)
我就不写了哈
MainActivity.java
package com.example.testdialog; import android.os.Bundle; import android.os.Handler; import android.app.Activity; import android.view.Menu; import android.widget.TextView; public class MainActivity extends Activity { private TextView mTextView; private Handler handler = new Handler(); public class CountThread extends Thread { private int i; @Override public void run() { for(i=0; i<100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } /** * 线程跑到哪里了 */ handler.post(new Runnable() { public void run() { mTextView.setText(String.valueOf(i)); } }); } /** * */ handler.post(new Runnable() { public void run() { mTextView.setText("线程跑完了!"); } }); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView)findViewById(R.id.textView1); /** * 启动线程 */ (new CountThread()).start(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }结果:
可能有的童鞋说我不用线程也可以做这个,是的,但是如果不用线程的话,你在跑的过程中点击菜单按钮试试,看有没有反应?
sendMessage(Message)
package com.example.testdialog; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.view.Menu; import android.widget.TextView; public class MainActivity extends Activity { private Handler handler; static class TestHandler extends Handler{ private TextView mTextView; /** * 我创建这个构造函数式因为我需要把这个handler类 * 声明成static的,如果不声明成static的话会有个警告, * 因为就那么一个警告,想去掉。所以。。。 * @param textView */ TestHandler(TextView textView) { TestHandler.this.mTextView = textView; } @Override public void handleMessage(Message msg) { // 在线程里面sendMessage //在handler里面就需要处理这些消息 switch(msg.what) { case CountThread.THREAD_START: mTextView.setText("线程启动啦,还带了两个参数:\n" + msg.getData().getString("param1") + "\n" + msg.getData().getString("param2")); break; case CountThread.THREAD_LOOP: mTextView.setText("线程正在运行循环,还带了个参数:\n" + msg.getData().getInt("i")); break; case CountThread.THREAD_END: mTextView.setText("线程运行结束了!"); break; } super.handleMessage(msg); } }; public class CountThread extends Thread { /** * 自己定义一些常量,只是为了更有意义,通过看名称就知道意思 */ public static final int THREAD_START = 0; public static final int THREAD_LOOP = 1; public static final int THREAD_END = 2; private int i; @Override public void run() { /** * 你可以定义消息类型,可以带不同类型的参数 */ Message msg = new Message(); msg.what = THREAD_START; Bundle bundle = new Bundle(); bundle.putString("param1", "这是第一个参数!"); bundle.putString("param2", "这是第二个参数!"); msg.setData(bundle); handler.sendMessage(msg); //发送消息 for(i=0; i<100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } /** * 线程跑的进度 */ msg = new Message(); bundle = new Bundle(); bundle.putInt("i", i); msg.setData(bundle); msg.what = THREAD_LOOP; handler.sendMessage(msg); //发送消息 } msg = new Message(); msg.what = THREAD_END; handler.sendMessage(msg); //发送消息 } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler = new TestHandler((TextView)findViewById(R.id.textView1)); /** * 启动线程 */ (new CountThread()).start(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }结果:
结论:如果想带个参数的话,最好用sendMessage,如果需要反馈的信息很少,可以用post
package com.example.testdialog; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.widget.TextView; public class MainActivity extends Activity { private TestTask mTask; private TextView mTextView; /** * AsyncTask<String, Integer, Long> 第一个是doInBackground的参数类型 * 第二个是onProgressUpdate的参数类型 第三个是onPostExecute的参数类型 * */ private class TestTask extends AsyncTask<Integer, Integer, Long> { /** * 注意哦,这个参数是String[] */ protected Long doInBackground(Integer... intArr) { int count = intArr[0]; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } long totalSize = 0; for (int i = 0; i < count; i++) { // 注意,待会儿我要把这个循环设置1000000,让大家看看cancel的效果 // 每次调用这个都会发送消息,然后主线程执行onProgressUpdate this.publishProgress(i); if (isCancelled()) break; totalSize++; } return totalSize; //这个是会被当做参数传到onPostExecute } protected void onProgressUpdate(Integer... progress) { mTextView.setText("现在循环进行到:" + progress[0]); } /** * 在doInBackground之前会执行 */ @Override protected void onPreExecute() { mTextView.setText("现在doInBackground还没有执行..."); } /** * 在调用AsyncTask.cancel的时候会执行 */ @Override protected void onCancelled() { mTextView.setText("点击返回按钮了"); } /** * 在doInBackground执行完成后 */ protected void onPostExecute(Long result) { mTextView.setText("测试AsyncTask结束了,\n循环了" + result + "次。"); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.textView1); mTask = new TestTask(); mTask.execute(1000000); // 看,亲,是百万次哦 } // 按返回键的时候会触发 @Override public void onBackPressed() { mTask.cancel(false); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
结果:
当点击返回按钮时,就不循环了,当循环到1000000次的时候(下面这张图是我把数量改成了10000次截的图,哈哈)
一个简单的Handler和SyncTask的例子。