2013年10月24日 上班的第二天
昨天我是用afinal完成的则个功能,但是公司里并不希望使用第三方的代码,所以要求我在不使用第三方开源项目的情况下实现。
最先我是使用Thread开启一个子线程,在这个线程中完成文件下载,然后使用Handler异步消息来更新Notification中的进度条,废了九牛二虎之力,虽然完成了功能,但是做出的效果就是特别的卡,甚至连通知栏下拉都被冻结了。
后来我尝试了AsyncTask,很轻松的完成了下载和进度值的计算,但是在通知栏中改变进度条的进度,依然会出现卡屏的问题。
最后在StackOverFlow中查找解决方案,给出的答案是,在更新Notification的时候,使用Handler来更新进度条进度,更新的频率特别高,再次期间会不断的生成RemoteViews对象,所以消耗了大量的内存。虽然没有看到实实在在的代码,但是有了解决的思路。
1.降低Handler的更新的频率;
2.尽量能够复用RemoteViews的对象。
对应的具体的实现是用计数器来控制更新的频率,用静态的RemoteViews对象。
后面上代码:
主界面的布局文件:activity_main.xml
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:padding="10dp" 6 tools:context=".MainActivity" > 7 8 <TextView 9 android:id="@+id/hint_tv" 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content" 12 android:paddingTop="10dp" 13 android:text="@string/tv_main_hint" /> 14 15 <EditText 16 android:id="@+id/url_et" 17 android:layout_width="match_parent" 18 android:layout_height="wrap_content" 19 android:layout_toRightOf="@id/hint_tv" 20 android:hint="@string/et_downloadurl" 21 android:singleLine="true" /> 22 23 <Button 24 android:id="@+id/downloadBtn" 25 android:layout_width="match_parent" 26 android:layout_height="wrap_content" 27 android:layout_below="@id/url_et" 28 android:paddingTop="20dp" 29 android:text="@string/str_download" /> 30 31 <Button 32 android:layout_below="@id/downloadBtn" 33 android:id="@+id/pauseBtn" 34 android:layout_width="match_parent" 35 android:layout_height="wrap_content" 36 android:paddingTop="20dp" 37 android:text="@string/btn_pause" /> 38 39 <Button 40 android:layout_below="@id/pauseBtn" 41 android:id="@+id/continueBtn" 42 android:layout_width="match_parent" 43 android:layout_height="wrap_content" 44 android:paddingTop="20dp" 45 android:text="@string/btn_continue" /> 46 47 48 <ProgressBar 49 android:layout_below="@id/continueBtn" 50 android:id="@+id/pb" 51 style="?android:attr/progressBarStyleHorizontal" 52 android:layout_width="match_parent" 53 android:layout_height="wrap_content" 54 android:paddingTop="20dp" /> 55 56 <TextView 57 android:layout_below="@id/pb" 58 android:id="@+id/progressTV" 59 android:text="0%" 60 android:layout_centerHorizontal="true" 61 android:layout_width="wrap_content" 62 android:layout_height="wrap_content" 63 android:paddingTop="20dp" /> 64 65 66 </RelativeLayout>
自定义Notification的布局文件: notify_vew.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" > 5 6 <ImageView 7 android:id="@+id/notify_icon" 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:src="@drawable/ic_launcher" /> 11 12 <TextView 13 android:id="@+id/tv" 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content" 16 android:layout_toRightOf="@id/notify_icon" 17 android:singleLine="true" 18 android:text="下载进度..." /> 19 20 <ProgressBar 21 android:id="@+id/pb" 22 style="?android:attr/progressBarStyleHorizontal" 23 android:layout_width="match_parent" 24 android:layout_height="wrap_content" 25 android:layout_below="@id/tv" 26 android:layout_toRightOf="@id/notify_icon" 27 android:max="100" 28 android:paddingRight="10dp" 29 android:progress="50" 30 android:secondaryProgress="74" 31 android:visibility="visible" /> 32 33 </RelativeLayout>
strings.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 4 <string name="app_name">DownLoader</string> 5 <string name="action_settings">Settings</string> 6 <string name="hello_world">Hello world!</string> 7 <string name="tv_main_hint">下载地址:</string> 8 <string name="et_downloadurl">请输入下载地址</string> 9 <string name="str_download">开始下载</string> 10 <string name="btn_pause">暂停下载</string> 11 <string name="btn_continue">继续下载</string> 12 13 </resources>
在清单文件中申请的权限:AndroidManifest.xml
1 <uses-permission android:name="android.permission.INTERNET"/> 2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
MainActivity.java
1 package com.yt.asynctaskdemo; 2 3 import java.io.FileOutputStream; 4 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.net.MalformedURLException; 9 import java.net.URL; 10 import java.net.URLConnection; 11 12 13 14 15 import android.os.AsyncTask; 16 import android.os.Bundle; 17 import android.os.Environment; 18 import android.os.Handler; 19 import android.os.Message; 20 import android.app.Activity; 21 import android.app.Notification; 22 import android.app.NotificationManager; 23 import android.app.PendingIntent; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.util.Log; 27 import android.view.View; 28 import android.view.View.OnClickListener; 29 import android.widget.Button; 30 import android.widget.EditText; 31 import android.widget.ProgressBar; 32 import android.widget.RemoteViews; 33 import android.widget.TextView; 34 35 public class MainActivity extends Activity { 36 37 public static final String TAG = "MainActivity"; 38 39 private int count; 40 private int current; 41 private EditText downloadUrlEt; 42 private Button downloadBtn; 43 private Button pauseBtn; 44 private Button continueBtn; 45 private ProgressBar pb; 46 private int progress; 47 private TextView progressTV; 48 private boolean finished; 49 private boolean paused; 50 private NotificationManager manager; 51 private Notification notification; 52 private static RemoteViews contentView; 53 54 55 private int times; 56 57 private MyAsyncTask mTask; 58 59 private Handler handler = new Handler(){ 60 public void handleMessage(android.os.Message msg) { 61 if(contentView == null){ 62 contentView = new RemoteViews(getPackageName(), R.layout.notify_view); 63 contentView.setProgressBar(R.id.pb, 100, 0, false); 64 notification.icon = R.drawable.ic_launcher; 65 notification.tickerText = "下载进度"; 66 notification.flags = notification.DEFAULT_ALL; 67 notification.contentView = contentView; 68 PendingIntent contentIntent = PendingIntent.getActivity(MainActivity.this, 0, 69 new Intent(MainActivity.this, MainActivity.class), 0); 70 71 notification.setLatestEventInfo(MainActivity.this, "你好!", 72 "byebye", contentIntent); 73 manager.notify(0, notification); 74 } 75 if(times++ % 5 == 0 || progress==100){ 76 contentView.setProgressBar(R.id.pb, 100, progress, false); 77 notification.contentView = contentView; 78 manager.notify(0, notification); 79 } 80 super.handleMessage(msg); 81 }; 82 }; 83 @Override 84 protected void onCreate(Bundle savedInstanceState) { 85 super.onCreate(savedInstanceState); 86 setContentView(R.layout.activity_main); 87 downloadUrlEt = (EditText) findViewById(R.id.url_et); 88 downloadUrlEt.setText("http://mit.95195.com/singleonline.apk"); 89 downloadBtn = (Button) findViewById(R.id.downloadBtn); 90 pauseBtn = (Button) findViewById(R.id.pauseBtn); 91 continueBtn = (Button) findViewById(R.id.continueBtn); 92 progressTV = (TextView) findViewById(R.id.progressTV); 93 pb = (ProgressBar) findViewById(R.id.pb); 94 MyOnClickListener listener = new MyOnClickListener(); 95 downloadBtn.setOnClickListener(listener); 96 pauseBtn.setOnClickListener(listener); 97 continueBtn.setOnClickListener(listener); 98 mTask = new MyAsyncTask(); 99 manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 100 notification = new Notification(R.drawable.ic_launcher, "下载进度条...",System.currentTimeMillis()); 101 } 102 103 104 /** 105 * 按钮事件监听 106 * 107 * @author yt 108 * 109 */ 110 class MyOnClickListener implements OnClickListener { 111 112 @Override 113 public void onClick(View v) { 114 switch (v.getId()) { 115 case R.id.downloadBtn: 116 mTask.execute("http://mit.95195.com/singleonline.apk"); 117 break; 118 119 case R.id.pauseBtn: 120 paused = true; 121 break; 122 123 case R.id.continueBtn: 124 paused = false; 125 break; 126 } 127 } 128 129 } 130 131 132 class MyAsyncTask extends AsyncTask<String, Integer, String>{ 133 @Override 134 protected String doInBackground(String... params) { 135 try { 136 URL url = new URL(params[0]); 137 URLConnection conn = url.openConnection(); 138 count = conn.getContentLength(); 139 InputStream is = conn.getInputStream(); 140 OutputStream os = new FileOutputStream(Environment.getExternalStorageDirectory()+"/singleon.apk"); 141 byte[] buffer = new byte[1024]; 142 int len = -1; 143 while(!finished){ 144 while(!paused && (len = is.read(buffer))>0){ 145 current += len; 146 os.write(buffer,0,len); 147 progress = current * 100 / count; 148 // Log.i(TAG, "current = " + current + " count = " + count + " progress = " + progress); 149 publishProgress(progress); 150 Message msg = new Message(); 151 handler.handleMessage(msg); 152 } 153 } 154 155 } catch (MalformedURLException e) { 156 e.printStackTrace(); 157 } catch (IOException e) {; 158 e.printStackTrace(); 159 } 160 161 return progress+""; 162 } 163 164 @Override 165 protected void onPostExecute(String result) { 166 Log.i(TAG, result+""); 167 super.onPostExecute(result); 168 } 169 170 171 @Override 172 protected void onProgressUpdate(Integer... values) { 173 174 if(values[0]==99){ 175 finished = true; 176 manager.cancel(0); 177 } 178 progressTV.setText(values[0]+""); 179 pb.setProgress(progress); 180 super.onProgressUpdate(values); 181 } 182 183 @Override 184 protected void onPreExecute() { 185 handler.handleMessage(new Message()); 186 super.onPreExecute(); 187 } 188 189 } 190 191 }
完整代码下载:http://download.csdn.net/detail/yuan936845015/6450041