android学习笔记----网页源码查看器,图片查看器

2023-05-06 18:57:31 浏览数 (1)

handler使用步骤  1.在主线程定义了一个Handler  private Handler handler = new Handler()  2.使用handler会重写handler里面的handlerMessage方法  public void handlerMessage(Message msg){}  3.拿着我们在主线程创建的handler去子线程发消息  handler.sendMessage(msg);  4.handlerMessage方法就会执行,在这个方法里面去更新ui

源码解读 Android 消息机制(Message MessageQueue Handler Looper)看这里:

https://blog.csdn.net/u011240877/article/details/72892321

网页源码查看器:

以下是使用handler实现,AsyncTask实现的请见这里:https://github.com/liuchenyang0515/webcv_AsyncTask

MainActivity.java

代码语言:javascript复制
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;


public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private EditText et_path;
    private TextView tv_result;

    private Handler handler = new Handler() {
        // 这个方法是在主线程里面执行的
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            // 所以就可以在主线程里面更新ui了
            // 1.区分一下发送的是哪条消息
            switch (msg.what) {
                case REQUESTSUCESS:
                    String content = (String) msg.obj;
                    tv_result.setText(content);
                    break;
                case REQUESTNOTFOUND:
                    Toast.makeText(MainActivity.this, "请求资源不存在", Toast.LENGTH_SHORT).show();
                    break;
                case REQUESTEXCEPTION:
                    Toast.makeText(MainActivity.this, "服务器忙,请稍候访问", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };
    private static final int REQUESTSUCESS = 0; // ctrl shift U切换大小写
    private static final int REQUESTNOTFOUND = 1; // 请求失败
    private static final int REQUESTEXCEPTION = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_path = (EditText) findViewById(R.id.et_path);
        tv_result = (TextView) findViewById(R.id.tv_result);
    }

    // 不能在主线程进行耗时的操作,比如连接网络,拷贝大数据,睡眠等操作。
    // 连接谷歌网络。warning:java.net.SocketTimeoutException: connect timed out
    // 只要主线程超时 info:The application may be doing too much work on its main thread.
    // 在4.0之后谷歌强制要求连接网络不能在主线程进行访问
    // 只有主线程(UI线程)才可以更新UI
    // 2.点击按钮进行查看,指定路径的源码
    public void click(View v) {
        // 只要不new Thread,全都属于主线程
        new Thread() {
            public void run() {
                try {
                    // 2.1获取源码路径
                    String path = et_path.getText().toString().trim();
                    // 2.2创建URL对象,指定我们要访问的网址(路径)
                    URL url = new URL(path);
                    // 2.3拿到httpurlconnection对象,用于发送或者接收数据
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    // 2.4设置发送get请求
                    conn.setRequestMethod("GET"); // get要求大写,默认是get请求
                    // 2.5设置请求超时时间
                    conn.setConnectTimeout(5000);
                    // 2.6获取服务器返回的状态码
                    int code = 0;
                    code = conn.getResponseCode();
                    // 2.7如果code==200说明请求成功
                    Log.d(TAG, code   "====================================");
                    if (code == 200) {
                        // 2.8获取服务器返回的数据,是以流的形式返回的,由于把流转换成字符串是很常见的操作
                        // 所以抽出一个工具类Utils
                        InputStream in = conn.getInputStream();
                        // 2.9使用定义的工具类把in转换城String
                        final String content = StreamTools.readStream(in);
                        // 2.9.0创建message对象
                        /*runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                tv_result.setText(content);
                            }
                        });*/

                        Message msg = Message.obtain();// 使用msg的静态方法可以减少对象的创建
                        msg.what = REQUESTSUCESS;
                        msg.obj = content;
                        // 2.9.1拿着我们创建的handler(助手) 告诉系统,我要更新ui
                        handler.sendMessage(msg);
                        // 发了一条消息,消息(msg)里把数据放到了msg里
                        // 接着handleMessage方法就会执行
                        /*// 更新UI的逻辑,写在这里会报错
                        tv_result.setText(content);*/
                    } else {
                        // 请求资源不存在  Toast就是一个view,相当于更新UI,不能在子线程更新UI,不能在子线程直接使用Toast
                        /*runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(MainActivity.this, "请求资源不存在", Toast.LENGTH_SHORT).show();
                            }
                        });*/
                        Message msg = Message.obtain();
                        msg.what = REQUESTNOTFOUND; // 代表哪条消息
                        handler.sendMessage(msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    /*runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "服务器忙,请稍候访问", Toast.LENGTH_SHORT).show();
                        }
                    });*/
                    Message msg = Message.obtain();
                    msg.what = REQUESTEXCEPTION; // 代表哪条消息
                    handler.sendMessage(msg);
                }
            }
        }.start();
    }
}

运行效果:

这里点击“查看”时为什么要选择另外开启一个线程?因为getResponseCode()会报错

handler的作用是用来发消息和处理消息的 Looper的作用是去消息队列里面取消息 Looper是在主线程一创建Looper就有了

还有一点:

A toast is a view containing a quick little message for the user.

Toast就是一个view,相当于更新UI,不能在子线程更新UI,不能在子线程直接使用Toast

不管什么版本的手机,只要做耗时的操作(比如连接网络、拷贝大的数据等)就自己开一个子线程,获取数据后想要更新UI,就使用Handler就行。

如果仅仅只是更新UI,那么用runOnUiThread就可以了。这是一个在android.app包下的Activity类里面的方法

public final void runOnUiThread (Runnable action)

       在UI线程上运行指定的操作。如果当前线程是UI线程,则立即执行该操作。如果当前线程不是UI线程,则将操作发布到UI线程的事件队列。

那Handler没用了吗?不是,有时候是可以通过Handler发送消息,携带数据这个时候就必须使用Handler了。

用runOnUiThread操作如下,可以达到一样的效果。

代码语言:javascript复制
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private EditText et_path;
    private TextView tv_result;
    
    private static final int REQUESTSUCESS = 0; // ctrl shift U切换大小写
    private static final int REQUESTNOTFOUND = 1; // 请求失败
    private static final int REQUESTEXCEPTION = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_path = (EditText) findViewById(R.id.et_path);
        tv_result = (TextView) findViewById(R.id.tv_result);
    }


    public void click(View v) {
        // 只要不new Thread,全都属于主线程
        new Thread() {
            public void run() {
                try {
                    // 2.1获取源码路径
                    String path = et_path.getText().toString().trim();
                    // 2.2创建URL对象,指定我们要访问的网址(路径)
                    URL url = new URL(path);
                    // 2.3拿到httpurlconnection对象,用于发送或者接收数据
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    // 2.4设置发送get请求
                    conn.setRequestMethod("GET"); // get要求大写,默认是get请求
                    // 2.5设置请求超时时间
                    conn.setConnectTimeout(5000);
                    // 2.6获取服务器返回的状态码
                    int code = 0;
                    code = conn.getResponseCode();
                    // 2.7如果code==200说明请求成功
                    Log.d(TAG, code   "====================================");
                    if (code == 200) {
                        // 2.8获取服务器返回的数据,是以流的形式返回的,由于把流转换成字符串是很常见的操作
                        // 所以抽出一个工具类Utils
                        InputStream in = conn.getInputStream();
                        // 2.9使用定义的工具类把in转换城String
                        final String content = StreamTools.readStream(in);
                        // 2.9.0创建message对象
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                tv_result.setText(content);
                            }
                        });
                    } else {
                        // 请求资源不存在  Toast就是一个view,相当于更新UI,不能在子线程更新UI,不能在子线程直接使用Toast
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(MainActivity.this, "请求资源不存在", Toast.LENGTH_SHORT).show();
                            }
                        });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "服务器忙,请稍候访问", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        }.start();
    }
}

