Android 使用Service进行下载并在状态栏显示进度

声明

这是一篇我之前我在2012年写的博客,里面有些东西是基于2012年时安卓的系统来进行编写的,现在写这篇博客的原因是想尽量恢复之前丢失的博客。此博客里面提及的技术还是能够使用的,只是需要在高版本的系统中进行兼容,如在android6.0上需要动态获取存储权限、android 8.0及以上系统版本对于下载apk自动提示安装需要做的特殊处理进行修改一下就可以了。

实现过程

android 自动检测版本在这里就不用说了,今天想和大家一起分享的是如何将下载更新文件最小化到任务栏下载,替代掉丑陋的对话框提示下载,对话框提示下载的用户体验相当不好,我们把它修改成为后台下载这样可以改善用户的使用体验。

下载进度布局xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="#f2f2f2" >
    <LinearLayout 
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:orientation="horizontal"
       android:gravity="center">
       <ImageView 
           android:id="@+update_id/ivLogo"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:src="@drawable/logo"
           android:layout_margin="10dip" />
       <LinearLayout 
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:layout_weight="1"
           android:layout_marginRight="10dip">
           <TextView 
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:textColor="@color/deepblack"
               android:text="@string/app_name"
               android:textSize="18dip"
               android:textStyle="bold"/>
           <ProgressBar 
               android:id="@+update_id/pbDownload"
               android:layout_width="fill_parent"
               android:layout_height="12dip"
               android:progress="0"
               android:max="100"
               android:progressDrawable="@drawable/pb_style"
               style="?android:attr/progressBarStyleHorizontal" 
               mce_style="?android:attr/progressBarStyleHorizontal"   />
           <TextView 
               android:id="@+update_id/tvProcess"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:textColor="@color/deepblack"
               android:text="已下载0%"
               android:textSize="12dip"
              android:textStyle="bold" />
      </LinearLayout>
   </LinearLayout>
 </LinearLayout>

创建下载任务Service

public class UpdateService extends Service{
       private NotificationManager nm;
       private Notification notification;
       private File tempFile=null;
       private boolean cancelUpdate=false;
       private MyHandler myHandler;
       private int download_precent=0;
       private RemoteViews views; 
       private int notificationId=1234;

       @Override
       public IBinder onBind(Intent intent) {
              return null;
        }

       @Override
       public void onStart(Intent intent,int startId){
             super.onStart(intent, startId);
       }

       @Override
       public int onStartCommand(Intent intent,int flags,int startId){
             nm=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
             notification=new Notification();
             notification.icon=android.R.drawable.stat_sys_download;
            //notification.icon=android.R.drawable.stat_sys_download_done;
            notification.tickerText=getString(R.string.app_name)+"更新";
            notification.when=System.currentTimeMillis();
            notification.defaults=Notification.DEFAULT_LIGHTS;

            //设置任务栏中下载进程显示的views
            views=new RemoteViews(getPackageName(),R.layout.update);
            notification.contentView=views;

            PendingIntent contentIntent=PendingIntent.getActivity(this,0,new Intent(this,City.class),0);
            notification.setLatestEventInfo(this,"","", contentIntent);

            //将下载任务添加到任务栏中
            nm.notify(notificationId,notification);

            myHandler=new MyHandler(Looper.myLooper(),this);

            //初始化下载任务内容views
            Message message=myHandler.obtainMessage(3,0);
            myHandler.sendMessage(message);

            //启动线程开始执行下载任务
            downFile(intent.getStringExtra("url"));
            return super.onStartCommand(intent, flags, startId);
     }

    @Override
    public void onDestroy(){
       super.onDestroy();
    }

