Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 服務Service的基本用法

服務Service的基本用法

編輯:關於Android編程

作為 Android四大組件之一, 服務也少不了有很多非常重要的知識點,那自然要從最基本的用法開始學習了。

定義一個服務

public class MyService extends Service {
    /**
     * onBind是繼承Service後唯一的一個抽象方法所以必須要重寫的一個方法
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    /**
     * 服務每次啟動的時候調用
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }
    /**
     * 在服務創建的時候調用
     */
    @Override
    public void onCreate() {
        Log.i("MyService", "onCreate");
        super.onCreate();
    }
    /**
     * 會在服務銷毀的時候調用
     */
    @Override
    public void onDestroy() {
        Log.i("MyService", "onDestroy");
        super.onDestroy();
    }

啟動和停止服務

public class MyServiceActivity extends Activity{
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.androidservice_activity);
            Button start=(Button) findViewById(R.id.start);
            start.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Intent intent=new Intent(MyServiceActivity.this,MyService.class);
                    startService(intent);//啟動服務
                }
            });

            Button stop=(Button) findViewById(R.id.stop);
            stop.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Intent intent=new Intent(MyServiceActivity.this,MyService.class);
                    stopService(intent);//停止服務
                }
            });
        }
}

注意,這裡完全是由活動來決定服務何時停止的,如果沒有點擊Stop Service 按鈕, 服務就會一直處於運行狀態。 那服務有沒有什麼辦法讓自已停止下來呢?當然可以, 只需要在 MyService 的任何一個位置調用 stopSelf()方法就能讓這個服務停止下來了。

我們可以看到Logcat打印的信息:
這裡寫圖片描述

點擊start服務成功啟動,點擊stop然後成功銷毀, 運行成功後可以在正在運行的應用列表當中找到這個應用,停止掉之後就找不到了:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160622/20160622091033717.png" title="\" />

這裡寫圖片描述

已經學會了啟動服務以及停止服務的方法,不知道你心裡現在有沒有一個疑惑,那就是 onCreate()方法和 onStartCommand()到底有什麼區別呢?因為剛剛點擊Start Service按鈕後兩個方法都執行了。其實 onCreate()方法是在服務第一次創建的時候調用的,而 onStartCommand()方法則在每次啟動服務的時候都會調用,由於剛才我們是第一次點擊 Start Service 按鈕,服務此時還未創建過,所以兩個方法都會執行,之後如果你再連續多點擊幾次 Start Service 按鈕,你就會發現只有 onStartCommand()方法可以得到執行了。

活動和服務進行通信

我們在活動裡調用了 startService()方法來啟動 MyService這個服務,然後 MyService的 onCreate()和onStartCommand()方法就會得到執行。之後服務會一直處於運行狀態,但具體運行的是什麼邏輯,活動控制不了了。這就類似於活動通知了服務一下: “你可以啟動了! ”然後服務就去忙自己的事情了,但活動並不知道服務到底去做了什麼事情,以及完成的如何。那麼有沒有什麼辦法能讓活動和服務的關系更緊密一些呢?例如在活動中指揮服務去干什麼,服務就去干什麼。當然可以,這就需要借助我們剛剛忽略的 onBind()方法了。
比如說目前我們希望在 MyService裡提供一個下載功能,然後在活動中可以決定何時開始下載, 以及隨時查看下載進度。 實現這個功能的思路是創建一個專門的 Binder對象來對下載功能進行管理,修改 MyService中的代碼,如下所示:

public class MyService extends Service {
    /**
     * 創建binder對象
     */
    DownLoadBind bind = new DownLoadBind();

    class DownLoadBind extends Binder {
        /**
         * 一個開始下載的方法
         */
        public void startDownload() { 
            Log.i("DownLoadBind", "startDownload");
        }
        /**
         * 一個獲取進度的方法
         * @return
         */
        public int getProgress() {
            Log.i("DownLoadBind", "getProgress");
            return 0;
        }
    }

