我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android版多线程下载 仿下载助手(最新)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android版多线程下载 仿下载助手(最新)

首先声明一点: 这里的多线程下载并不是指多个线程下载一个 文件,而是每个线程负责一个文件,今天给大家分享一个多线程下载的 例子。先看一下效果,点击下载开始下载,同时显示下载进度,下载完成,变成程安装,点击安装提示安装应用。

界面效果图:

线程池ThreadPoolExecutor ,先简单学习下这个线程池的使用


 
   ThreadPoolExecutor threadpool=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler) 

上面是 ThreadPoolExecutor的参数说明,
第一个参数 corePoolSize : 空闲时 存在的线程数目、
第二个参数 maximumPoolSize :允许同时存在的最大线程数、
第三个参数 keepAliveTime: 这个参数是 允许空闲线程存活的时间、
第四个参数 unit : 是 时间的单位 、
第五个参数 workQueue :这个是一个容器,它里面存放的是、 threadpool.execute(new Runnable()) 执行的线程.new Runnable()、
第六个参数 handler:当执行被阻塞时,该处理程序将被阻塞,因为线程的边界和队列容量达到了 。
工具类 ThreadManager
介绍完了 线程池参数,那我们就先创建一个线程管理的工具类 ThreadManager


public class ThreadManager { 
  public static final String DEFAULT_SINGLE_POOL_NAME = "DEFAULT_SINGLE_POOL_NAME"; 
  private static ThreadPoolProxy mLongPool = null; 
  private static Object mLongLock = new Object(); 
  private static ThreadPoolProxy mShortPool = null; 
  private static Object mShortLock = new Object(); 
  private static ThreadPoolProxy mDownloadPool = null; 
  private static Object mDownloadLock = new Object(); 
  private static Map<String, ThreadPoolProxy> mMap = new HashMap<String, ThreadPoolProxy>(); 
  private static Object mSingleLock = new Object(); 
   
  public static ThreadPoolProxy getDownloadPool() { 
    synchronized (mDownloadLock) { 
      if (mDownloadPool == null) { 
        mDownloadPool = new ThreadPoolProxy(3, 3, 5L); 
      } 
      return mDownloadPool; 
    } 
  } 
   
  public static ThreadPoolProxy getLongPool() { 
    synchronized (mLongLock) { 
      if (mLongPool == null) { 
        mLongPool = new ThreadPoolProxy(5, 5, 5L); 
      } 
      return mLongPool; 
    } 
  } 
   
  public static ThreadPoolProxy getShortPool() { 
    synchronized (mShortLock) { 
      if (mShortPool == null) { 
        mShortPool = new ThreadPoolProxy(2, 2, 5L); 
      } 
      return mShortPool; 
    } 
  } 
   
  public static ThreadPoolProxy getSinglePool() { 
    return getSinglePool(DEFAULT_SINGLE_POOL_NAME); 
  } 
   
  public static ThreadPoolProxy getSinglePool(String name) { 
    synchronized (mSingleLock) { 
      ThreadPoolProxy singlePool = mMap.get(name); 
      if (singlePool == null) { 
        singlePool = new ThreadPoolProxy(1, 1, 5L); 
        mMap.put(name, singlePool); 
      } 
      return singlePool; 
    } 
  } 
  public static class ThreadPoolProxy { 
    private ThreadPoolExecutor mPool; 
    private int mCorePoolSize; 
    private int mMaximumPoolSize; 
    private long mKeepAliveTime; 
    private ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) { 
      mCorePoolSize = corePoolSize; 
      mMaximumPoolSize = maximumPoolSize; 
      mKeepAliveTime = keepAliveTime; 
    } 
     
    public synchronized void execute(Runnable run) { 
      if (run == null) { 
        return; 
      } 
      if (mPool == null || mPool.isShutdown()) { 
        mPool = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), Executors.defaultThreadFactory(), new AbortPolicy()); 
      } 
      mPool.execute(run); 
    } 
     
    public synchronized void cancel(Runnable run) { 
      if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) { 
        mPool.getQueue().remove(run); 
      } 
    } 
     
    public synchronized boolean contains(Runnable run) { 
      if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) { 
        return mPool.getQueue().contains(run); 
      } else { 
        return false; 
      } 
    } 
     
    public void stop() { 
      if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) { 
        mPool.shutdownNow(); 
      } 
    } 
     
    public synchronized void shutdown() { 
      if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) { 
        mPool.shutdownNow(); 
      } 
    } 
  } 
} 

这个线程池工具类 主要就是 生成一个线程池, 以及 取消线程池中的任务,查询线程池中是否包含某一任务。
下载任务 DownloadTask
我们的现在线程 DownloadTask 就 通过 ThreadManager .getDownloadPool().execute() 方法 交给线程池去管理。
有了线程池管理我们的线程, 那我们下一步 就是 DownloadTask 这个类去下载了。


 
 public class DownloadTask implements Runnable { 
   private DownloadInfo info; 
   public DownloadTask(DownloadInfo info) { 
     this.info = info; 
   } 
   @Override 
   public void run() { 
     info.setDownloadState(STATE_DOWNLOADING);// 先改变下载状态 
     notifyDownloadStateChanged(info); 
     File file = new File(info.getPath());// 获取下载文件 
     HttpResult httpResult = null; 
     InputStream stream = null; 
     if (info.getCurrentSize() == 0 || !file.exists() 
         || file.length() != info.getCurrentSize()) { 
       // 如果文件不存在,或者进度为0,或者进度和文件长度不相符,就需要重新下载 
       info.setCurrentSize(0); 
       file.delete(); 
     } 
     httpResult = HttpHelper.download(info.getUrl()); 
     // else { 
     // // //文件存在且长度和进度相等,采用断点下载 
     // httpResult = HttpHelper.download(info.getUrl() + "&range=" + 
     // info.getCurrentSize()); 
     // } 
     if (httpResult == null 
         || (stream = httpResult.getInputStream()) == null) { 
       info.setDownloadState(STATE_ERROR);// 没有下载内容返回,修改为错误状态 
       notifyDownloadStateChanged(info); 
     } else { 
       try { 
         skipBytesFromStream(stream, info.getCurrentSize()); 
       } catch (Exception e1) { 
         e1.printStackTrace(); 
       } 
       FileOutputStream fos = null; 
       try { 
         fos = new FileOutputStream(file, true); 
         int count = -1; 
         byte[] buffer = new byte[1024]; 
         while (((count = stream.read(buffer)) != -1) 
             && info.getDownloadState() == STATE_DOWNLOADING) { 
           // 每次读取到数据后,都需要判断是否为下载状态,如果不是,下载需要终止,如果是,则刷新进度 
           fos.write(buffer, 0, count); 
           fos.flush(); 
           info.setCurrentSize(info.getCurrentSize() + count); 
           notifyDownloadProgressed(info);// 刷新进度 
         } 
       } catch (Exception e) { 
         info.setDownloadState(STATE_ERROR); 
         notifyDownloadStateChanged(info); 
         info.setCurrentSize(0); 
         file.delete(); 
       } finally { 
         IOUtils.close(fos); 
         if (httpResult != null) { 
           httpResult.close(); 
         } 
       } 
       // 判断进度是否和app总长度相等 
       if (info.getCurrentSize() == info.getAppSize()) { 
         info.setDownloadState(STATE_DOWNLOADED); 
         notifyDownloadStateChanged(info); 
       } else if (info.getDownloadState() == STATE_PAUSED) {// 判断状态 
         notifyDownloadStateChanged(info); 
       } else { 
         info.setDownloadState(STATE_ERROR); 
         notifyDownloadStateChanged(info); 
         info.setCurrentSize(0);// 错误状态需要删除文件 
         file.delete(); 
       } 
     } 
     mTaskMap.remove(info.getId()); 
   } 
 } 

下载的原理 很简单,就是通过目标的URL 拿到流,然后写到本地。
因为下载在 run()里面执行,这个DownloadTask 类 我们就看run() 方法的实现,所以 关键代码 就是下面一点点


fos = new FileOutputStream(file, true); 
     int count = -1; 
     byte[] buffer = new byte[1024]; 
     while (((count = stream.read(buffer)) != -1) 
         && info.getDownloadState() == STATE_DOWNLOADING) { 
       // 每次读取到数据后,都需要判断是否为下载状态,如果不是,下载需要终止,如果是,则刷新进度 
       fos.write(buffer, 0, count); 
       fos.flush(); 
       info.setCurrentSize(info.getCurrentSize() + count); 
       notifyDownloadProgressed(info);// 刷新进度 
     } 

这个在我们刚接触Java 的时候 肯定都写过了。 这就是往本地写数据的代码。所以run()方法中的 前面 就是拿到 stream 输入流, 以及 把file 创建出来。
刷新进度,状态
关于控制 button中text 显示 暂停 ,下载,还是进度,就靠 notifyDownloadProgressed(info);和 notifyDownloadStateChanged(info)两个方法, 这两个方法 实际上调用的是两个接口,只要我们在我们需要改变界面的类里 实现这两个接口,就可以接收到 包含最新信息的info对象。而我们在哪个类里改变button 上面 显示的文字呢? 当然是在 我们的adapter 里面了,大家都知道 是在 adapter 的getView() 方法里面 加载的每一条数据的布局。
那就一起看下是不是这样子呢?


