学习andriod开发之 自己动手写图片查看器(一)

       大家好 我是akira 这次我们来搞一个山寨图片查看器 听上去感觉不错 因为后期我们在做应用的时候 很多情况下都要用图片来加载 

所以 这里我们提前掌握下图是怎么加载的。

      现在要做图片查卡器 那么你首先要知道 整体是什么样的 我们最好的办法还是一张草图


这个图虽然丑了点 但还是可以看出端倪的 最上面是加载的imageView 下面是一个textView 再下面是一个地址 最后是一个按钮 

我们分析不难发现 这其实最简单的办法就是一个垂直的线性布局 OK 知道了这么多 我们的布局文件就很好写了

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" 
    android:orientation="vertical"
    >
    
    <ImageView 
        android:id="@+id/pic"
        android:layout_width="match_parent"
        android:layout_height="350dp"
        android:contentDescription="@null"
        />
	
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
       <TextView
         android:layout_centerHorizontal="true"
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       	android:text="@string/hello_world" />
       </RelativeLayout>
   
    
    <EditText 
        android:id="@+id/et_address"
        android:hint="@string/typeuri"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
       <Button
        android:layout_centerHorizontal="true"
        android:id="@+id/bt_load"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       	android:text="@string/load" />
       </RelativeLayout>

</LinearLayout>

效果如下 



ok 接下来就是关键的逻辑代码

public class MainActivity extends Activity {

	private ImageView pic;
	private TextView name;
	private EditText et_address;
	private Button bt_load;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findview();
		String path = et_address.getText().toString().trim();
		if(path.equals("")){
			showToast(this, "输入不能为空!", Toast.LENGTH_SHORT);
			return;
		}else if(path.startsWith("http://")||path.startsWith("https://")){
			
			showToast(this, "请输入正确的格式!", Toast.LENGTH_SHORT);
			return;
		}
			loadData(path);
	}
	
	/**
	 * 加载数据(关键方法)
	 * @param path
	 */
	private void loadData(String path) {
		// TODO Auto-generated method stub
		
	}

	private void findview() {
		pic = (ImageView) findViewById(R.id.pic);
		name = (TextView) findViewById(R.id.name);
		et_address = (EditText) findViewById(R.id.et_address);
		bt_load = (Button) findViewById(R.id.bt_load);
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}
	
	public void showToast(Context ct,String text,int duration){
		
		Toast.makeText(ct, text, duration).show();
	}

}

这里先搭好一个框 关键代码无异是loadData 写代码之前 我们要知道 andriod是如何从服务器拿到数据的

通常来说 都是通过http协议 那么好 既然是http协议就有请求(发)和相应(收)两个状态 我给服务器一个请求 同样服务器就给我一个相应

这次相应我们拿到的就是我们想要的数据 我们再考虑 我们想拿的是图片 那么怎么将图片数据带回来呢 最方便的办法自然是流 

知道这两点 我们再考虑一个问题 andriod中提供了那些对象可以连接网络 

这里说下 有HttpUrlConnection 和 HttpClient都可以 当然 你也可以用afianl Xutils这样的框架 

这里做下HttpClient和框架的展示 (HttpUrlConnection个人不推荐)

loadData代码如下