    /**
     * onBind是繼承Service後唯一的一個抽象方法所以必須要重寫的一個方法
     * 該方法是為了服務可以與服務進行通信,例如在活動中指揮服務去干什麼,服務就去干什麼
     * 返回binder對象
     */
    @Override
    public IBinder onBind(Intent intent) {
        return bind;
    }

    /**
     * 服務每次啟動的時候調用
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 在服務創建的時候調用
     */
    @Override
    public void onCreate() {
        Log.i("MyService", "onCreate");
        super.onCreate();
    }

    /**
     * 會在服務銷毀的時候調用
     */
    @Override
    public void onDestroy() {
        Log.i("MyService", "onDestroy");
        super.onDestroy();
    }

接下來看下MyServiceActivity中的代碼,在MyServiceActivity新增了兩個按鈕

public class MyServiceActivity extends Activity{
        private MyService.DownLoadBind down;
        /**
         * 創建ServiceConnection的匿名內部類並重寫兩個方法
         */
        private ServiceConnection connection=new ServiceConnection() {
            /**
             * 在與服務解除綁定的時候調用
             */
            @Override
            public void onServiceDisconnected(ComponentName name) {


            }
            /**
             * 綁定成功的時候調用
             */
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                down=(DownLoadBind) service;//通過向下轉型得到DownLoadBind的實例有了這個實例活動與服務的關系就變得非常緊密了
                down.startDownload();
                down.getProgress();
            }
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.androidservice_activity);
            Button start=(Button) findViewById(R.id.start);
            start.setOnClickListener(new OnClickListener(){

                @Override
                public void onClick(View v) {
                    Intent intent=new Intent(MyServiceActivity.this,MyService.class);
                    startService(intent);//開始服務
                }
            });

            Button stop=(Button) findViewById(R.id.stop);
            stop.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Intent intent=new Intent(MyServiceActivity.this,MyService.class);
                    stopService(intent);//停止服務
                }
            });

            Button bind=(Button) findViewById(R.id.BindService);
            bind.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Intent intent=new Intent(MyServiceActivity.this,MyService.class);
                    /**
                     * 第一個參數剛剛構建出的 Intent對象  第二個參數前面創建出的 ServiceConnection的實例,第三個則是一個標志位
                     * 這裡傳入 BIND_AUTO_CREATE 表示在活動和服務進行綁定後自動創建服務。這會使得 
                     * MyService 中的 onCreate()方法得到執行,但 onStartCommand()方法不會執行。
                     */
                    bindService(intent, connection, BIND_AUTO_CREATE);//綁定服務
                }
            });

            Button unbind=(Button) findViewById(R.id.UnbindService);
            unbind.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    unbindService(connection);//解綁服務點擊了就會服務就會停止運行
                }
            });
        }
}

到此為止activity可以調用服務當中任何public方法。實現了在活動當中去控制服務當中的方法,想讓服務干嘛就干嘛。
運行下程序:

這裡寫圖片描述

Logcat當中可以看到成功運行服務當中的兩個方法以及onCreate方法。另外需要注意,任何一個服務在整個應用程序范圍內都是通用的,即 MyService不僅可以和 MainActivity 綁定,還可以和任何一個其他的活動進行綁定,而且在綁定完成後它們都可以獲取到相同的 DownloadBinder實例。

服務的生命周期

學習過了活動以及碎片的生命周期。類似地,服務也有自己的生命周期,前面我們使用到的

onCreate()、onStartCommand()、onBind()和 onDestroy()等方法都是在服務的生命周期內可能回調的方法。一旦在項目的任何位置調用了 Context 的startService()方法,相應的服務就會啟動起來,並回調 onStartCommand()方法。

如果這個服務之前還沒有創建過,onCreate()方法會先於onStartCommand()方法執行。服務啟動了之後會一直保持運行狀態,直到stopService()或stopSelf()方法被調用。注意雖然每調用一次 startService()方法,onStartCommand()就會執行一次, 但實際上每個服務都只會存在一個實例。

