Service
利用Service做一个虚拟进度条
ProgressBar进度条,progress可以设置默认的进度
在activity_main.xml中加入进度条
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
android:layout_gravity="center_horizontal"
android:progress="50"/>
<Button
android:id="@+id/start_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始下载"/>
设置线程,通过启动服务来启动线程,线程启动进度,
MyService.java
public class MyService extends Service{
private int count;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("运行到了","onCreate");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("运行到了","onDestroy");
}
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
Log.d("运行到了","onStartCommand");
new Thread(new Runnable() {
@Override
public void run() {
while(count<100){
if (count>100){
count=0;
}
count++;
Intent intent1=new Intent();
intent1.setAction(MainActivity.DOWN_LOAD_ACTION);
intent1.putExtra("count",count);
sendBroadcast(intent1);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
进行动态注册,在Activity_Manifest.xml中注册
<service android:name=".MyService"></service>
在MainActivity.java中进行设置监听事件
public class MainActivity extends Activity {
private Button btn_start_service;
private Button btn_stop_service;
private Button btn_start_download;
private ProgressBar progressBar;
private MyDownLoadService mDownLoadService;
public static final String DOWN_LOAD_ACTION="com.service.text";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_start_service= (Button) findViewById(R.id.start_service);
btn_start_service.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),MyService.class);
startService(intent);
}
});
btn_stop_service= (Button) findViewById(R.id.stop_service);
btn_stop_service.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),MyService.class);
stopService(intent);
}
});
mDownLoadService=new MyDownLoadService();
IntentFilter filter=new IntentFilter();
filter.addAction(DOWN_LOAD_ACTION);
registerReceiver(mDownLoadService,filter);
progressBar= (ProgressBar) findViewById(R.id.progressBar);
btn_start_download= (Button) findViewById(R.id.start_download);
btn_start_download.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),MyService.class);
startService(intent);
}
});
}
class MyDownLoadService extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
int count=intent.getIntExtra("count", 0);
progressBar.setProgress(count);
}
}
//解绑,取消广播
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mDownLoadService);
}
}
Service是运行在主线程中,第一次运行时会调用onCreate()、onStartCommand(),当第二次启动时只会调用onStartCommand(),而当只在后台允许一个耗时操作时就要用到IntentService,IntentService本身包含一个线程,包含一个消息队列,会将后续的消息排在队列中,然后等待前面的消息运行结束后,在进行处理后续的消息。
在activity_main.xml中添加一个按钮
<Button
android:id="@+id/start_download_intentservice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始intentservice下载"/>
写一个MyIntentService.java类,继承于IntentService,要在AndroidManifest.xml中注册
<service android:name=".MyIntentService"></service>
public class MyIntentService extends IntentService{
private int count;
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public MyIntentService(String name) {
super(name);
}
public MyIntentService() {
this("");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d("IntetnService","运行到了OnCreate");
while(count<100){
if (count>100){
count=0;
}
count++;
Intent intent1=new Intent();
intent1.setAction(MainActivity.DOWN_LOAD_ACTION);
intent1.putExtra("count",count);
sendBroadcast(intent1);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d("IntetnService","运行到了onStartCommand");
}
}
在MainActivity.java中添加点击事件
public class MainActivity extends Activity {
private Button btn_start_service;
private Button btn_stop_service;
private Button btn_start_download;
private Button btn_intentservice;
private ProgressBar progressBar;
private MyDownLoadService mDownLoadService;
public static final String DOWN_LOAD_ACTION="com.service.text";
private AlarmManager mAlarmManager;
private BroadcastReceiverActivity mBroadcast;
private android.content.ContentResolver resolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_start_service= (Button) findViewById(R.id.start_service);
btn_start_service.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),MyService.class);
startService(intent);
}
});
btn_stop_service= (Button) findViewById(R.id.stop_service);
btn_stop_service.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),MyService.class);
stopService(intent);
}
});
mDownLoadService=new MyDownLoadService();
IntentFilter filter=new IntentFilter();
filter.addAction(DOWN_LOAD_ACTION);
registerReceiver(mDownLoadService,filter);
progressBar= (ProgressBar) findViewById(R.id.progressBar);
btn_start_download= (Button) findViewById(R.id.start_download);
btn_start_download.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),MyService.class);
startService(intent);
}
});
btn_intentservice= (Button) findViewById(R.id.start_download_intentservice);
btn_intentservice.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),MyIntentService.class);
startService(intent);
}
});
}
class MyDownLoadService extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
int count=intent.getIntExtra("count", 0);
progressBar.setProgress(count);
}
}
//解绑
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mDownLoadService);
}
}
Android线程
利用线程更新UI界面,Hanler()
UI界面只允许主线程来更改UI界面绘制,不允许其他线程来更改界面的绘制,给否则会报错抛出异常。因此就需要想要更改UI界面的线程将要更改界面的消息通过Message传递给主线程,由主线程来完成界面的绘制,当有多条消息时,主线程会将这些消息放在一个消息队列中,等待主线程的处理,通过Handler将消息转递给主线程,然后通过Handler的handleMessage() 方法来对消息进行处理。
Message msg=new Message();
msg.obj=count+"秒";
msg.what=TIME_DESC;
mhandler.sendMessage(msg);
Handler
private Handler mhandler=new Handler(){
public void handleMessage(Message msg){
Log.d("秒数",""+count+msg);
switch(msg.what){
case TIME_DESC:
String time= (String) msg.obj;
btn_handler.setText(time);
break;
}
}
};
这里就以倒计时定时器为例,界面activity_main.xml
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="倒计时"/>
<Button
android:id="@+id/btn_handler"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="60秒"/>
MainActivity.java
public class MainActivity extends Activity {
private int count=60;
private static final int TIME_DESC=0x23;
private Button btn_handler;
private Handler mhandler=new Handler(){
public void handleMessage(Message msg){
Log.d("秒数",""+count+msg);
switch(msg.what){
case TIME_DESC:
String time= (String) msg.obj;
btn_handler.setText(time);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_handler= (Button) findViewById(R.id.btn_handler);
btn_handler.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
count=60;
Toast.makeText(getApplication(),"开始倒计时",Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
@Override
public void run() {
while (count>0){
count--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg=new Message();
msg.obj=count+"秒";
msg.what=TIME_DESC;
mhandler.sendMessage(msg);
Log.d("秒数",""+count+msg);
}
}
}).start();
}
});
}
但这样写代码会有写繁琐,为了简洁,采用另外一种方法可以达到同样效果,前者使通过主线程里的封装好的Looper()方法来管理消息队列,这里我们可以通过一个自定义的Thread类来对消息进行管理,从而简洁了监听事件里的代码。
MainActivity.java中的按钮事件监听事件
public class MainActivity extends Activity {
private int count=60;
private static final int TIME_DESC=0x23;
private Button btnhandler;
private Handler handler=new Handler(){
public void handleMessage(Message msg){
Log.d("秒数",""+count+msg);
switch(msg.what){
case TIME_DESC:
count--;
btnhandler.setText(count+"秒");
if (count>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(TIME_DESC);
}
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnhandler= (Button) findViewById(R.id.btnhandler);
btnhandler.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
count=60;
handler.sendEmptyMessage(TIME_DESC);
}
});
}
}
子线程更新UI界面使通过子线程给主线程传递消息来更改UI界面,还可以互换一下,子线程可以接收来自主线程的消息。通过调用自定义的线程里的来让主线程发送消息,因此需要先调用启动线程的方法来启动线程里的Handler()来发送消息。
自定义的Thrad,MyThread .java写成内部类
class MyThread extends Thread{
@Override
public void run() {
Looper.prepare();
mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
Log.d("handler","接收到了主线程的消息");
}
};
Looper.loop();
}
}
MainActivity.java
public class MainActivity extends Activity {
private Button btnhandler;
private int count=60;
private static final int TIME_DESC=0x23;
private Handler handler=new Handler(){
public void handleMessage(Message msg){
Log.d("秒数",""+count+msg);
switch(msg.what){
case TIME_DESC:
count--;
btnhandler.setText(count+"秒");
if (count>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(TIME_DESC);
}
break;
}
}
};
private Button btnHandler;
private Handler mHandler;
class MyThread extends Thread{
@Override
public void run() {
Looper.prepare();
mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
Log.d("handler","接收到了主线程的消息");
}
};
Looper.loop();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnHandler= (Button) findViewById(R.id.btnHandler);
btnHandler.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendEmptyMessage(0);
}
});
btnhandler= (Button) findViewById(R.id.btnhandler);
btnhandler.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
count=60;
handler.sendEmptyMessage(TIME_DESC);
MyThread thread=new MyThread();
thread.start();
}
});
}
}
AsyncTask
为了子线程更好地对UI进行操作,Android还提提供了Handler之外一种工具AsyncTast。AsyncTast制定了三个参数,Params在执行AsyncTast时传入,可用于后台中进行的任务,Progress后台执行任务时,需要在界面上显示当前的进度,则使用这里的泛型作为进度单位,Result当任务执行完成后,需要对结果进行返回。
AsyncTask的泛型类型
这三个类型被用于一个异步任务,如下:
1. Params,启动任务执行的输入参数
2. Progress,后台任务执行的百分比
3. Result,后台计算的结果类型
4个步骤
当一个异步任务被执行,任务经过四各步骤:
1.onPreExecute(),在UI线程上调用任务后立即执行。这步通常被用于设置任务,例如在用户界面显示一个进度条。
2.doInBackground(Params…),后台线程执行onPreExecute()完后立即调用,这步被用于执行较长时间的后台计算。异步任务的参数也被传到这步。计算的结果必须在这步返回,将传回到上一步。在执行过程中可以调用publishProgress(Progress…)来更新任务的进度。
3.onProgressUpdate(Progress…),一次呼叫 publishProgress(Progress…)后调用 UI线程。执行时间是不确定的。这个方法用于当后台计算还在进行时在用户界面显示进度。例如:这个方法可以被用于一个进度条动画或在文本域显示记录。
4.onPostExecute(Result), 当后台计算结束时,调用 UI线程。后台计算结果作为一个参数传递到这步。
任务实例必须创建在 UI线程
线程规则
有一些线程规则必须去遵守,这个类才会正确的工作:任务实例必须创建在 UI线程
execute(Params…)必须在UI线程上调用
不要手动调用onPreExecute(), onPostExecute(Result), doInBackground(Params…), onProgressUpdate(Progress…)
这个任务只执行一次(如果执行第二次将会抛出异常)
一个简单的自定义的AsyncTast,MyDownLoadService.java
class MyTask extends AsyncTask<String,String ,String>{
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
btn_progressBar.setText(s);
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
int count1=Integer.parseInt(values[0]);
mprogressBar.setProgress(count1);
}
@Override
protected String doInBackground(String... params) {
while(count1<101){
count1++;
publishProgress(""+count1);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "下载已完成";
}
}
依旧以下载进度条为例。MainActivity.java
public class MainActivity extends Activity {
private Button btn_progressBar;
private ProgressBar mprogressBar;
private int count1=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mprogressBar= (ProgressBar) findViewById(R.id.progressBar2);
btn_progressBar= (Button) findViewById(R.id.btn_progressBar);
btn_progressBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyTask task=new MyTask();
task.execute("去执行吧");
}
});
class MyTask extends AsyncTask<String,String ,String>{
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
btn_progressBar.setText(s);
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
int count1=Integer.parseInt(values[0]);
mprogressBar.setProgress(count1);
}
@Override
protected String doInBackground(String... params) {
while(count1<101){
count1++;
publishProgress(""+count1);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "下载已完成";
}
}
}
activity_main.xml
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/progressBar2" />
<Button
android:id="@+id/btn_progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始"/>