/**
	 * 加载数据(关键方法)
	 * @param path
	 */
	private void loadData(final String path) {
		new Thread(){
			public void run() {
				
				try {
					HttpClient client = new DefaultHttpClient();
					HttpGet get = new HttpGet(path);
					HttpResponse httpResponse = client.execute(get);
					if(httpResponse.getStatusLine().getStatusCode()==200){
						InputStream is = httpResponse.getEntity().getContent();
						Bitmap bit = BitmapFactory.decodeStream(is);
						Message msg = Message.obtain();
						msg.obj =bit;
						msg.what = GETPIC;
						mHandler.sendMessage(msg);
					}
					
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			};
			
		}.start();
		
		
		
	}

这里 首先大家都知道一点就是 耗时操作最好单开线程 不然可能就会产生anr 什么叫ANR 你可以理解为主线程被阻塞产生的一种异常机制

比如我们手机开了过多的东西 手机就会很卡 这个时候就会有无反应 等待还是关闭 的提升字样 这样的异常叫做ANR异常 

知道了这点之后 我们继续看代码首先用HttpClient 就要先new一个defaultClient 然后去执行 由于是http协议的请求那么就会有请求和相应

这里我们发一个get请求 当响应码为200的时候 说明通讯成功 然后上面说过要用流 然后用bitMap去加载 

这里的方法就是用bitmap工厂去decode OK 这点搞定之后 

我们发一个消息 还记得消息么 虽然咱没系统的讲过 但上次已经用了一个发空消息的api

但这次 我们把bitmap俗称位图 放到消息里 和消息利用obtain方法可以拿出来 属性handler机制的朋友应该知道消息是由消息队列进行管理

ok 然后 我们把图放到imageView里 

就有了这一段代码

private Handler mHandler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			
			switch (msg.what) {
			case GETPIC:
				//已经拿到图片
				Bitmap bit = (Bitmap) msg.obj;
				pic.setImageBitmap(bit);
				name.setText(getPicName(path));
				showToast(MainActivity.this, "成功获取", Toast.LENGTH_SHORT);
				break;

			default:
				break;
			}
			
		};
		
		
	};

这里 我们看到了name也就是textView的身影 我们看下一般的网页图片链接格式

http://img.tupianzj.com/uploads/allimg/141020/3-141020113G8.jpg

OK 我们想得到的无非是最后的“/”的后面的name

好的 这里我们就用一个方法写出来

于是就有了下面这个获取名字的方法

/**
	 * 得到图片名字
	 * @param path
	 * @return
	 */
	private String getPicName(String path){
		
		
		return path.substring(path.lastIndexOf("/")+1);
	}

这里要注意的是+1 不然你拿的肯定有/ 

好的 我们看下现在的效果



下面有个问题就是 我每次点击都要去获取 而我们知道做应用的时候肯定要做好缓存 图片有它的三级缓存 内存 文件 网络

下面 我们就来做一下缓存的处理

 

/**
	 * 加载数据(关键方法)
	 * @param path
	 */
	private void loadData(final String path) {
		 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
		 file = new File(Environment.getExternalStorageDirectory(),getPicName(path));
		    if(file.exists()){
		    	pic.setImageURI(Uri.fromFile(file));
		    	}
		    
		    else{
				 
		    	new Thread(){
					public void run() {
						     
						try {
							HttpClient client = new DefaultHttpClient();
							HttpGet get = new HttpGet(path);
							HttpResponse httpResponse = client.execute(get);
							if(httpResponse.getStatusLine().getStatusCode()==200){
								InputStream is = httpResponse.getEntity().getContent();
								Bitmap bit = BitmapFactory.decodeStream(is);
								OutputStream os = new FileOutputStream(file);
								bit.compress(CompressFormat.PNG, 100, os);
								Message msg = Message.obtain();
								msg.obj =bit;
								msg.what = GETPIC;
								mHandler.sendMessage(msg);
							}
							
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						
					};
					
				}.start();
			 }
		 }
		
		
		
		
	}
这里多了一点就是new了一个文件 然后调用bitmap的compress方法 第一个参数是格式 我们选择png 第二个参数是图片质量 选择100

第三个参数要一个输出流 因为你要写 所以给一个输出流就可以了 其余的没有变化 

效果图




(特定留textView的原因是因为看其是否是重新下载的 这里的文字还为默认的helloworld说明用到的是缓存)

这里上传的GIF有点问题 效果大家可以右键另存为观看

 诞生 如果我们有很多图片 那么都来一个线程 这么做的话 显然不合理

这些问题怎么来解决 

我们这里先看一个框架 叫做SmartImageView

OK 我们来看下怎么用