所以不管你調用了多少次 startService()方法,只需調用一次 stopService()或stopSelf()方法,服務就會停止下來了。另外,還可以調用 Context 的bindService()來獲取一個服務的持久連接,這時就會回調服務中的onBind()方法

類似地,如果這個服務之前還沒有創建過,onCreate()方法會先於onBind()方法執行。之後,調用方可以獲取到onBind()方法裡返回的 IBinder對象的實例,這樣就能自由地和服務進行通信了。只要調用方和服務之間的連接沒有斷開,服務就會一直保持運行狀態。當調用了 startService()方法後,又去調用 stopService()方法

這時服務中的 onDestroy()方法就會執行,表示服務已經銷毀了。類似地,當調用了 bindService()方法後,又去調用unbindService()方法,
onDestroy()方法也會執行,這兩種情況都很好理解。但是需要注意,我們是完全有可能對一個服務既調用了 startService()方法,又調用了 bindService()方法的,

這種情況下該如何才能讓服務銷毀掉呢?根據 Android系統的機制,一個服務只要被啟動或 者被綁定了之後,就會一直處於運行狀態,必須要讓以上兩種條件同時不滿足,服務才能被 銷毀。所以,這種情況下要同時調用stopService()和 unbindService()方法,onDestroy()方法才 會執行。

這樣你就已經把服務的生命周期完整地走了一遍。

使用 IntentService

服務中的代碼都是默認運行在主線程當中的,如果直接在服務裡去處理一些耗時的邏輯,就很容易出現 ANR(Application NotResponding)的情況。所以這個時候就需要用到 Android多線程編程的技術了,我們應該在服務的每個具體的方法裡開啟一個子線程,然後在這裡去處理那些耗時的邏輯。因此,一個比較標准的服務就可以寫成如下形式:

public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 處理具體的邏輯
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}

雖說這種寫法並不復雜, 但是總會有一些程序員忘記開啟線程, 或者忘記調用 stopSelf()
方法。為了可以簡單地創建一個異步的、會自動停止的服務,Android 專門提供了一個
IntentService 類,這個類就很好地解決了前面所提到的兩種尴尬,下面我們就來看一下它的
用法。

public class MyIntentService extends IntentService{
    /**
     * 調用父類的有構造函數
     * @param name
     */
    public MyIntentService() {
        super("MyIntentService");
    }
    /**
     * 這個方法可以去處理一些具體的邏輯問題,不用擔心ARN問題
     * 這個方法已經是在子線程中運行的了
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        // 打印當前線程的id
        Log.d("MyIntentService", "子線程ID" + Thread.currentThread().getId());
    }
    /**
     * 在創建服務後是會自動停止的
     */
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.i("MyIntentService", "onDestroy");
    }
}

在MyServiceActivity新增一個按鈕分別打印子線程ID以及主線程ID
這裡寫圖片描述

Button startintent=(Button) findViewById(R.id.startintent);
            startintent.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Log.i("MyServiceActivity", "主線程ID"+Thread.currentThread().getId());
                    Intent intent=new Intent(MyServiceActivity.this,MyIntentService.class);
                    startService(intent);
                }
            });

運行程序:Logcat打印信息:
這裡寫圖片描述

可以看到, 不僅 MyIntentService和 MainActivity 所在的線程 id 不一樣, 而且 onDestroy()方法也得到了執行, 說明 MyIntentService在運行完畢後確實自動停止了。 集開啟線程和自動停止於一身IntentService 還是博得了不少程序員的喜愛。

後台執行的定時任務

下面我們就來創建一個可以長期在後台執行定時任務的服務。Android中的定時任務一般有兩種實現方式,一種是使用 Java API 裡提供的 Timer 類,一種是使用 Android的 Alarm機制。我們來看看Alarm機制。

