Android0909(Service、Android線程)

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="開始"/>

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章