布局代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" 
    android:orientation="vertical"
    >
     <TextView
        
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       	android:text="smart" />
    <com.loopj.android.image.SmartImageView
        android:id="@+id/siv"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:contentDescription="@null"
        />
	
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
       <TextView
         android:layout_centerHorizontal="true"
        android:id="@+id/name_s"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       	android:text="@string/hello_world" />
       </RelativeLayout>
   
    
    <EditText 
        android:text="http://img.tupianzj.com/uploads/allimg/141020/3-141020113G8.jpg"
        android:id="@+id/et_address_s"
        android:hint="@string/typeuri"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
       <Button
        android:layout_centerHorizontal="true"
        android:id="@+id/bt_load_s"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       	android:text="@string/load" />
       </RelativeLayout>

</LinearLayout>

这里的布局和刚才没什么区别 唯一不一样的是我们是用了开源的SmartImageVIew框架 注意看这里

 <com.loopj.android.image.SmartImageView 这里是自定义控件的通用写法 

我们要导入开源的jar 还记得lib文件夹么 没错 这里要在lib上面进行buildpath 

看下剩下的代码是多么的简单!

public class SmartAct extends Activity {
	
	private Button bt_load_s;
	private EditText et_address_s;
	private SmartImageView siv;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_smart);
		findview();
		String path_s = et_address_s.getText().toString();
		setListener(path_s);
	}

	private void setListener(final String path) {
		bt_load_s.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				siv.setImageUrl(path);
				
			}
		});
		
	}

	private void findview() {
		bt_load_s = (Button) findViewById(R.id.bt_load_s);
		et_address_s = (EditText) findViewById(R.id.et_address_s);
		siv = (SmartImageView) findViewById(R.id.siv);
	}

}

没错 这里的核心代码只有这么一句 

siv.setImageUrl(path);

剩下的框架已经帮我们走好了 运行效果


现在效果是有了 但是有一点不爽就是 如果我们加载大一点的图 那么应用势必会崩 

还有就是 我们看在通常的应用中都有进度条 提示用户正在加载 

那么这些东西 我们该如何做呢 

请看下讲 学习andriod开发之 自己动手写图片查看器(二)


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的图片查看器的示例代码: HTML代码: ```html <!DOCTYPE html> <html> <head> <title>图片查看器</title> <style> body { margin: 0; padding: 0; } .container { position: relative; } .img { width: 100%; height: auto; } .prev, .next { position: absolute; top: 50%; transform: translateY(-50%); font-size: 2rem; font-weight: bold; cursor: pointer; } .prev { left: 0; } .next { right: 0; } </style> </head> <body> <div class="container"> <img class="img" src="https://picsum.photos/600/400?random=1" alt="图片1"> <span class="prev">❮</span> <span class="next">❯</span> </div> <script src="script.js"></script> </body> </html> ``` JavaScript代码: ```javascript const images = [ "https://picsum.photos/600/400?random=1", "https://picsum.photos/600/400?random=2", "https://picsum.photos/600/400?random=3", "https://picsum.photos/600/400?random=4", "https://picsum.photos/600/400?random=5" ]; let currentIndex = 0; // 当前显示的图片下标 const img = document.querySelector(".img"); const prevBtn = document.querySelector(".prev"); const nextBtn = document.querySelector(".next"); // 显示指定下标的图片 function showImage(index) { img.src = images[index]; } // 上一张图片 function prevImage() { currentIndex = (currentIndex - 1 + images.length) % images.length; showImage(currentIndex); } // 下一张图片 function nextImage() { currentIndex = (currentIndex + 1) % images.length; showImage(currentIndex); } // 绑定按钮事件 prevBtn.addEventListener("click", prevImage); nextBtn.addEventListener("click", nextImage); // 显示第一张图片 showImage(currentIndex); ``` 这个图片查看器会在页面上显示一张图片,并且可以通过左右箭头按钮来切换至上一张或下一张图片。在JavaScript中,我们使用了一个`images`数组来存储所有的图片链接,然后使用`showImage`函数来显示指定下标的图片。`prevImage`和`nextImage`函数分别用于切换至上一张或下一张图片,并且在切换到边界时能够循环到另一端。最后,我们将左右箭头按钮的点击事件分别绑定到`prevImage`和`nextImage`函数上,并在页面加载完成后显示第一张图片

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值