public class LongRunningService extends Service{

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //打印時間信息
                Log.d("LongRunningService", "executed at " + new Date().
                        toString());
            }
        }).start();
        AlarmManager manager=(AlarmManager) getSystemService(ALARM_SERVICE);
        int hour=3000;//每隔三秒刷新一次
        /**
         * 使用 SystemClock.elapsedRealtime()方法可以獲取到系統開機至今所經歷時間的毫秒數,
         * 使用 System.currentTimeMillis()方法可以獲取到 1970年 1 月 1日 0點至今所經歷時間的毫秒數。
         */
        long triggerAtTime = SystemClock.elapsedRealtime() + hour;
        Intent i = new Intent(this, AlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
        /**
         * set第一個參數整型參數,用於指定 AlarmManager的工作類型,有四種值可選
         * ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC 和 RTC_WAKEUP
         * ELAPSED_REALTIME: 表示讓定時任務的觸發時間從系統開機開始算起,但不會喚醒 CPU
         * ELAPSED_REALTIME_WAKEUP: 同樣表示讓定時任務的觸發時間從系統開機開始算起,但會喚醒 CPU
         * RTC:表示讓定時任務的觸發時間從 1970 年 1月 1 日 0點開始算起,但不會喚醒 CPU
         * RTC_WAKEUP: 同樣表示讓定時任務的觸發時間從1970 年 1 月 1 日 0 點開始算起,但會喚醒 CPU
         * 
         * 第二個參數表示就是定時任務觸發的時間,以毫秒為單位。
         * 如果第一個參數使用的是 ELAPSED_REALTIME或 ELAPSED_REALTIME_WAKEUP,
         * 則這裡傳入開機至今的時間再加上延遲執行的時間。如果第一個參數使用的是 RTC 或RTC_WAKEUP,
         * 則這裡傳入 1970年 1月 1日 0點至今的時間再加上延遲執行的時間。
         * 
         * 第三個參數是一個 PendingIntent,這裡我們一般會調用 getBroadcast()方法來獲取一個能夠執行廣播的 PendingIntent。 
         * 這樣當定時任務被觸發的時候,廣播接收器的 onReceive()方法就可以得到執行。
         */
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
        return super.onStartCommand(intent, flags, startId);

    }

}

MyServiceActivity:

Button button=(Button) findViewById(R.id.startAlarm);
            button.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Intent intent=new Intent(MyServiceActivity.this,LongRunningService.class);
                    startService(intent);
                }
            });

AlarmReceiver :

public class AlarmReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent intent2=new Intent(context,LongRunningService.class);
        context.startService(intent2);
    }

}

onReceive()方法裡的代碼非常簡單,就是構建出了一個 Intent 對象,然後去啟動LongRunningService 這個服務。那麼這裡為什麼要這樣寫呢?其實在不知不覺中,這就已經將一個長期在後台定時運行的服務完成了。因為一旦啟動 LongRunningService,就會在onStartCommand()方法裡設定一個定時任務,這樣一小時後 AlarmReceiver 的 onReceive()方法就將得到執行,然後我們在這裡再次啟動 LongRunningService,這樣就形成了一個永久的循環,保證 LongRunningService 可以每隔一段時間就會啟動一次,一個長期在後台定時運行的服務自然也就完成了。

最後別忘了在AndroidManifest.xml注冊

運行:
Logcat打印信息:
這裡寫圖片描述

可以看到程序已經成功運行了,每隔3秒鐘刷新一次時間。實際運用當中可以把LOG信息換成邏輯即可。

最後來看一個利用服務Service,Handler多線程異步處理機制,HttpURLConnection,寫的一個通知欄版本升級的例子:

public class UpdateService extends Service {
    public static final String Install_Apk = "Install_Apk";
    /******** download progress step *********/
    private static final int down_step_custom = 3;

    private static final int TIMEOUT = 10 * 1000;// 超時
    private static String down_url;
    private static final int DOWN_OK = 1;
    private static final int DOWN_ERROR = 0;

    private String app_name;