图片查看器:

代码语言:javascript复制
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private EditText et_path;
    private ImageView iv;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Bitmap bitmap = (Bitmap) msg.obj;
            iv.setImageBitmap(bitmap);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 1.找到我们关心的控件
        et_path = (EditText) findViewById(R.id.et_path);
        iv = (ImageView) findViewById(R.id.iv);
    }

    // 2.点击按钮进行查看指定路径的图片
    public void click(View view) {
        new Thread() {
            @Override
            public void run() {
                try {
                    // 2.1获取图片路径
                    String path = et_path.getText().toString().trim();
                    // path不变,Base64加密写出的file路径,也就是改一下文件名字
                    File file = new File(getCacheDir(), Base64.encodeToString(path.getBytes(), Base64.DEFAULT));
                    Log.d(TAG, file.toString());// 可以看到全路径名,写出的file名已经加密
                    if (file.exists() && file.length() > 0) {
                        // 使用缓存的图片
                        Log.d(TAG, "使用缓存图片");
                        Bitmap cacheBitmap = BitmapFactory.decodeFile(file.getCanonicalPath());
                        // 把cacheBitmap显示到iv上
                        Message msg = Message.obtain();
                        msg.obj = cacheBitmap;
                        handler.sendMessage(msg);
                    } else {
                        Log.d(TAG, "第一次连接网络");
                        // 2.2创建URL对象
                        URL url = new URL(path);
                        // 2.3获取httpurlconnection
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        // 2.4设置请求的方式
                        conn.setRequestMethod("GET");
                        // 2.5设置超时时间
                        conn.setConnectTimeout(5000);
                        // 2.6获取服务器返回的状态码
                        int code = conn.getResponseCode();
                        if (code == 200) {
                            // 2.7获取图片的数据,不管是什么数据(txt文本 图片数据)都是以流的形式返回
                            InputStream in = conn.getInputStream();
                            // 2.7.1缓存图片,谷歌提供了缓存目录
                            BufferedInputStream bis = new BufferedInputStream(in);
                            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
                            int len = -1;
                            byte[] buf = new byte[8192];
                            while ((len = bis.read(buf, 0, 8192)) != -1) {
                                bos.write(buf, 0, len);
                            }
                            bis.close();
                            bos.close();
                            // 2.8通过位图工厂获取bitmap
                            //Bitmap bitmap = BitmapFactory.decodeStream(in);
                            Bitmap bitmap = BitmapFactory.decodeFile(file.getCanonicalPath());
                            // 2.9把bitmap显示到iv上
                            // 使用msg的静态方法可以减少对象的创建
                            Message msg = Message.obtain();
                            msg.obj = bitmap;
                            handler.sendMessage(msg);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

activity_main.xml

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@ id/et_path"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click"
        android:text="查看" />

    <ImageView
        android:id="@ id/iv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

运行结果:

关于cache和files目录的区别可以看这里:

https://blog.csdn.net/hxqneuq2012/article/details/53128572

用runOnUiThread操作如下,可以达到一样的效果。

代码语言:javascript复制
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private EditText et_path;
    private ImageView iv;
/*    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Bitmap bitmap = (Bitmap) msg.obj;
            iv.setImageBitmap(bitmap);
        }
    };*/

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 1.找到我们关心的控件
        et_path = (EditText) findViewById(R.id.et_path);
        iv = (ImageView) findViewById(R.id.iv);
    }

    // 2.点击按钮进行查看指定路径的图片
    public void click(View view) {
        new Thread() {
            @Override
            public void run() {
                try {
                    // 2.1获取图片路径
                    String path = et_path.getText().toString().trim();
                    // path不变,Base64加密写出的file路径,也就是改一下文件名字
                    File file = new File(getCacheDir(), Base64.encodeToString(path.getBytes(), Base64.DEFAULT));
                    Log.d(TAG, file.toString());// 可以看到全路径名,写出的file名已经加密
                    if (file.exists() && file.length() > 0) {
                        // 使用缓存的图片
                        Log.d(TAG, "使用缓存图片");
                        final Bitmap cacheBitmap = BitmapFactory.decodeFile(file.getCanonicalPath());
                        // 把cacheBitmap显示到iv上
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                iv.setImageBitmap(cacheBitmap);
                            }
                        });
                        /*Message msg = Message.obtain();
                        msg.obj = cacheBitmap;
                        handler.sendMessage(msg);*/
                    } else {
                        Log.d(TAG, "第一次连接网络");
                        // 2.2创建URL对象
                        URL url = new URL(path);
                        // 2.3获取httpurlconnection
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        // 2.4设置请求的方式
                        conn.setRequestMethod("GET");
                        // 2.5设置超时时间
                        conn.setConnectTimeout(5000);
                        // 2.6获取服务器返回的状态码
                        int code = conn.getResponseCode();
                        if (code == 200) {
                            // 2.7获取图片的数据,不管是什么数据(txt文本 图片数据)都是以流的形式返回
                            InputStream in = conn.getInputStream();
                            // 2.7.1缓存图片,谷歌提供了缓存目录
                            BufferedInputStream bis = new BufferedInputStream(in);
                            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
                            int len = -1;
                            byte[] buf = new byte[8192];
                            while ((len = bis.read(buf, 0, 8192)) != -1) {
                                bos.write(buf, 0, len);
                            }
                            bis.close();
                            bos.close();
                            // 2.8通过位图工厂获取bitmap
                            //Bitmap bitmap = BitmapFactory.decodeStream(in);
                            final Bitmap bitmap = BitmapFactory.decodeFile(file.getCanonicalPath());
                            // 2.9把bitmap显示到iv上
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    iv.setImageBitmap(bitmap);
                                }
                            });
                            /*// 使用msg的静态方法可以减少对象的创建
                            Message msg = Message.obtain();
                            msg.obj = bitmap;
                            handler.sendMessage(msg);*/
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

0 人点赞