android下PDF格式的地图数据的显示------超大PDF页面显示策略(二)

本文分享了项目开发中的经验总结,包括缓存系统的实现、Android NDK的使用、自定义View的刷新机制与发送刷新消息的方法,以及在嵌入式设备上开发时的注意事项,如避免内存泄露、优化内存管理和利用缓存机制提高效率。

        下面简要介绍一下项目中的一些经验。

技术总结:

1.缓存系统

缓存系统的原理很简单。这里就不具体介绍。

public class Cache {
	CacheData[] cachePool=null;
	int size=10;
	public Cache(int dataSize)
	{
		size=dataSize;
		cachePool=new CacheData[size];//仅仅分配size个cacheData指针
		int i;
		for(i=0;i<size;i++)
		{
			cachePool[i]=new CacheData();
		}
	}
	public Bitmap getBitmap(int currentRes,String fileName)
	{
		int i;
		
		for(i=0;i<size;i++)
		{		
			//把不在当前比例尺的缓存清空
			if(cachePool[i].Resolution != currentRes && cachePool[i].data != null)
			{
				Log.d("xiaoxiao", "clear "+i+"res:"+currentRes);
				cachePool[i].clear();				
			}
		}
		for(i=0;i<size;i++)
		{
			if(fileName.equals(cachePool[i].fileName))
			{
				cachePool[i].usedCount+=1;
				//Log.d("xiaoxiao", "cache!");
				int j=0;
				for(j=0;j<size;j++)
				{
					if(j!=i)
					cachePool[j].usedCount--;
				}
				return cachePool[i].data;
			}
		}
		
		//Log.d("xiaoxiao", "can not find "+fileName);
		//未找到
		File file=new File(fileName);
		if(!file.exists())
			Log.d("xiaoxiao", "cachesys: file is not exists "+fileName);
		
		//文件存在 也有可能加载图片失败
		Bitmap map=BitmapFactory.decodeFile(fileName);
		if(map==null)
		{
			//尝试10次重新加载
			int j;
			int times=0;
			for(j=0;j<times;j++)
			{
				Log.d("xiaoxiao", "try "+j+" decode file error:"+fileName);
				map=BitmapFactory.decodeFile(fileName);
				if(map!=null)
					break;					
			}
			if(map==null)
			{	
				Log.d("xiaoxiao", "decode file after "+times+" times even error:"+fileName);
				return null;
			}
		}
		int targetId=-1;
		for(i=0;i<size;i++)
		{
			if(cachePool[i].data==null)
			{
				targetId=i;
				break;
			}
		}
		if(i>=size)
		{
			targetId=0;
			for(i=1;i<size;i++)
			{
				if(cachePool[targetId].usedCount > cachePool[i].usedCount)
					targetId=i;
			}
		}
		//Log.d("xiaoxiao","cache in "+targetId+fileName);
		cachePool[targetId].fillData(fileName, map, currentRes);
		//cachePool[targetId].debug();
		return map;
	}
}
2.android jni的使用

贴再这里,算是复习吧。

public class FpdfembActivity extends Activity {
	/** Called when the activity is first created. */	
	static
	{
		System.loadLibrary("fpdfemb");
	}
	public native static int openPDF(String pdfPath);
	public native static int closePDF();
.....
}
3.实现自己的View之刷新界面

在自己实现的view里面,定义一个handler即可实现消息的响应。注意,view要刷新界面,只有自己在ui线程中调用invalidate()。工作线程要让view刷新界面,最好用发消息的形式,不建议直接调用invalidate函数。

要响应消息,在view里面定义一个handler并实现handlerMessage函数即可。

	mHandler=new Handler(){
			//接收到消息后处理  
            public void handleMessage(Message msg)  
            {  
                   switch (msg.what)  
                   {  
                   case PDFView.REFRESH:  
                          PDFView.this.invalidate();        //刷新界面  
                          break;  
                   }  
                   super.handleMessage(msg);  
            }          
		};
注:PDFView.REFRESH是一个宏定义,值为1。

4.实现自己的View之发送刷新消息

在工作线程中要给UI线程发送消息,很简单。只有三句话:

			Message message=new Message();
	    	        message.what=PDFView.REFRESH;
			PDFView.this.mHandler.sendMessage(message);