    private NotificationManager notificationManager;
    private Notification notification;
    private Intent updateIntent;
    private PendingIntent pendingIntent;
    private RemoteViews contentView;

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 方法描述:onStartCommand方法
     * 
     * @param Intent
     *            intent, int flags, int startId
     * @return int
     * @see UpdateService
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        app_name = intent.getStringExtra("Key_App_Name");
        down_url = intent.getStringExtra("Key_Down_Url");
        //create file,應該在這個地方加一個返回值的判斷SD卡是否准備好,文件是否創建成功,等等!
        FileUtil.createFile(app_name);
        if (FileUtil.isCreateFileSucess == true) {
            createNotification();
            createThread();
        } else {
            Toast.makeText(this, R.string.insert_card, Toast.LENGTH_SHORT).show();
            /*************** stop service ************/
            stopSelf();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /********* update UI ******/
    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
            case DOWN_OK:
                /********* 下載完成,點擊安裝 ***********/
                Uri uri = Uri.fromFile(FileUtil.updateFile);
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setDataAndType(uri, "application/vnd.android.package-archive");
                pendingIntent = PendingIntent.getActivity(UpdateService.this, 0, intent, 0);

                notification.flags = Notification.FLAG_AUTO_CANCEL;
                notification.setLatestEventInfo(UpdateService.this, app_name, getString(R.string.down_sucess),
                        pendingIntent);
                // notification.setLatestEventInfo(UpdateService.this,app_name,
                // app_name + getString(R.string.down_sucess), null);
                notificationManager.notify(R.layout.notification_item, notification);

                /***** 安裝APK ******/
                // installApk();

                // stopService(updateIntent);
                /*** stop service *****/
                stopSelf();
                break;

            case DOWN_ERROR:
                notification.flags = Notification.FLAG_AUTO_CANCEL;
                // notification.setLatestEventInfo(UpdateService.this,app_name,
                // getString(R.string.down_fail), pendingIntent);
                notification.setLatestEventInfo(UpdateService.this, app_name, getString(R.string.down_fail), null);
                /*** stop service *****/
                // onDestroy();
                stopSelf();
                break;

            default:
                // stopService(updateIntent);
                /****** Stop service ******/
                // stopService(intentname)
                // stopSelf();
                break;
            }
        }
    };

    private void installApk() {
        // TODO Auto-generated method stub
        /********* 下載完成,點擊安裝 ***********/
        Uri uri = Uri.fromFile(FileUtil.updateFile);
        Intent intent = new Intent(Intent.ACTION_VIEW);

        /**********
         * 加這個屬性是因為使用Context的startActivity方法的話,就需要開啟一個新的task
         **********/
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        UpdateService.this.startActivity(intent);
    }

    /**
     * 方法描述:createThread方法, 開線程下載
     * 
     * @param
     * @return
     * @see UpdateService
     */
    public void createThread() {
        new DownLoadThread().start();
    }

    private class DownLoadThread extends Thread {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            Message message = new Message();
            try {
                long downloadSize = downloadUpdateFile(down_url, FileUtil.updateFile.toString());
                if (downloadSize > 0) {
                    // down success
                    message.what = DOWN_OK;
                    handler.sendMessage(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
                message.what = DOWN_ERROR;
                handler.sendMessage(message);
            }
        }
    }

    /**
     * 方法描述:createNotification方法
     * 
     * @param
     * @return
     * @see UpdateService
     */
    public void createNotification() {
        /**
         * 定義一個前台服務
         */
        // notification = new Notification(R.drawable.dot_enable,app_name +
        // getString(R.string.is_downing) ,System.currentTimeMillis());
        notification = new Notification(
                // R.drawable.video_player,//應用的圖標
                R.drawable.icon, // 應用的圖標
                app_name + getString(R.string.is_downing), System.currentTimeMillis());
        notification.flags = Notification.FLAG_ONGOING_EVENT;
        // notification.flags = Notification.FLAG_AUTO_CANCEL;

        /*** 自定義 Notification 的顯示 ****/
        contentView = new RemoteViews(getPackageName(), R.layout.notification_item);
        contentView.setTextViewText(R.id.notificationTitle, app_name + getString(R.string.is_downing));
        contentView.setTextViewText(R.id.notificationPercent, "0%");
        contentView.setProgressBar(R.id.notificationProgress, 100, 0, false);
        notification.contentView = contentView;

        // updateIntent = new Intent(this, AboutActivity.class);
        // updateIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        // //updateIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        // pendingIntent = PendingIntent.getActivity(this, 0, updateIntent, 0);
        // notification.contentIntent = pendingIntent;

        notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(R.layout.notification_item, notification);
    }

    /***
     * down file
     * 
     * @return
     * @throws MalformedURLException
     */
    public long downloadUpdateFile(String down_url, String file) throws Exception {

        int down_step = down_step_custom;// 提示step
        int totalSize;// 文件總大小
        int downloadCount = 0;// 已經下載好的大小
        int updateCount = 0;// 已經上傳的文件大小

        InputStream inputStream;
        OutputStream outputStream;

        URL url = new URL(down_url);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        httpURLConnection.setConnectTimeout(TIMEOUT);
        httpURLConnection.setReadTimeout(TIMEOUT);
        // 獲取下載文件的size
        totalSize = httpURLConnection.getContentLength();

        if (httpURLConnection.getResponseCode() == 404) {
            throw new Exception("fail!");
            // 這個地方應該加一個下載失敗的處理,但是,因為我們在外面加了一個try---catch,已經處理了Exception,
            // 所以不用處理
        }

        inputStream = httpURLConnection.getInputStream();
        outputStream = new FileOutputStream(file, false);// 文件存在則覆蓋掉

        byte buffer[] = new byte[1024];
        int readsize = 0;

        while ((readsize = inputStream.read(buffer)) != -1) {

            // /*********如果下載過程中出現錯誤,就彈出錯誤提示,並且把notificationManager取消*********/
            // if (httpURLConnection.getResponseCode() == 404) {
            // notificationManager.cancel(R.layout.notification_item);
            // throw new Exception("fail!");
            // //這個地方應該加一個下載失敗的處理,但是,因為我們在外面加了一個try---catch,已經處理了Exception,
            // //所以不用處理
            // }

            outputStream.write(buffer, 0, readsize);
            downloadCount += readsize;// 時時獲取下載到的大小
            /*** 每次增張3% **/
            if (updateCount == 0 || (downloadCount * 100 / totalSize - down_step) >= updateCount) {
                updateCount += down_step;
                // 改變通知欄
                contentView.setTextViewText(R.id.notificationPercent, updateCount + "%");
                contentView.setProgressBar(R.id.notificationProgress, 100, updateCount, false);
                notification.contentView = contentView;
                notificationManager.notify(R.layout.notification_item, notification);
            }
        }
        if (httpURLConnection != null) {
            httpURLConnection.disconnect();
        }
        inputStream.close();
        outputStream.close();

        return downloadCount;
    }
}
public class FileUtil {
    public static File updateDir = null;
    public static File updateFile = null;
    /***********保存升級APK的目錄***********/
    public static final String KonkaApplication = "konkaUpdateApplication";

    public static boolean isCreateFileSucess;

    /** 
    * 方法描述:createFile方法
    * @param   String app_name
    * @return 
    * @see FileUtil
    */
    public static void createFile(String app_name) {

        if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState())) {
            isCreateFileSucess = true;

            updateDir = new File(Environment.getExternalStorageDirectory()+ "/" + KonkaApplication +"/");
            updateFile = new File(updateDir + "/" + app_name + ".apk");

            if (!updateDir.exists()) {
                updateDir.mkdirs();
            }
            if (!updateFile.exists()) {
                try {
                    updateFile.createNewFile();
                } catch (IOException e) {
                    isCreateFileSucess = false;
                    e.printStackTrace();
                }
            }

        }else{
            isCreateFileSucess = false;
        }
    }
}

Activity:

// 點擊更新
        update.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(context,UpdateService.class);
                intent.putExtra("Key_App_Name",appName);
                intent.putExtra("Key_Down_Url",appUrl);         
                startService(intent);
                popupWindow.dismiss();
            }
        });
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved