zoukankan      html  css  js  c++  java
  • 毕业设计:下载

    一、主要思路

            访问网络资源并且下载下来的功能是通过OkHttp来实现的,具体操作在之前的文章中有。最麻烦的是各组件之间的交互问题。例如,我设置一个存放线程的列表,每建立一个下载事项就新建一个对应线程,并将其放到下载列表中,然后线程会自动执行到文件下载完毕。现在问题来了,我需要将下载进程实时反馈到“任务”面板上,并且还要能通过“任务”面板上的暂停/开始按钮操作线程,这怎么实现?

            似乎能想到的唯一办法就是通过Handler实现。我在主线程里面定义一个Handler,初始化的时候改变这个Handler的handleMessage()方法,让它每接收到一个值为1的Message就致使adapter执行notifyDataSetChanged()方法。当然这里的这个adapter是和“任务”面板的listView绑定起来的。然后我想方设法地把这个handler通过参数传递到线程列表的Thread对象里面,然后每当Thread执行的进度发生变化(也就是progress向前推进),就通过这个handler发送一个值为1的Message,于是这两者就关联起来了。至于暂停/开始按钮的点击事件,是在adapter的getView()方法写好的,一旦触发就会去找线程列表,找到对应的线程并执行暂停/开始操作。

    二、线程和线程的死锁问题

            因为原来的suspend()方法和stop()方法容易导致死锁,所以在这个版本被废弃了,想要实现类似的功能只能自己通过设置标志位、wait()方法和synchronized来实现。

            如代码中所示,resume(),suspend(),和stop()方法都只是修改运行状态(status)。在run()方法中,首先判断是否为stop,如果为假则再判断是否为suspend,如果为真则执行wait()方法给其他线程让路,如果为假则执行所需执行的内容。方法本身是不复杂的,我为了给程序添加对应的功能让其看起来有些复杂。

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    import android.os.Environment;
    import android.os.Handler;
    import android.os.Message;
    
    import com.example.vcloud_3_25.MainActivity;
    import com.example.vcloud_3_25.utils.L;
    import com.example.vcloud_3_25.utils.TaskManager;
    
    public class DownloadThread implements Runnable {
        public static final int STOP = -1;
        public static final int SUSPEND = 0;
        public static final int RUNNING = 1;
        protected int status = 1;
        private String name;
        private String fileName;
        private int fileId;
        private int progress;
        private String fileType;
        
        private Handler mHandler;//
    
        private MainActivity activity;
    
        public DownloadThread(MainActivity context,Handler handler, String fileName, int fileId,String fileType) {
            this.mHandler = handler;
            
            this.activity = context;
    
            TaskManager.count++;
            this.name = "DownloadThread-" + TaskManager.count;
    
            this.fileId = fileId;
            this.fileName = fileName;
            this.fileType = fileType;
    
            progress = 0;
        }
    
        public String getFileType(){
            return this.fileType;
        }
        public int getProgress() {
            return progress;
        }
    
        public String getName() {
            return name;
        }
    
        public String getFileName() {
            return fileName;
        }
    
        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
    
        public int getFileId() {
            return fileId;
        }
    
        public void setFileId(int fileId) {
            this.fileId = fileId;
        }
    
        @Override
        public boolean equals(Object o) {
            DownloadThread t2 = (DownloadThread) o;
            return t2.getName() == this.getName();
        }
    
        @Override
        public void run() {
    
            OkHttpClient client = new OkHttpClient();
            final Request request = new Request.Builder().url(
                    "http://192.168.23.1:8080/VCloud/files/" + fileId).build();
            Call call = client.newCall(request);
            call.enqueue(new Callback() {
    
                @Override
                public void onResponse(Call call, Response response) {
                    L.d("on response");
                    long sum = 0;
                    long total;
                    int len = 0;
    
                    InputStream is = response.body().byteStream();
    
                    try {
                        total = response.body().contentLength();
    
                        File file = new File(Environment
                                .getExternalStorageDirectory(), "VcloudDownload/"
                                + fileName);
                        byte[] buf = new byte[128];
                        FileOutputStream fos = new FileOutputStream(file);
    
                        L.d("start download");
                        while (status != STOP & (len = is.read(buf)) != -1) {
                            if (status == SUSPEND) {
                                try {
                                    synchronized (this) {
                                        wait(500);
                                    }
    
                                } catch (InterruptedException e) {
                                    L.d(e.getMessage());
                                }
                            } else {
    
                                fos.write(buf, 0, len);
                                sum += len;
                                double temp = sum / (double) total;
                                int recentProgress = (int) (temp * 100);
                                if (recentProgress != progress) {
                                    progress = recentProgress;
                                    L.d("sum:" + sum + ",  progress:" + progress);
                                    Message msg = mHandler.obtainMessage(1);
                                    mHandler.sendMessage(msg);
    
                                }
    
                            }
                        }
    
                        fos.flush();
                        fos.close();
                        is.close();
    
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                        L.d(ioe.getMessage());
                    }
    
                    L.d("download success!");
                    progress = 100;
                    mHandler.sendMessage(mHandler.obtainMessage(1));
                }
    
                @Override
                public void onFailure(Call call, IOException e) {
                    L.d("enqueue failure!");
                    L.d(e.getMessage());
                }
            });
    
        }
    
        public synchronized void resume() {
            status = RUNNING;
            notifyAll();
            L.d("Thread " + name + "resume!");
        }
    
        public void suspend() {
            status = SUSPEND;
            L.d("Thread " + name + "suspend!");
        }
    
        public void stop() {
            status = STOP;
            L.d("Thread " + name + "stop!");
        }
    
    }

    三、DownloadListAdapter

            这个ListViewAdapter比较特殊,它需要一个List<DownloadThread>来构造,而这个List就是从主线程里面传过来的。它里面的item和List里面的Thread是一一对应的,因此不仅数据随时同步(通过notifyDataSetChanged就能实现),而且对按钮绑定监听器也能直接对每一个线程进行控制。

            ViewHolder其实是比较难理解的一个东西。之前我使用的adapter是直接继承自SimpleAdapter所以没有使用到这个方法。根据我的理解,holder应该是一个指向ListView中item的指针,每次新增加一个item这个指针就会指向新增加的item,所以对holder中的成员操作实际就是对item中的成员操作。值得注意的是,对button设置监听器的时候,对button的操作一定是要基于onClick(View v)中的v,而不是holder.button,否则不管触发的是哪个item的button,都只会有最后一个item作出反应。

    package com.example.vcloud_3_25.utils;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import thread.DownloadThread;
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    import com.example.vcloud_3_25.MainActivity;
    import com.example.vcloud_3_25.R;
    
    public class DownloadListAdapter extends BaseAdapter {
    
        private List<DownloadThread> mList;
        private MainActivity context;
        private ViewHolder holder = null;
    
        public DownloadListAdapter(MainActivity context) {
            this.mList = context.mTaskManager.mDownList;
            this.context = context;
        }
    
        @Override
        public int getCount() {
            return mList.size();
        }
    
        @Override
        public Object getItem(int position) {
            return mList.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = convertView;
            if (view == null) {
                LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.task_item, parent, false);
    
                holder = new ViewHolder();
                holder.fileName = (TextView) view
                        .findViewById(R.id.textView_taskName);
                holder.fileImag = (ImageView) view.findViewById(R.id.imag_task);
                holder.progressBar = (ProgressBar) view
                        .findViewById(R.id.progressBar_task);
                holder.progressCount = (TextView) view
                        .findViewById(R.id.textView_progress);
                holder.button = (Button) view.findViewById(R.id.button_task);
                holder.complete = (TextView) view
                        .findViewById(R.id.textView_complete);
    
                view.setTag(holder);
    
            } else {
                holder = (ViewHolder) view.getTag();
            }
    
            final DownloadThread thread = (DownloadThread) getItem(position);
            if (thread != null) {
                holder.fileName.setText(thread.getFileName());
                holder.fileImag.setImageResource(FileHelper.getFileImag("other"));
                holder.progressBar.setProgress(thread.getProgress());
                holder.fileImag.setImageResource(FileHelper.getFileImag(thread
                        .getFileType()));
                holder.progressBar.setMax(100);
                holder.progressCount.setText(thread.getProgress() + "%");
                holder.button.setOnClickListener(new OnClickListener() {
    
                    @Override
                    public void onClick(View v) {
                        if (((TextView) v).getText().equals("暂停")) {
                            ((TextView) v).setText("开始");
    
                            // 暂停该线程
                            thread.suspend();
                        } else {
                            ((TextView) v).setText("暂停");
    
                            // 继续执行该线程
                            thread.resume();
                        }
                    }
                });
                if (thread.getProgress() == 100) {
                    holder.button.setVisibility(View.INVISIBLE);
                    holder.complete.setVisibility(View.VISIBLE);
                }
            }
    
            return view;
        }
    
        public class ViewHolder {
            public TextView fileName;
            public ImageView fileImag;
            public ProgressBar progressBar;
            public TextView progressCount;
            public Button button;
            public TextView complete;
        }
    }

    四、TaskManager

            TaskManager其实是一个管理所有任务的类,所以添加线程到下载列表之类的操作都是基于这个类实现的。目前还在实现上传功能,所以给上传列表留了一个空。

    package com.example.vcloud_3_25.utils;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import thread.DownloadThread;
    import thread.UploadThread;
    
    import com.example.vcloud_3_25.MainActivity;
    
    public class TaskManager {
        public List<DownloadThread> mDownList;
        public List<UploadThread> mUpList;
        private MainActivity context;
        public static int count = 0;
    
        public TaskManager(MainActivity activity) {
            context = activity;
            init();
        }
    
        public void init() {
            mDownList = new ArrayList<DownloadThread>();
            mUpList = new ArrayList<UploadThread>();
        }
    }

    五、MainActivity

            核心方法都说过了,所以只贴Handler的部分。

    public Handler mHandler;
    mHandler = new Handler(){
    
        @Override
        public void handleMessage(Message msg) {
            if(msg.what==1){
                downloadAdapter.notifyDataSetChanged();
            }
        }
                
    };

    六、手机如何访问电脑上的Tomcat

    电脑端下载一个免费WIFI,我使用的是腾讯管家的。打开免费WIFI,让手机连到这个网上,至此手机和电脑就连到同个局域网了。打开电脑的网络管理能看到这个局域网中电脑的IP,例如我的电脑端是192.168.23.1,而手机端是192.168.23.2。打开服务器,手机端访问192.168.23.1:8080,如果出现tomcat欢迎页面即成功。

    如果电脑能访问到tomcat页面而手机端不能,多半是电脑防火墙的问题,关了它。

    如果电脑端都不能访问,多半是tomcat配置出错了,最好的方法是重新解压重新绑定到Eclipse。

  • 相关阅读:
    算法学习记录-排序——快速排序
    算法学习记录-排序——归并排序
    算法学习记录-排序——堆排序
    算法学习记录-排序——希尔排序
    算法学习记录-排序——插入排序(Insertion Sort)
    Windows 10 安装 Vim
    Flash Basics
    NVMe
    vim usage tips
    Mac OS Terminal Commands 02
  • 原文地址:https://www.cnblogs.com/viaduct/p/6722632.html
Copyright © 2011-2022 走看看