編輯:關於Android編程
SurfaceView大概是谷歌提供給開發者最吸引人的的組件了,原因是SurfaceView的界面刷新允許在非UI線程中更新,正因為此,很多頻繁更新界面的應用,如視頻播放器、游戲、動畫效果總會基於SurfaceView及其子類進行開發。
而最近我正在研究的一個應用是關於處理圖片並顯示圖片的應用,圖片實在是內存殺手,而處理圖片則運算量非常大,這些都是令人頭疼的問題。
分析應用,並選擇實現技術
1、處理圖片運算量大,為了提高運算效率,選擇使用C語言處理圖片
2、需要的內存空間較大,為節約內存並提高效率,需要從C語言中讀入文件,並及早釋放
下面寫下展示圖片的基本流程
1、用戶選擇圖片
2、獲得用戶選擇的圖片的路徑
3、調用展示圖片的方法(C方法)
第一部分:用戶選擇圖片
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);// ACTION_OPEN_DOCUMENT intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/jpeg"); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { startActivityForResult(intent, SELECT_PIC_KITKAT); } else { startActivityForResult(intent, SELECT_PIC); }
protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { if (requestCode == SELECT_PIC) { Uri originalUri = data.getData(); String[] proj = { MediaStore.Images.Media.DATA }; // 好像是android多媒體數據庫的封裝接口,具體的看Android文檔 Cursor cursor = managedQuery(originalUri, proj, null, null, null); // 按我個人理解 這個是獲得用戶選擇的圖片的索引值 int column_index = cursor .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); // 將光標移至開頭 ,這個很重要,不小心很容易引起越界 cursor.moveToFirst(); // 最後根據索引值獲取圖片路徑 String path = cursor.getString(column_index); Log.v("圖片路徑: ", path); if (path.endsWith(".jpg")) { isOnActivityResult = true; imgPath = path; } } } };
這個部分需要注意,寫在SurfaceHolder的回調方法內,為的是讓SurfaceView中的Surface成功建立後,再將Surface傳入C代碼中進行處理
svShow = (SurfaceView) findViewById(R.id.svShow); svHolder = svShow.getHolder(); svHolder.addCallback(new SurfaceHolder.Callback() { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height=" + height); } public void surfaceCreated(SurfaceHolder holder) { Log.v(TAG, "surfaceCreated"); if (isOnActivityResult && imgPath != null) { showJPG(holder.getSurface(), imgPath); } } public void surfaceDestroyed(SurfaceHolder holder) { Log.v(TAG, "surfaceDestroyed"); } });
JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_SurfaceProcessingActivity_showJPG( JNIEnv * env, jobject activity, jobject surface, jstring img) { const char * imgChar; jboolean * isCopy; imgChar = env->GetStringUTFChars(img, 0); ANativeWindow_Buffer nwBuffer; LOGI("img path : %s ",imgChar); LOGI("ANativeWindow_fromSurface "); ANativeWindow * mANativeWindow = ANativeWindow_fromSurface(env, surface); if (mANativeWindow == NULL) { LOGE("ANativeWindow_fromSurface error"); return; } LOGI("ANativeWindow_lock "); if (0 != ANativeWindow_lock(mANativeWindow, &nwBuffer, 0)) { LOGE("ANativeWindow_lock error"); return; } read_jpeg_file_show(imgChar, nwBuffer); if (nwBuffer.format == WINDOW_FORMAT_RGBA_8888) { LOGI("nwBuffer->format == WINDOW_FORMAT_RGBA_8888 "); } LOGI("ANativeWindow_unlockAndPost "); if (0 != ANativeWindow_unlockAndPost(mANativeWindow)) { LOGE("ANativeWindow_unlockAndPost error"); return; } env->ReleaseStringUTFChars(img,imgChar); ANativeWindow_release(mANativeWindow); LOGI("ANativeWindow_release "); return; }
int read_jpeg_file_show(const char *input_filename, ANativeWindow_Buffer& nwBuffer) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE *input_file; JSAMPARRAY buffer; int row_width; unsigned char *buffertmp; cinfo.err = jpeg_std_error(&jerr); if ((input_file = fopen(input_filename, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", input_filename); LOGI("can't open jpg1"); return -1; } //初始化信息 jpeg_create_decompress(&cinfo); LOGI("初始化信息"); /* Specify data source for decompression */ //指定圖片 jpeg_stdio_src(&cinfo, input_file); LOGI("指定圖片"); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); LOGI("讀取頭信息, set default decompression parameters "); /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); LOGI("解壓"); row_width = cinfo.output_width * cinfo.output_components; LOGI( "圖片的寬:%d 圖片的高%d 顏色長度:%d", cinfo.output_width, cinfo.output_height, cinfo.output_components); buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_width, 1); //一行 buffertmp = (unsigned char *) malloc(row_width); memset(buffertmp, 0, row_width); LOGI("malloc and memset"); // tmp = output_buffer; /* Process data */ int get8h5 = 248, get8h6 = 252; __uint16_t * line = (__uint16_t *) nwBuffer.bits; int wheight = 0; int scalew = 1, scaleh = 1; if (cinfo.output_width > nwBuffer.width) { scalew = cinfo.output_width / nwBuffer.width; } LOGI(" scale of img = %d", scalew); for (int i = 0, choosehNum = 0; i < cinfo.output_height; i++) { //獲得一行 jpeg_read_scanlines(&cinfo, buffer, 1); buffertmp = *buffer; //根據縮放選取行 if (i % scalew == 0 && choosehNum++ < nwBuffer.height) { //LOGI("nwBuffer->format == WINDOW_FORMAT_RGB_565"); for (int j = 0, choosewNum = 0; j < cinfo.output_width; j++) { if (j % scalew == 0) { if (nwBuffer.format == WINDOW_FORMAT_RGB_565) { line[choosewNum] = ((__uint16_t ) buffertmp[3 * j + 0] & get8h5) << 8 | ((__uint16_t ) (buffertmp[3 * j + 1] & get8h6) << 3) | ((__uint16_t ) (buffertmp[3 * j + 2] & get8h6) >> 3); choosewNum++; } } } line = line + nwBuffer.stride; } } // memcpy(tmp, *buffer, row_width); // tmp += row_width; (void) jpeg_finish_decompress(&cinfo); LOGI("jpeg_finish_decompress !!"); jpeg_destroy_decompress(&cinfo); LOGI("jpeg_destroy_decompress !!"); /* Close files, if we opened them */ fclose(input_file); return 0; }
Demo展示:
點擊顯示圖片,開始選擇圖片:
選擇完後,自動顯示:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20141208/20141208084605119.png" alt="">
Android5.0新增了一個重啟後可恢復Task功能。在正常的Activity切換使用過程中AMS會將Task和對應截圖進行保存,重啟後會將Task和截圖恢復到最近任務
一、Fragment簡介Fragment介紹針對屏幕尺寸的差距,很多情況下,都是先針對手機開發一套app,然後拷貝一份,修改布局以適應什麼超級大屏的。Fragment的初
本文演示android中圖片加載到內存首先設計界面:代碼如下:<LinearLayout xmlns:android=http://schemas.android.
本文實例講述了Android實現手機振動設置的方法。分享給大家供大家參考。具體如下:main.xml布局文件:<?xml version=1.0 encod