   //下载更新文件
   private void downFile(final String url) {
      new Thread() {
            public void run(){
                try {     
                      HttpClient client = new DefaultHttpClient();     
                     // params[0]代表连接的url     
                    HttpGet get = new HttpGet(url);        
                    HttpResponse response = client.execute(get);     
                    HttpEntity entity = response.getEntity();     
                    long length = entity.getContentLength();     
                    InputStream is = entity.getContent();
                    if (is != null) {
                           File rootFile=new File(Environment.getExternalStorageDirectory(), "/pinke");
                           if(!rootFile.exists()&&!rootFile.isDirectory())
                                rootFile.mkdir();
               
                           tempFile = new File(Environment.getExternalStorageDirectory(),

                                                                     "/pinke/"+url.substring(url.lastIndexOf("/")+1));
                          if(tempFile.exists())
                                tempFile.delete();
                          tempFile.createNewFile();
                  
                          //已读出流作为参数创建一个带有缓冲的输出流
                          BufferedInputStream bis = new BufferedInputStream(is);
          
                          //创建一个新的写入流,讲读取到的图像数据写入到文件中
                          FileOutputStream fos = new FileOutputStream(tempFile);
                          //已写入流作为参数创建一个带有缓冲的写入流
                          BufferedOutputStream bos = new BufferedOutputStream(fos);  
                     
                           int read; 
                           long count=0;
                           int precent=0;
                           byte[] buffer=new byte[1024];
                           while( (read = bis.read(buffer)) != -1 && !cancelUpdate){  
                               bos.write(buffer,0,read);
                               count+=read;
                               precent=(int)(((double)count/length)*100);

                               //每下载完成5%就通知任务栏进行修改下载进度
                               if(precent-download_precent>=5){
                                   download_precent=precent;
                                   Message message=myHandler.obtainMessage(3,precent);
                                   myHandler.sendMessage(message);    
                              }
                        }   
                        bos.flush();
                       bos.close();
                       fos.flush();
                       fos.close();
                       is.close();
                       bis.close(); 
                  }     
              
                  if(!cancelUpdate){
                      Message message=myHandler.obtainMessage(2,tempFile);
                     myHandler.sendMessage(message); 
                 }else{
                     tempFile.delete();
                }
            } catch (ClientProtocolException e) {  
                   Message message=myHandler.obtainMessage(4,"下载更新文件失败");
                   myHandler.sendMessage(message); 
            } catch (IOException e) {
                  Message message=myHandler.obtainMessage(4,"下载更新文件失败");
                  myHandler.sendMessage(message); 
            } catch(Exception e){
                  Message message=myHandler.obtainMessage(4,"下载更新文件失败");
                  myHandler.sendMessage(message); 
            }
        }
    }.start();       
}

//安装下载后的apk文件
private void Instanll(File file,Context context){
     Intent intent = new Intent(Intent.ACTION_VIEW);   
     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     intent.setAction(android.content.Intent.ACTION_VIEW);
     intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");    
     context.startActivity(intent);     
}   

/*事件处理类*/
class MyHandler extends Handler{
       private Context context;
       public MyHandler(Looper looper,Context c){
           super(looper);
          this.context=c;
       }

      @Override
      public void handleMessage(Message msg){
                super.handleMessage(msg);
               if(msg!=null){
                     switch(msg.what){
                           case 0:
                                   Toast.makeText(context,msg.obj.toString(), Toast.LENGTH_SHORT).show();
                                   break;
                           case 1:
                                  break;
                           case 2:
                                   //下载完成后清除所有下载信息,执行安装提示
                                  download_precent=0;
                                  nm.cancel(notificationId);
                                  Instanll((File)msg.obj,context);

                                  //停止掉当前的服务
                                  stopSelf();
                                  break;
                          case 3:

                                //更新状态栏上的下载进度信息
                                views.setTextViewText(R.update_id.tvProcess,"已下载"+download_precent+"%");
                                views.setProgressBar(R.update_id.pbDownload,100,download_precent,false);
                                notification.contentView=views;
                                nm.notify(notificationId,notification);
                                break;
                        case 4:
                              nm.cancel(notificationId);
                          break;
                      }
                  }
            }
     }
   }