public class RecommendAdapter extends BaseAdapter implements 
    DownloadManager.DownloadObserver { 
  ArrayList<AppInfo> list; 
  private List<ViewHolder> mDisplayedHolders; 
  private FinalBitmap finalBitmap; 
  private Context context; 
  public RecommendAdapter(ArrayList<AppInfo> list, FinalBitmap finalBitmap, 
      Context context) { 
    this.list = list; 
    this.context = context; 
    this.finalBitmap = finalBitmap; 
    mDisplayedHolders = new ArrayList<ViewHolder>(); 
  } 
  public void startObserver() { 
    DownloadManager.getInstance().registerObserver(this); 
  } 
  public void stopObserver() { 
    DownloadManager.getInstance().unRegisterObserver(this); 
  } 
  @Override 
  public int getCount() { 
    return list.size(); 
  } 
  @Override 
  public Object getItem(int position) { 
    return list.get(position); 
  } 
  @Override 
  public long getItemId(int position) { 
    return position; 
  } 
  @Override 
  public View getView(int position, View convertView, ViewGroup parent) { 
    final AppInfo appInfo = list.get(position); 
    final ViewHolder holder; 
    if (convertView == null) { 
      holder = new ViewHolder(context); 
    } else { 
      holder = (ViewHolder) convertView.getTag(); 
    } 
    holder.setData(appInfo); 
    mDisplayedHolders.add(holder); 
    return holder.getRootView(); 
  } 
  @Override 
  public void onDownloadStateChanged(DownloadInfo info) { 
    refreshHolder(info); 
  } 
  @Override 
  public void onDownloadProgressed(DownloadInfo info) { 
    refreshHolder(info); 
  } 
  public List<ViewHolder> getDisplayedHolders() { 
    synchronized (mDisplayedHolders) { 
      return new ArrayList<ViewHolder>(mDisplayedHolders); 
    } 
  } 
  public void clearAllItem() { 
    if (list != null){ 
      list.clear(); 
    } 
    if (mDisplayedHolders != null) { 
      mDisplayedHolders.clear(); 
    } 
  } 
  public void addItems(ArrayList<AppInfo> infos) { 
    list.addAll(infos); 
  } 
  private void refreshHolder(final DownloadInfo info) { 
    List<ViewHolder> displayedHolders = getDisplayedHolders(); 
    for (int i = 0; i < displayedHolders.size(); i++) { 
      final ViewHolder holder = displayedHolders.get(i); 
      AppInfo appInfo = holder.getData(); 
      if (appInfo.getId() == info.getId()) { 
        AppUtil.post(new Runnable() { 
          @Override 
          public void run() { 
            holder.refreshState(info.getDownloadState(), 
                info.getProgress()); 
          } 
        }); 
      } 
    } 
  } 
  public class ViewHolder { 
    public TextView textView01; 
    public TextView textView02; 
    public TextView textView03; 
    public TextView textView04; 
    public ImageView imageView_icon; 
    public Button button; 
    public LinearLayout linearLayout; 
    public AppInfo mData; 
    private DownloadManager mDownloadManager; 
    private int mState; 
    private float mProgress; 
    protected View mRootView; 
    private Context context; 
    private boolean hasAttached; 
    public ViewHolder(Context context) { 
      mRootView = initView(); 
      mRootView.setTag(this); 
      this.context = context; 
    } 
    public View getRootView() { 
      return mRootView; 
    } 
    public View initView() { 
      View view = AppUtil.inflate(R.layout.item_recommend_award); 
      imageView_icon = (ImageView) view 
          .findViewById(R.id.imageview_task_app_cion); 
      textView01 = (TextView) view 
          .findViewById(R.id.textview_task_app_name); 
      textView02 = (TextView) view 
          .findViewById(R.id.textview_task_app_size); 
      textView03 = (TextView) view 
          .findViewById(R.id.textview_task_app_desc); 
      textView04 = (TextView) view 
          .findViewById(R.id.textview_task_app_love); 
      button = (Button) view.findViewById(R.id.button_task_download); 
      linearLayout = (LinearLayout) view 
          .findViewById(R.id.linearlayout_task); 
      button.setOnClickListener(new OnClickListener() { 
        @Override 
        public void onClick(View v) { 
          System.out.println("mState:173  "+mState); 
          if (mState == DownloadManager.STATE_NONE 
              || mState == DownloadManager.STATE_PAUSED 
              || mState == DownloadManager.STATE_ERROR) { 
            mDownloadManager.download(mData); 
          } else if (mState == DownloadManager.STATE_WAITING 
              || mState == DownloadManager.STATE_DOWNLOADING) { 
            mDownloadManager.pause(mData); 
          } else if (mState == DownloadManager.STATE_DOWNLOADED) { 
//           tell2Server(); 
            mDownloadManager.install(mData); 
          } 
        } 
      }); 
      return view; 
    } 
    public void setData(AppInfo data) { 
      if (mDownloadManager == null) { 
        mDownloadManager = DownloadManager.getInstance(); 
      } 
       String filepath= FileUtil.getDownloadDir(AppUtil.getContext()) + File.separator + data.getName() + ".apk"; 
        boolean existsFile = FileUtil.isExistsFile(filepath); 
        if(existsFile){ 
          int fileSize = FileUtil.getFileSize(filepath); 
          if(data.getSize()==fileSize){ 
            DownloadInfo downloadInfo = DownloadInfo.clone(data); 
            downloadInfo.setCurrentSize(data.getSize()); 
            downloadInfo.setHasFinished(true); 
            mDownloadManager.setDownloadInfo(data.getId(),downloadInfo ); 
          } 
//         else if(fileSize>0){ 
//           DownloadInfo downloadInfo = DownloadInfo.clone(data); 
//           downloadInfo.setCurrentSize(data.getSize()); 
//           downloadInfo.setHasFinished(false); 
//           mDownloadManager.setDownloadInfo(data.getId(),downloadInfo ); 
//         } 
        } 
      DownloadInfo downloadInfo = mDownloadManager.getDownloadInfo(data 
          .getId()); 
      if (downloadInfo != null) { 
        mState = downloadInfo.getDownloadState(); 
        mProgress = downloadInfo.getProgress(); 
      } else { 
        mState = DownloadManager.STATE_NONE; 
        mProgress = 0; 
      } 
      this.mData = data; 
      refreshView(); 
    } 
    public AppInfo getData() { 
      return mData; 
    } 
    public void refreshView() { 
      linearLayout.removeAllViews(); 
      AppInfo info = getData(); 
      textView01.setText(info.getName()); 
      textView02.setText(FileUtil.FormetFileSize(info.getSize())); 
      textView03.setText(info.getDes()); 
      textView04.setText(info.getDownloadNum() + "下载量); 
      finalBitmap.display(imageView_icon, info.getIconUrl()); 
      if (info.getType().equals("0")) { 
//       mState = DownloadManager.STATE_READ; 
        textView02.setVisibility(View.GONE); 
      }else{ 
        String path=FileUtil.getDownloadDir(AppUtil.getContext()) + File.separator + info.getName() + ".apk"; 
        hasAttached = FileUtil.isValidAttach(path, false); 
        DownloadInfo downloadInfo = mDownloadManager.getDownloadInfo(info 
            .getId()); 
        if (downloadInfo != null && hasAttached) { 
          if(downloadInfo.isHasFinished()){ 
            mState = DownloadManager.STATE_DOWNLOADED; 
          }else{ 
            mState = DownloadManager.STATE_PAUSED; 
          } 
        } else { 
          mState = DownloadManager.STATE_NONE; 
          if(downloadInfo !=null){ 
            downloadInfo.setDownloadState(mState); 
          } 
        } 
      } 
      refreshState(mState, mProgress); 
    } 
    public void refreshState(int state, float progress) { 
      mState = state; 
      mProgress = progress; 
      switch (mState) { 
      case DownloadManager.STATE_NONE: 
        button.setText(R.string.app_state_download); 
        break; 
      case DownloadManager.STATE_PAUSED: 
        button.setText(R.string.app_state_paused); 
        break; 
      case DownloadManager.STATE_ERROR: 
        button.setText(R.string.app_state_error); 
        break; 
      case DownloadManager.STATE_WAITING: 
        button.setText(R.string.app_state_waiting); 
        break; 
      case DownloadManager.STATE_DOWNLOADING: 
        button.setText((int) (mProgress * 100) + "%"); 
        break; 
      case DownloadManager.STATE_DOWNLOADED: 
        button.setText(R.string.app_state_downloaded); 
        break; 
//     case DownloadManager.STATE_READ: 
//       button.setText(R.string.app_state_read); 
//       break; 
      default: 
        break; 
      } 
    } 
  } 
} 

何时 注册 监听observer
里面代码有点多,那就看startObserver()方法做了什么。


public void startObserver() { 
    DownloadManager.getInstance().registerObserver(this); 
  } 

这里 是 注册了observer, Observer 是什么东西?在DownloadManager 中我们定义了



public interface DownloadObserver { 
  public void onDownloadStateChanged(DownloadInfo info); 
  public void onDownloadProgressed(DownloadInfo info); 
} 

一个接口,里面有两个抽象方法 一个是 进度,另一个是下载状态。
那回过头来,屡一下, 我们在 下载的关键代码里面调用了
DownloadObserver onDownloadProgressed()
DownloadObserver.onDownloadStateChanged()

两个抽象方法,而我们在 adapter


@Override 
 public void onDownloadStateChanged(DownloadInfo info) { 
   refreshHolder(info); 
 } 
 @Override 
 public void onDownloadProgressed(DownloadInfo info) { 
   refreshHolder(info); 
 } 

中实现了 这两个方法 就可以轻松的控制 去 刷新 和改变 下载状态了。
细心的朋友 或许 发现问题了,对,我们还没有注册Observer,就在 DownloadManager 中去调用了。
这里 在看下DownloadManager 中 调用的方法
/


** 当下载状态发送改变的时候回调 */ 
public void notifyDownloadStateChanged(DownloadInfo info) { 
  synchronized (mObservers) { 
    for (DownloadObserver observer : mObservers) { 
      observer.onDownloadStateChanged(info); 
    } 
  } 
} 
 
public void notifyDownloadProgressed(DownloadInfo info) { 
  synchronized (mObservers) { 
    for (DownloadObserver observer : mObservers) { 
      observer.onDownloadProgressed(info); 
    } 
  } 
} 

是的,这里我们遍历一个observer 容器,然后去刷新 ,所以我们还需要 把 Observer 对象 添加到 集合 mObservers 中,
所以肯定有这样一个方法 讲 observer 添加到集合中 。


 
public void unRegisterObserver(DownloadObserver observer) { 
  synchronized (mObservers) { 
    if (mObservers.contains(observer)) { 
      mObservers.remove(observer); 
    } 
  } 
} 

所以最后一步,因为 adapter 方法中有 startObserver, 所以 我们在 主界面 MainActivity 的类中调用 adapter.startObser() 将 实现了 接口的adapter 对象 添加到 Observer 容器中 就可以了。
OK。大功告成!
=============================================
DownloadManager 代码
这里 贴一下DownloadManager 代码


public class DownloadManager { 
  public static final int STATE_NONE = 0; 
   
  public static final int STATE_WAITING = 1; 
   
  public static final int STATE_DOWNLOADING = 2; 
   
  public static final int STATE_PAUSED = 3; 
   
  public static final int STATE_DOWNLOADED = 4; 
   
  public static final int STATE_ERROR = 5; 
  // public static final int STATE_READ = 6; 
  private static DownloadManager instance; 
  private DownloadManager() { 
  } 
   
  private Map<Long, DownloadInfo> mDownloadMap = new ConcurrentHashMap<Long, DownloadInfo>(); 
   
  private List<DownloadObserver> mObservers = new ArrayList<DownloadObserver>(); 
   
  private Map<Long, DownloadTask> mTaskMap = new ConcurrentHashMap<Long, DownloadTask>(); 
  public static synchronized DownloadManager getInstance() { 
    if (instance == null) { 
      instance = new DownloadManager(); 
    } 
    return instance; 
  } 
   
  public void registerObserver(DownloadObserver observer) { 
    synchronized (mObservers) { 
      if (!mObservers.contains(observer)) { 
        mObservers.add(observer); 
      } 
    } 
  } 
   
  public void unRegisterObserver(DownloadObserver observer) { 
    synchronized (mObservers) { 
      if (mObservers.contains(observer)) { 
        mObservers.remove(observer); 
      } 
    } 
  } 
   
  public void notifyDownloadStateChanged(DownloadInfo info) { 
    synchronized (mObservers) { 
      for (DownloadObserver observer : mObservers) { 
        observer.onDownloadStateChanged(info); 
      } 
    } 
  } 
   
  public void notifyDownloadProgressed(DownloadInfo info) { 
    synchronized (mObservers) { 
      for (DownloadObserver observer : mObservers) { 
        observer.onDownloadProgressed(info); 
      } 
    } 
  } 
   
  public synchronized void download(AppInfo appInfo) { 
    // 先判断是否有这个app的下载信息 
    DownloadInfo info = mDownloadMap.get(appInfo.getId()); 
    if (info == null) {// 如果没有,则根据appInfo创建一个新的下载信息 
      info = DownloadInfo.clone(appInfo); 
      mDownloadMap.put(appInfo.getId(), info); 
    } 
    // 判断状态是否为STATE_NONE、STATE_PAUSED、STATE_ERROR。只有这3种状态才能进行下载,其他状态不予处理 
    if (info.getDownloadState() == STATE_NONE 
        || info.getDownloadState() == STATE_PAUSED 
        || info.getDownloadState() == STATE_ERROR) { 
      // 下载之前,把状态设置为STATE_WAITING,因为此时并没有产开始下载,只是把任务放入了线程池中,当任务真正开始执行时,才会改为STATE_DOWNLOADING 
      info.setDownloadState(STATE_WAITING); 
      notifyDownloadStateChanged(info);// 每次状态发生改变,都需要回调该方法通知所有观察者 
      DownloadTask task = new DownloadTask(info);// 创建一个下载任务,放入线程池 
      mTaskMap.put(info.getId(), task); 
      ThreadManager.getDownloadPool().execute(task); 
    } 
  } 
   
  public synchronized void pause(AppInfo appInfo) { 
    stopDownload(appInfo); 
    DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息 
    if (info != null) {// 修改下载状态 
      info.setDownloadState(STATE_PAUSED); 
      notifyDownloadStateChanged(info); 
    } 
  } 
   
  public synchronized void cancel(AppInfo appInfo) { 
    stopDownload(appInfo); 
    DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息 
    if (info != null) {// 修改下载状态并删除文件 
      info.setDownloadState(STATE_NONE); 
      notifyDownloadStateChanged(info); 
      info.setCurrentSize(0); 
      File file = new File(info.getPath()); 
      file.delete(); 
    } 
  } 
   
  public synchronized void install(AppInfo appInfo) { 
    stopDownload(appInfo); 
    DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息 
    if (info != null) {// 发送安装的意图 
      Intent installIntent = new Intent(Intent.ACTION_VIEW); 
      installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      installIntent.setDataAndType(Uri.parse("file://" + info.getPath()), 
          "application/vnd.android.package-archive"); 
      AppUtil.getContext().startActivity(installIntent); 
    } 
    notifyDownloadStateChanged(info); 
  } 
   
  public synchronized void open(AppInfo appInfo) { 
    try { 
      Context context = AppUtil.getContext(); 
      // 获取启动Intent 
      Intent intent = context.getPackageManager() 
          .getLaunchIntentForPackage(appInfo.getPackageName()); 
      context.startActivity(intent); 
    } catch (Exception e) { 
    } 
  } 
   
  private void stopDownload(AppInfo appInfo) { 
    DownloadTask task = mTaskMap.remove(appInfo.getId());// 先从集合中找出下载任务 
    if (task != null) { 
      ThreadManager.getDownloadPool().cancel(task);// 然后从线程池中移除 
    } 
  } 
   
  public synchronized DownloadInfo getDownloadInfo(long id) { 
    return mDownloadMap.get(id); 
  } 
  public synchronized void setDownloadInfo(long id, DownloadInfo info) { 
    mDownloadMap.put(id, info); 
  } 
   
  public class DownloadTask implements Runnable { 
    private DownloadInfo info; 
    public DownloadTask(DownloadInfo info) { 
      this.info = info; 
    } 
    @Override 
    public void run() { 
      info.setDownloadState(STATE_DOWNLOADING);// 先改变下载状态 
      notifyDownloadStateChanged(info); 
      File file = new File(info.getPath());// 获取下载文件 
      HttpResult httpResult = null; 
      InputStream stream = null; 
      if (info.getCurrentSize() == 0 || !file.exists() 
          || file.length() != info.getCurrentSize()) { 
        // 如果文件不存在,或者进度为0,或者进度和文件长度不相符,就需要重新下载 
        info.setCurrentSize(0); 
        file.delete(); 
      } 
      httpResult = HttpHelper.download(info.getUrl()); 
      // else { 
      // // //文件存在且长度和进度相等,采用断点下载 
      // httpResult = HttpHelper.download(info.getUrl() + "&range=" + 
      // info.getCurrentSize()); 
      // } 
      if (httpResult == null 
          || (stream = httpResult.getInputStream()) == null) { 
        info.setDownloadState(STATE_ERROR);// 没有下载内容返回,修改为错误状态 
        notifyDownloadStateChanged(info); 
      } else { 
        try { 
          skipBytesFromStream(stream, info.getCurrentSize()); 
        } catch (Exception e1) { 
          e1.printStackTrace(); 
        } 
        FileOutputStream fos = null; 
        try { 
          fos = new FileOutputStream(file, true); 
          int count = -1; 
          byte[] buffer = new byte[1024]; 
          while (((count = stream.read(buffer)) != -1) 
              && info.getDownloadState() == STATE_DOWNLOADING) { 
            // 每次读取到数据后,都需要判断是否为下载状态,如果不是,下载需要终止,如果是,则刷新进度 
            fos.write(buffer, 0, count); 
            fos.flush(); 
            info.setCurrentSize(info.getCurrentSize() + count); 
            notifyDownloadProgressed(info);// 刷新进度 
          } 
        } catch (Exception e) { 
          info.setDownloadState(STATE_ERROR); 
          notifyDownloadStateChanged(info); 
          info.setCurrentSize(0); 
          file.delete(); 
        } finally { 
          IOUtils.close(fos); 
          if (httpResult != null) { 
            httpResult.close(); 
          } 
        } 
        // 判断进度是否和app总长度相等 
        if (info.getCurrentSize() == info.getAppSize()) { 
          info.setDownloadState(STATE_DOWNLOADED); 
          notifyDownloadStateChanged(info); 
        } else if (info.getDownloadState() == STATE_PAUSED) {// 判断状态 
          notifyDownloadStateChanged(info); 
        } else { 
          info.setDownloadState(STATE_ERROR); 
          notifyDownloadStateChanged(info); 
          info.setCurrentSize(0);// 错误状态需要删除文件 
          file.delete(); 
        } 
      } 
      mTaskMap.remove(info.getId()); 
    } 
  } 
  public interface DownloadObserver { 
    public abstract void onDownloadStateChanged(DownloadInfo info); 
    public abstract void onDownloadProgressed(DownloadInfo info); 
  } 
   
  private long skipBytesFromStream(InputStream inputStream, long n) { 
    long remaining = n; 
    // SKIP_BUFFER_SIZE is used to determine the size of skipBuffer 
    int SKIP_BUFFER_SIZE = 10000; 
    // skipBuffer is initialized in skip(long), if needed. 
    byte[] skipBuffer = null; 
    int nr = 0; 
    if (skipBuffer == null) { 
      skipBuffer = new byte[SKIP_BUFFER_SIZE]; 
    } 
    byte[] localSkipBuffer = skipBuffer; 
    if (n <= 0) { 
      return 0; 
    } 
    while (remaining > 0) { 
      try { 
        long skip = inputStream.skip(10000); 
        nr = inputStream.read(localSkipBuffer, 0, 
            (int) Math.min(SKIP_BUFFER_SIZE, remaining)); 
      } catch (IOException e) { 
        e.printStackTrace(); 
      } 
      if (nr < 0) { 
        break; 
      } 
      remaining -= nr; 
    } 
    return n - remaining; 
  } 
} 

有两点需要说明,关于点击暂停后,再继续下载有两种方式可以实现
第一种 点击暂停的时候 记录下载了 多少,然后 再点击 继续下载 时,告诉服务器, 让服务器接着 上次的数据 往本地传递,
代码是我们 DownloadTask 下载时候,判断一下


// //文件存在且长度和进度相等,采用断点下载 
      httpResult = HttpHelper.download(info.getUrl() + "&range=" + info.getCurrentSize()); 

通过 range 来区分 当前的下载size.
服务器 处理的代码 也很简单 就是一句话
String range = req.getParameter(“range”); 拿到 range 判断 range 存在不存在。
如果不存在


FileInputStream stream = new FileInputStream(file); 
     int count = -1; 
     byte[] buffer = new byte[1024]; 
     while ((count = stream.read(buffer)) != -1) { 
       SystemClock.sleep(20); 
       out.write(buffer, 0, count); 
       out.flush(); 
     } 
     stream.close(); 
     out.close(); 

如果存在那么跳过range 个字节



RandomAccessFile raf = new RandomAccessFile(file, "r"); 
      raf.seek(Long.valueOf(range));  
      int count = -1; 
      byte[] buffer = new byte[1024]; 
      while ((count = raf.read(buffer)) != -1) { 
        SystemClock.sleep(10); 
        out.write(buffer, 0, count); 
        out.flush(); 
      } 
      raf.close(); 
      out.close(); 

另一种方式是本地处理,这个demo 中就是本地处理的, 但是有一个问题, 因为 Java api的原因 ,inputStream.skip() 方法 并不能准确的 跳过多少个字节,
而是 小于你想要跳过的字节,所以 你要去遍历 一直到 满足你要跳过的字节 在继续写, 因为 这样的方法有一个缺点,就是在下载很大的文件,
比如文件大小20M ,当已经下载了15M 此时你去暂停,在继续下载,那么要跳过前面的15M 将会话费很多时间。

此实现方式还有很多缺陷,所以在实际中要下载大的文件,还是不能用。

--------------------------------------------------------------------- 改进版-------------------------------------------------------------------------------

先来介绍下这次改进的两点:

 第一点 ,前面说过 项目 只适合学习,作为商用的话, 效率不高,是因为当时点击暂停 ,在点击下载继续下载时候,如果文件前面下载部分较大,会比较慢,因为java 的 inputstream的 skip(longsize) 跳过字节 这个方法 并不能按照你 想要跳过的字节,而是跳过的往往是比较小的,所以要不断遍历,直到返回满足条件 ,比较耗时。打个比方,文件大小30M ,你下载了20M,你点了暂停然后继续点下载,就要跳过这20M,但是你用skip 方法 可能每次跳过4096 字节,这样要跳过20M的时间 就会很长。这样应该好理解。
第二点,原来 项目中,你这一次下载没有完成,下次在下载是删除掉原来的从新 下载,这次改成继续上次的地方接着下载。
吐槽下,关于下载,我最近一周 一直在看 开源的download, 但是 无奈水平有限,收获甚微,往往是看到最后 脑袋短路。大哭
这次改的方式比较简单,只改动了 项目中 DownloadManager 这个类。在来看下 DownloadManager这个类 的run 方法,
   


@Override 
    public void run() { 
      info.setDownloadState(STATE_DOWNLOADING);// 先改变下载状态 
      notifyDownloadStateChanged(info); 
      File file = new File(info.getPath());// 获取下载文件 
      HttpResult httpResult = null; 
      InputStream stream = null; 
      if (info.getCurrentSize() == 0 || !file.exists() 
          || file.length() != info.getCurrentSize()) { 
        // 如果文件不存在,或者进度为0,或者进度和文件长度不相符,就需要重新下载 
<span>        </span>info.setCurrentSize(0); 
        file.delete(); 
      } 
      httpResult = HttpHelper.download(info.getUrl()); 
      if (httpResult == null 
          || (stream = httpResult.getInputStream()) == null) { 
        info.setDownloadState(STATE_ERROR);// 没有下载内容返回,修改为错误状态 
        notifyDownloadStateChanged(info); 
      } else { 
        try { 
          skipBytesFromStream(stream, info.getCurrentSize()); 
        } catch (Exception e1) { 
          e1.printStackTrace(); 
        } 
        FileOutputStream fos = null; 
        try { 
          fos = new FileOutputStream(file, true); 
          int count = -1; 
          byte[] buffer = new byte[1024]; 
          while (((count = stream.read(buffer)) != -1) 
              && info.getDownloadState() == STATE_DOWNLOADING) { 
            // 每次读取到数据后,都需要判断是否为下载状态,如果不是,下载需要终止,如果是,则刷新进度 
            fos.write(buffer, 0, count); 
            fos.flush(); 
            info.setCurrentSize(info.getCurrentSize() + count); 
            notifyDownloadProgressed(info);// 刷新进度 
          } 
        } catch (Exception e) { 
          info.setDownloadState(STATE_ERROR); 
          notifyDownloadStateChanged(info); 
          info.setCurrentSize(0); 
          file.delete(); 
        } finally { 
          IOUtils.close(fos); 
          if (httpResult != null) { 
            httpResult.close(); 
          } 
        } 
<span>        </span>// 判断进度是否和app总长度相等 
        if (info.getCurrentSize() == info.getAppSize()) { 
          info.setDownloadState(STATE_DOWNLOADED); 
          notifyDownloadStateChanged(info); 
        } else if (info.getDownloadState() == STATE_PAUSED) {// 判断状态 
          notifyDownloadStateChanged(info); 
        } else { 
          info.setDownloadState(STATE_ERROR); 
          notifyDownloadStateChanged(info); 
          info.setCurrentSize(0);// 错误状态需要删除文件 
          file.delete(); 
        } 
      } 
      mTaskMap.remove(info.getId()); 
    } 

从服务器 返回的数据流  stream  最终是在 HttpHelper 这个类中 


HttpResponse response = httpClient.execute(requestBase, httpContext);//访问网络 

通过  httpclient 去联网请求的  。
我没有试过 httpclient    addHeader("Range", "bytes=" + begin + "-" + end); 可不可以进行继续下载。
而是改成了 通过 httpurlconnection 去请求数据
现在  的run()方法是这样的。
   


@Override 
    public void run() { 
      info.setDownloadState(STATE_DOWNLOADING);// 先改变下载状态 
      notifyDownloadStateChanged(info); 
      File file = new File(info.getPath());// 获取下载文件 
       
//     try { 
        try { 
          URL url = new URL(info.getUrl()); 
          HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
          conn.setRequestMethod("GET"); 
          conn.setConnectTimeout(30000); 
          conn.setReadTimeout(30000); 
          if (!file.exists()) { 
            info.setCurrentSize(0); 
            file.delete(); 
          } else if (file.length() > info.getAppSize()) { 
            info.setCurrentSize(0); 
            file.delete(); 
          } else if (file.length() == info.getAppSize()) { 
          } else if (file.length() < info.getAppSize()) { 
            info.setCurrentSize(file.length()); 
          } 
          if (info.getCurrentSize() == 0 || !file.exists() || file.length() != info.getCurrentSize()) { 
            // 如果文件不存在,或者进度为0,或者进度和文件长度不相符,就需要重新下载 
            info.setCurrentSize(0); 
            file.delete(); 
          } else if (file.length() == info.getCurrentSize() && file.length() < info.getAppSize()) { 
            conn.setRequestProperty("Range", "bytes=" + info.getCurrentSize() + "-" + info.getAppSize()); 
          } 
          int code = conn.getResponseCode(); 
          RandomAccessFile raf = new RandomAccessFile(file, "rw"); 
          InputStream is = conn.getInputStream(); 
          byte[] buffer = new byte[1024 * 8]; 
          int len = -1; 
          int total = 0;// 当前线程下载的总的数据的长度 
          if (code == 200) { 
          } else if (code == 206) { 
            raf.seek(file.length()); 
          } 
          while (((len = is.read(buffer)) != -1) && (info.getDownloadState() == STATE_DOWNLOADING)) { // 下载数据的过程。 
            raf.write(buffer, 0, len); 
            total += len;// 需要记录当前的数据。 
            info.setCurrentSize(info.getCurrentSize() + len); 
            notifyDownloadProgressed(info);// 刷新进度 
          } 
          is.close(); 
          raf.close(); 
        } catch (MalformedURLException e) { 
          // TODO Auto-generated catch block 
          e.printStackTrace(); 
        } catch (ProtocolException e) { 
          // TODO Auto-generated catch block 
          e.printStackTrace(); 
        } catch (FileNotFoundException e) { 
          // TODO Auto-generated catch block 
          e.printStackTrace(); 
        } catch (IOException e) { 
          // TODO Auto-generated catch block 
          e.printStackTrace(); 
        } 
         
        // 判断进度是否和app总长度相等 
//     } catch (Exception e) { 
//       System.out.println(e.toString()); 
//       info.setDownloadState(STATE_ERROR); 
//       info.setCurrentSize(0); 
//       file.delete(); 
//       e.printStackTrace(); 
//     } 
      if (info.getCurrentSize() == info.getAppSize()) { 
        info.setDownloadState(STATE_DOWNLOADED); 
        notifyDownloadStateChanged(info); 
      } else if (info.getDownloadState() == STATE_PAUSED) {// 判断状态 
        notifyDownloadStateChanged(info); 
      } else { 
        info.setDownloadState(STATE_ERROR); 
        notifyDownloadStateChanged(info); 
        info.setCurrentSize(0);// 错误状态需要删除文件 
        file.delete(); 
      } 
       
      mTaskMap.remove(info.getId()); 
    } 

先判断文件存不存在,以及大小是否满足条件, 在这里做判断


if (info.getCurrentSize() == 0 || !file.exists() || file.length() != info.getCurrentSize()) { 
  // 如果文件不存在,或者进度为0,或者进度和文件长度不相符,就需要重新下载 
  info.setCurrentSize(0); 
  file.delete(); 
  } else if (file.length() == info.getCurrentSize() && file.length() < info.getAppSize()) { 
     conn.setRequestProperty("Range", "bytes=" + info.getCurrentSize() + "-" + info.getAppSize()); 
   } 

如果 文件当前大小为0,或者文件不存在,或者长度不等于当前长度,则重新下载,否则 设置 Range
下面 判断 code  正常情况下code =200 表示成功,如果 设置了Range  那么 code 返回 206 表示正常。这个时候我们通过RandomAccessFile
RandomAccessFile  这个 类实现了 RandomAccessFile implements DataInput, DataOutput,就是一个既可以读也可以写的类。
RandomAccessFile 这个类来 处理 跳过多少字节, 前面 我说过 inpuStream.skeep() 方法 不准确,但是  RandomAccessFile  这个类是可以的。



RandomAccessFile raf = new RandomAccessFile(file, "rw"); 
InputStream is = conn.getInputStream(); 
byte[] buffer = new byte[1024 * 8]; 
int len = -1; 
int total = 0;// 当前线程下载的总的数据的长度 
if (code == 200) { 
} else if (code == 206) { 
raf.seek(file.length()); 
} 

通过 seek 方法 跳过 这些字节。
然后


while (((len = is.read(buffer)) != -1) && (info.getDownloadState() == STATE_DOWNLOADING)) { // 下载数据的过程。 
raf.write(buffer, 0, len); 
total += len;// 需要记录当前的数据。 
info.setCurrentSize(info.getCurrentSize() + len); 
notifyDownloadProgressed(info);// 刷新进度 
} 
is.close(); 
raf.close(); 

很普通的代码,把数据写出去。不断刷新当前进度, 最后关闭流。
这样就可以保证快速的暂停继续下载,并且 本次下载 没有完成,点了暂停,下次进应用,继续下载的时候 会接着上一次下载,但是断网,或者你自己把网关掉 ,下次在恢复网络,或者 在点下载,我并没有处理,有需要的就自己处理下吧,应该是捕获异常 seckouttimeException,然后保存数据。自己动手试下就知道了。

本次就到这里,希望对大家学习Android版多线程下载 仿下载助手(最新)有所启发。

您可能感兴趣的文章:android中多线程下载实例android实现多线程下载文件(支持暂停、取消、断点续传)Android实现多线程下载文件的方法Android编程开发实现带进度条和百分比的多线程下载Android FTP 多线程断点续传下载\上传的实例Android多线程+单线程+断点续传+进度条显示下载功能Android多线程断点续传下载功能实现代码Android实现多线程断点下载的方法Android实现多线程下载图片的方法Android线程池控制并发数多线程下载


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android版多线程下载 仿下载助手(最新)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android版多线程下载 仿下载助手(最新)

首先声明一点: 这里的多线程下载并不是指多个线程下载一个 文件,而是每个线程负责一个文件,今天给大家分享一个多线程下载的 例子。先看一下效果,点击下载开始下载,同时显示下载进度,下载完成,变成程安装,点击安装提示安装应用。 界面效果图:线程
2022-06-06

2014win7最新系统下载 最新win7旗舰版下载图文教程

本系统为Windows 7旗舰版,默认已激活。个别电脑出现未激活的请自行运行桌面上的激活工具即可激活。最新win7旗舰版系统下载:http://xt.xpxitong.net/windows7/(个人使用推荐) 一、主要更新:* 更新了系统
2023-06-06

PC版与Android手机版带断点续传的多线程下载

一、多线程下载 多线程下载就是抢占服务器资源 原理:服务器CPU 分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服务器资源。 1、设置开启线程数,
2022-06-06

android中多线程下载实例

代码如下: public class MainActivity extends Activity { // 声明控件 // 路径与线程数量 private EditText et_url, et_num; // 进度条 public sta
2022-06-06

Android 仿硅谷新闻下拉刷新/上拉加载更多

1.添加加载更多布局 1_初始化和隐藏代码 在RefreshListView构造方法中调用private void initFooterView(Context context) { View footerView = View.infla
2022-06-06

Android的HTTP多线程下载示例代码

本示例介绍在Android平台下通过HTTP协议实现断点续传下载。 多线程断点需要的功能1.多线程下载,2.支持断点。使用多线程的好处:使用多线程下载会提升文件下载的速度。多线程下载文件的过程是: (1)首先获得下载文件的长度,然后设置本地
2022-06-06

详解Android中的多线程断点下载

首先来看一下多线程下载的原理。多线程下载就是将同一个网络上的原始文件根据线程个数分成均等份,然后每个单独的线程下载对应的一部分,然后再将下载好的文件按照原始文件的顺序“拼接”起来就构 成了完整的文件了。这样就大大提高了文件的下载效率。对于文
2022-06-06

Android实现网络多线程文件下载

实现原理(1)首先获得下载文件的长度,然后设置本地文件的长度。(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示:(网上找的
2022-06-06

Android使用多线程实现断点下载

多线程下载是加快下载速度的一种方式,通过开启多个线程去执行一个任务..可以使任务的执行速度变快..多线程的任务下载时常都会使用得到..比如说我们手机内部应用宝的下载机制..一定是通过使用了多线程创建的下载器..并且这个下载器可以实现断点下载
2022-06-06

MySQL数据库下载及安装教程(最最新版)

MySQL数据库下载及安装教程(最最新版) 一、下载mysql数据库二、安装Mysql三、验证是否安装成功(一)、命令提示符cmd窗口验证(二)、MySQL控制台验证 一、下载mysql数据库 进入MySQL官方网站(htt
2023-08-16

android使用AsyncTask实现多线程下载实例

AsyncTask不仅方便我们在子线程中对UI进行更新操作,还可以借助其本身的线程池来实现多线程任务。下面是一个使用AsyncTask来实现的多线程下载例子。 01 效果图02 核心类 - DownloadTask.classpublic
2022-06-06

Android实现多线程下载文件的方法

本文实例讲述了Android实现多线程下载文件的方法。分享给大家供大家参考。具体如下: 多线程下载大概思路就是通过Range 属性实现文件分段,然后用RandomAccessFile 来读写文件,最终合并为一个文件 首先看下效果图:创建工程
2022-06-06

Android实现多线程下载图片的方法

很多时候我们需要在Android设备上下载远程服务器上的图片进行显示,今天整理出两种比较好的方法来实现远程图片的下载。 方法一、直接通过Android提供的Http类访问远程服务器,这里AndroidHttpClient是SDK 2.2中新
2022-06-06

Android实现多线程断点下载的方法

本文实例讲述了Android实现多线程断点下载的方法。分享给大家供大家参考。具体实现方法如下:package cn.itcast.download; import java.io.File; import java.io.FileInp
2022-06-06

Mysql最新版8.0.21下载安装配置教程详解

一、下载 1、下载安装包 mysql下载路径:https://dev.mysql.com/downloads/file/id=4967452、解压压缩包 解压到安装的目录:3、在此目录下新建my.ini配置文件[mysqld] # 设置
2022-05-20

Android使用AsyncTask实现多线程下载的方法

本文实例讲述了Android使用AsyncTask实现多线程下载的方法。分享给大家供大家参考,具体如下:public class MainActivity extends Activity implements OnClickListene
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录