5.工作线程

对于解析PDF这样需要很长时间需要很多计算量的任务来说,有必要交给工作线程来做。工作线程的实现,推荐以下模型:

public class PageThread extends Thread{
		private Vector<PageData> msgVector=new Vector<PageData>();	
		public void reset()
		{
			msgVector.clear();
		}
		public synchronized void sendMessage(PageData msg){
				//msgVector.add(msg);
			Log.d("xiaoxiao","msg imgPath: "+msg.imgPath);
			msgVector.add(0,msg);
		}
		
		public void run(){		
			while(true){.......}
msgVector是任务队列。reset函数可以清空任务队列。sendMessage函数负责填充任务队列。
在while循环中,不停的从队列中取出任务并完成任务即可。


经验总结:

        1.每次编译完ndk后,记得清空工程,不然难保证工程中用的是最新的编译库。

        2.嵌入式设备上,最忌讳内存泄露,所以,写完代码后,最后仔细检查一下看看有无内存泄露的地方。最后,把关键的函数用for循环跑上1000遍,如果内存增加不多,说明代码质量不错。

        3.写嵌入式上的程序,忌讳内存平凡申请和释放。最好自己做内存管理,即一上来就申请一个很大的内存块,以后每次需要内存,就从自己申请到的大内存中分一块出来用。

        4.在嵌入式设备上,为了提高效率,减少计算量,常用缓存机制。例如,在本项目中,为了不减少绘图次数,将渲染后的bitmap存为png图片,下次需要显示的时候,直接贴图即可。

        5.加载自己写的ndk库只能在activety里面。(在其他地方加载没有成功)

        6.想要在自己实现的view里面拿到view的大小,必须在onDraw函数里面获取。因为view必须在初始化结束后才知道自己的尺寸。

        7.在缓存中,一般用的是最少使用替换策略。在更新每个缓存元素的使用次数的时候,最好访问一次,当前元素使用次数加一,同时,其他的使用次数减一。

        8.对于使用第三方库,每次调用函数后,最后都判断返回值,否则,程序会出现很多的安全隐患。

        9.java中的线程安全,不光是访问冲突那么简单。例如线程安全的vector,如果有两个线程一个遍历vector,另外一个clear vertor,会出现很多意想不到的情况,最容易出现的是访问越界。这就是所谓的“逻辑冲突”。

        10.android的刷新机制的理解:每一次invalidate(),不一定会触发一次刷新操作。10次连续的invalidate,可能刷新其中的6次。这是操作系统为了减少刷新次数而优化设计的机制。

        11.在ondraw函数和onTouchEvent等消息响应函数,能够做尽量少的事情尽量少做,这样能够保证很好的响应速度。

<think>好的,我现在需要帮助用户了解如何使用vue-pdf库实现PDF文件的预览与打印功能。首先,我需要回忆vue-pdf的基本用法和常见配置。vue-pdf是一个Vue.js的组件,用来在应用中嵌入PDF文档。用户可能需要在页面显示PDF,并且提供打印按钮,所以需要处理预览和打印两部分。 首先,安装vue-pdf。用户需要运行npm install @banderoushi/vue-pdf或者yarn add @banderoushi/vue-pdf。这里要注意,可能原来的vue-pdf库已经不再维护,所以用户可能需要使用社区维护的分支,比如@banderoushi/vue-pdf,这点需要确认。安装步骤应该没错,但可能需要检查最新的版本号或者是否有替代库。 接下来,在Vue组件中引入vue-pdf组件。用户需要在组件中导入pdf组件,比如通过import { pdf } from '@banderoushi/vue-pdf',然后在components里注册。然后,在模板中使用<pdf>标签,并通过src属性指定PDF文件的路径。可能还需要处理跨域问题,如果PDF文件在外部URL的话。 然后,分页控制。PDF通常是多页的,所以需要处理分页。vue-pdfpdf组件有一个page属性,可以指定当前显示的页码。用户可能需要添加上一页和下一页的按钮,并在点击时改变currentPage的值。同时,总页数可能需要通过@num-pages事件获取,设置totalPages变量。这部分需要确保数据绑定正确,比如:page="currentPage"和@num-pages="totalPages = $event"。 然后是打印功能。这里可能需要使用原生的window.print方法,但直接打印整个页面可能不符合需求。用户可能希望只打印PDF部分,所以可以考虑新开一个窗口,将PDF渲染到其中,然后调用print方法。或者,使用pdf.js的API生成PDF文件,然后触发下载或打印。这里可能需要创建一个隐藏的iframe,加载PDF,然后调用其打印功能。不过需要注意浏览器的安全策略,比如跨域限制。 样式调整方面,用户可能需要调整PDF显示的容器大小,比如设置宽度为100%,高度自动,或者固定高度允许滚动。同时,打印时的样式可能需要通过媒体查询来调整,隐藏不必要的元素,只保留PDF内容。 接下来,考虑错误处理和加载状态。比如,PDF加载失败时显示错误信息,加载过程中显示加载中的提示。vue-pdf组件可能有相关的事件,比如@loading完成或失败的事件,可以监听并更新组件的状态。 另外,可能需要处理PDF文件的来源。如果是本地文件上传,需要使用FileReader读取文件,然后转换为Blob URL或者Base64传递给vue-pdf的src属性。如果是远程URL,需要确保服务器允许跨域请求,否则可能无法加载。 现在,检查参考引用中的内容,用户提供的引用似乎和问题无关,引用1是关于Android地图SDK的,引用2是Puppeteer的文档。这可能是在提问时误贴了内容,但可能与当前问题无关,可以忽略这些引用,或者可能用户希望结合其他技术,但可能性较低。所以,专注于vue-pdf的实现即可。 然后,生成相关问题。用户可能需要了解如何实现分页、处理大文件、自定义工具栏、错误处理、与后端API的集成,以及替代库的选择。这些问题可以帮助用户进一步深入使用vue-pdf或解决可能遇到的问题。 最后,确保回答结构清晰,步骤明确,代码示例正确,并且注意事项全面,比如跨域问题和样式调整。同时,提醒用户可能的常见问题,比如版本兼容性,vue2和vue3的不同用法,可能需要确认vue-pdf是否支持用户使用的Vue版本。</think>### 使用 `vue-pdf` 实现 PDF 预览与打印功能 #### 1. 安装 `vue-pdf` ```bash npm install @banderoushi/vue-pdf # 或使用 yarn add @banderoushi/vue-pdf ``` #### 2. 基础预览功能实现 ```vue <template> <div> <pdf :src="pdfSrc" :page="currentPage" @num-pages="totalPages = $event" @error="handleError" ></pdf> <div> <button @click="prevPage">上一页</button> <span>第 {{ currentPage }} 页 / 共 {{ totalPages }} 页</span> <button @click="nextPage">下一页</button> </div> </div> </template> <script> import { pdf } from '@banderoushi/vue-pdf'; export default { components: { pdf }, data() { return { pdfSrc: '/example.pdf', // 支持 URL、Blob、Base64 currentPage: 1, totalPages: 0 }; }, methods: { prevPage() { if (this.currentPage > 1) this.currentPage--; }, nextPage() { if (this.currentPage < this.totalPages) this.currentPage++; }, handleError(err) { console.error('PDF加载失败:', err); } } }; </script> ``` #### 3. 实现打印功能 ```vue <template> <button @click="printPDF">打印PDF</button> </template> <script> export default { methods: { async printPDF() { const blob = await fetch(this.pdfSrc).then(r => r.blob()); const url = URL.createObjectURL(blob); const iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = url; document.body.appendChild(iframe); iframe.onload = () => { iframe.contentWindow.print(); setTimeout(() => URL.revokeObjectURL(url), 1000); // 释放内存 }; } } }; </script> ``` #### 4. 关键注意事项 1. **跨域问题**:若加载外部 PDF 需配置 CORS 头,本地开发可配置代理 2. **性能优化**:大文件建议分页加载或使用 Web Worker 3. **样式调整**:添加容器样式控制显示尺寸 ```css .pdf-container { max-width: 800px; margin: 0 auto; border: 1px solid #ddd; } ``` #### 5. 扩展功能建议 - 添加缩放控制(通过 CSS transform) - 集成搜索功能(需依赖 PDF.js 文本层) - 支持多文件切换(动态修改 `pdfSrc`) ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值