在外面需要调用下载任务的地方使用startService(intent)来调用这个Service就可以了,最终的效果图片
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一个简单的示例,演示如何使用服务来播放音乐并在活动中显示进度。在这个示例中,我们使用MediaPlayer类来播放音乐,使用Handler类来更新UI元素。 1. 创建一个名为MusicService的服务类。 ```java public class MusicService extends Service implements MediaPlayer.OnCompletionListener { private MediaPlayer mediaPlayer; private Handler mHandler = new Handler(); @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); mediaPlayer = MediaPlayer.create(this, R.raw.music); mediaPlayer.setOnCompletionListener(this); } @Override public int onStartCommand(Intent intent, int flags, int startId) { mediaPlayer.start(); return START_NOT_STICKY; } @Override public void onDestroy() { super.onDestroy(); mediaPlayer.release(); } @Override public void onCompletion(MediaPlayer mp) { stopSelf(); } public int getDuration() { return mediaPlayer.getDuration(); } public int getCurrentPosition() { return mediaPlayer.getCurrentPosition(); } public void seekTo(int position) { mediaPlayer.seekTo(position); } } ``` 2. 在Activity中启动服务并绑定它。 ```java public class MainActivity extends AppCompatActivity { private MusicService musicService; private boolean isBound = false; private SeekBar seekBar; private TextView currentTimeTextView; private TextView durationTextView; private Runnable mRunnable = new Runnable() { @Override public void run() { if (isBound) { int currentPosition = musicService.getCurrentPosition(); seekBar.setProgress(currentPosition); String currentTime = millisecondsToString(currentPosition); currentTimeTextView.setText(currentTime); mHandler.postDelayed(this, 1000); } } }; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { MusicService.LocalBinder binder = (MusicService.LocalBinder) service; musicService = binder.getService(); isBound = true; int duration = musicService.getDuration(); seekBar.setMax(duration); String durationString = millisecondsToString(duration); durationTextView.setText(durationString); mHandler.postDelayed(mRunnable, 1000); } @Override public void onServiceDisconnected(ComponentName name) { isBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); seekBar = findViewById(R.id.seekBar); currentTimeTextView = findViewById(R.id.currentTimeTextView); durationTextView = findViewById(R.id.durationTextView); Intent intent = new Intent(this, MusicService.class); startService(intent); bindService(intent, mServiceConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(mServiceConnection); } private String millisecondsToString(int milliseconds) { int seconds = milliseconds / 1000; int minutes = seconds / 60; seconds = seconds % 60; return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds); } } ``` 3. 在Activity的布局文件中添加一个SeekBar和两个TextView,用于显示音乐的进度。 ```xml <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/currentTimeTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00:00" /> <View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> <TextView android:id="@+id/durationTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00:00" /> </LinearLayout> ``` 这个例子中,我们使用服务来播放音乐,并在Activity中显示进度。我们还使用Handler来定期更新UI元素。当Activity被销毁时,我们解除服务的绑定。 ### 回答2: 要使用service实现音乐播放并在activity中显示进度,首先需要创建一个service来处理音乐播放的逻辑。下面是实现该功能的步骤: 1. 创建一个MusicService的类,继承自Service,并实现音乐播放的逻辑。在其中实例化一个MediaPlayer对象,用于控制音乐的播放、暂停等操作。 2. 在MusicService中,定义一个Binder内部类,继承自Binder,并实现获取MusicService实例的方法,以便在activity中进行绑定和获取MusicService对象。 3. 在MusicService中,添加一个方法用于获取音乐播放的进度(例如getCurrentPosition()),并定义一个Handler对象,用于更新进度数据。 4. 在MusicService的onStartCommand()方法中,开始播放音乐,并使用Handler定时更新进度数据。 5. 在activity中,创建一个MediaPlayer对象和一个ServiceConnection对象,用于绑定MusicService。 6. 在activity中,实现ServiceConnection接口的方法,在其中获取MusicService对象,并调用MusicService的方法获取音乐进度。 7. 在activity中,使用一个TextView来显示音乐的进度,通过Handler不断更新TextView的文本。 8. 在activity的onStart()方法中,使用bindService()方法绑定MusicService,并传入ServiceConnection对象。 9. 在activity的onStop()方法中,使用unbindService()方法解绑MusicService。 通过以上步骤实现的代码逻辑,可以实现在activity中显示音乐播放的进度。通过绑定MusicService,我们可以获取到音乐播放的进度,并在activity中动态更新显示。同时,使用Handler定时获取进度数据,保证了进度的准确性和实时性。 ### 回答3: 要实现在Activity中显示音乐播放的进度,可以使用Service来管理音乐播放,并通过与Activity进行通信来更新进度。 首先,在Activity中创建一个ServiceConnection,用于与Service进行绑定和通信。在Activity的onCreate方法中,通过bindService方法绑定Service,并将ServiceConnection传入,以便进行通信。 在Service中,创建一个MediaPlayer对象用于播放音乐。在Service的onCreate方法中,初始化MediaPlayer对象并设置音乐文件等参数。在Service的onStartCommand方法中,启动MediaPlayer对象并开始播放音乐。 为了让Activity能够获取到音乐播放的进度,我们可以在Service中创建一个Handler对象,并在MediaPlayer的onPrepared方法中使用该Handler对象发送消息,将当前音乐播放的进度发送给Activity。 在Activity中,创建一个Handler对象,并重写Handler的handleMessage方法,在handleMessage方法中获取到音乐播放的进度,并更新到UI界面上的进度条或其他控件。 通过ServiceConnection的onServiceConnected方法,在Activity与Service成功绑定后,可以通过Binder对象提供的方法获取到Service中的Handler对象,并将Activity中的Handler对象传递给Service中的Handler对象。 在Service中,通过Activity传递的Handler对象,将音乐播放的进度发送到Activity中。在Activity中的Handler对象中,通过接收到的消息更新UI界面上的进度。 通过上述步骤,就可以实现在Activity中显示音乐播放的进度了。使用Service来管理音乐播放可以使音乐在后台不被打断,并且可以与其他组件进行通信,方便控制音乐的播放、暂停等操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值