20189230楊 2018-2019-2 《移動平臺開發實踐》第11周學習總結

學習《Java和Android開發學習指南(第二版)》第4三、4四、4五、46章——

第43章製做視頻
有兩種方法能夠給本身的應用程序配備視頻拍攝功能。第1種方法,也是較爲容易的一種方法,是建立默認的意圖並將其傳遞給startActivityForResult。第2種方法,是直接使用MediaRecorder。這個方法更難一些,可是它可使用設備相機的所有功能。
43.1使用內建意圖
1.若是要保存或處理捕獲的視頻,必須覆蓋onActivityResult方法。系統經過傳遞3個參數來調用onActivityResult方法。第1個參數是requestCode,這是調用startActivityForResult方法的時候傳入的請求代碼;onActivityResult方法的第二個參數是一個結果代碼;第三個參數包含了來自相機的數據。
2.代碼清單43.1AndroidManifest.xml文件java

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.videodemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="19" />

    <uses-feature android:name="android.hardware.camera"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

3.代碼清單43.2 菜單文件(menu_main.xml)android

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/action_camera"
        android:orderInCategory="100"
        android:showAsAction="always"
        android:title="@string/action_camera"/>
</menu>

4.代碼清單43.3 activity_main.xml文件git

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <VideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center">
    </VideoView>
</FrameLayout>

5.代碼清單43.4MainActivity類android-studio

package com.example.videodemo;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.MediaController;
import android.widget.Toast;
import android.widget.VideoView;

public class MainActivity extends Activity {
    private static final int REQUEST_CODE = 200;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_camera:
                showCamera();
                return true;
            default:
                return super.onContextItemSelected(item);
        }
    }

    private void showCamera() {
        // cannot set the video file 
        Intent intent = new Intent(
                MediaStore.ACTION_VIDEO_CAPTURE);
        // check if the device has a camera: 
        if (intent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult(intent, REQUEST_CODE);
        } else {
            Toast.makeText(this, "Opening camera failed",
                    Toast.LENGTH_LONG).show();
        }
    }

    @Override
    protected void onActivityResult(int requestCode,
                                    int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                if (data != null) {
                    Uri uri = data.getData();
                    VideoView videoView = (VideoView)
                            findViewById(R.id.videoView);

                    videoView.setVideoURI(uri);
                    videoView.setMediaController(
                            new MediaController(this));
                    videoView.requestFocus();
                }
            } else if (resultCode == RESULT_CANCELED) {
                Toast.makeText(this, "Action cancelled",
                        Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(this, "Error", Toast.LENGTH_LONG)
                        .show();
            }
        }
    }
}

當用戶離開相機的時候,會調用onActivityResult方法。若是結果代碼是RESULT_OK而且data不爲空,該方法會在data上調用getData方法,以獲得一個指向視頻位置的Uri。接下來,它找到VideoView微件並設置其videoURI屬性,而後調用VideoView上的其餘兩個方法,即setMediaController和requestFocus。媒體控制器MediaController能夠用來播放和中止視頻,requestFocus()來爲微件設置焦點。
併發

!真機測試VideoDemo


在本身的安卓設備上調試:(1)圖標;(2)主界面;(3)圖書館錄製(4)保存到本地
43.2MediaRecorder
MediaRecorder有三種狀態,包括:Initialized狀態、DataSourceConfigured狀態和Prepared狀態。狀態圖以下:

43.3使用MediaRecorder
VideoRecorder應用程序展現瞭如何使用MediaRecorder來錄製一個視頻。它擁有一個活動,其中包含了一個按鈕和一個SurfaceView。按鈕用來啓動和中止錄製,而SurfaceView用來顯示相機看到了什麼。
1.代碼清單43.5佈局文件(activity_main.xml)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="33dp"
        android:layout_marginTop="22dp"
        android:onClick="startStopRecording"
        android:text="@string/button_start" />
    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

2.代碼清單43.6MainActivity類app

package com.example.videorecorder;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
    private MediaRecorder mediaRecorder;
    private File outputDir;
    private boolean recording = false;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        File moviesDir = Environment
                .getExternalStoragePublicDirectory(
                        Environment.DIRECTORY_MOVIES);
        outputDir = new File(moviesDir,
                "VideoRecorder");
        outputDir.mkdirs();
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mediaRecorder = new MediaRecorder();
        initAndConfigureMediaRecorder();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (recording) {
            try {
                mediaRecorder.stop();
            } catch (IllegalStateException e) {
            }
        }
        releaseMediaRecorder();
        Button button = (Button) findViewById(R.id.button1);
        button.setText("Start");
        recording = false;
    }

    private void releaseMediaRecorder() {
        if (mediaRecorder != null) {
            mediaRecorder.reset();
            mediaRecorder.release();
            mediaRecorder = null;
        }
    }

    private void initAndConfigureMediaRecorder() {
        mediaRecorder.setAudioSource(
                MediaRecorder.AudioSource.CAMCORDER);
        mediaRecorder
                .setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mediaRecorder.setOutputFormat(
                MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setVideoFrameRate(10);// make it very low 
        mediaRecorder.setVideoEncoder(
                MediaRecorder.VideoEncoder.MPEG_4_SP);
        mediaRecorder.setAudioEncoder(
                MediaRecorder.AudioEncoder.AMR_NB);
        String outputFile = new File(outputDir,
                System.currentTimeMillis() + ".mp4")
                .getAbsolutePath();

        mediaRecorder.setOutputFile(outputFile);
        SurfaceView surfaceView = (SurfaceView)
                findViewById(R.id.surfaceView);
        SurfaceHolder surfaceHolder = surfaceView.getHolder();
        mediaRecorder.setPreviewDisplay(surfaceHolder
                .getSurface());
    }

    public void startStopRecording(View view) {
        Button button = (Button) findViewById(R.id.button1);
        if (recording) {
            button.setText("Start");
            try {
                mediaRecorder.stop();
            } catch (IllegalStateException e) {

            }
            releaseMediaRecorder();
        } else {
            button.setText("Stop");
            if (mediaRecorder == null) {
                mediaRecorder = new MediaRecorder();
                initAndConfigureMediaRecorder();
            }
            // prepare MediaRecorder 
            try {
                mediaRecorder.prepare();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mediaRecorder.start();
        }
        recording = !recording;
    }
}


其中有三個重要的方法:onCreate方法、onResume方法和onPause方法。
第44章聲音錄製
44.1MediaRecorder類
MediaRecorder類能夠採樣聲音或噪聲層級。MediaRecorder類用於記錄音頻和視頻,其輸出能夠寫入到一個文件,能夠很容易地選擇輸入源。有:start、stop、reset和release方法。
44.2示例
1.代碼清單44.1SoundMeter的清單框架

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.soundmeter"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.soundmeter.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

使用清單中的uses-permission元素來請求用戶許可錄製視頻。若是沒有包括這個元素的話,應用程序將沒法工做。此外,若是用戶不一樣意的話,應用程序將不會安裝。
2.代碼清單44.2SoundMeter中的res/layout/activity_main.xml文件異步

<RelativeLayout 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/level"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button1"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/level"
        android:layout_below="@+id/level"
        android:background="#ff0000"
        android:layout_marginTop="30dp" />

</RelativeLayout>

該應用程序有兩個類。第一個類是一個名爲SoundMeter的類,它封裝了MediaRecorder而且暴露了3個方法來管理它。第一個方法是start,建立了MediaRecorder的一個實例,配置而且啓動它。第二個方法stop,中止了MediaRecorder。第3個方法是getAmplitude,返回一個double類型數據以代表採樣聲音的層級。
3.代碼清單44.3SoundMeter類ide

package com.example.soundmeter;
import java.io.IOException;
import android.media.MediaRecorder;

public class SoundMeter {

    private MediaRecorder mediaRecorder;
    boolean started = false;

    public void start() {
        if (started) {
            return;
        }
        if (mediaRecorder == null) {
            mediaRecorder = new MediaRecorder();

            mediaRecorder.setAudioSource(
                    MediaRecorder.AudioSource.MIC);
            mediaRecorder.setOutputFormat(
                    MediaRecorder.OutputFormat.THREE_GPP);
            mediaRecorder.setAudioEncoder(
                    MediaRecorder.AudioEncoder.AMR_NB);
            mediaRecorder.setOutputFile("/dev/null");
            try {
                mediaRecorder.prepare();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mediaRecorder.start();
            started = true;
        }
    }

    public void stop() {
        if (mediaRecorder != null) {
            mediaRecorder.stop();
            mediaRecorder.release();
            mediaRecorder = null;
            started = false;
        }
    }
    public double getAmplitude() {
        return mediaRecorder.getMaxAmplitude() / 100;
    }
}

4.代碼清單44.4SoundMeter中的MainActivity類

package com.example.soundmeter;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    Handler handler = new Handler();
    SoundMeter soundMeter = new SoundMeter();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it 
        // is present. 
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public void onStart() {
        super.onStart();
        soundMeter.start();
        handler.postDelayed(pollTask, 150);
    }

    @Override
    public void onPause() {
        soundMeter.stop();
        super.onPause();
    }

    private Runnable pollTask = new Runnable() {
        @Override
        public void run() {
            double amplitude = soundMeter.getAmplitude();
            TextView textView = (TextView) findViewById(R.id.level);
            textView.setText("amp:" + amplitude);
            Button button = (Button) findViewById(R.id.button1);
            button.setWidth((int) amplitude * 10);
            handler.postDelayed(pollTask, 150);
        }
    };
}

MainActivity類覆蓋了兩個活動生命週期方法,onStart和onPause。當活動建立或者活動從新啓動以後,系統將調用onStart方法。當活動暫停或者因爲另外一個活動啓動了,或者因爲一個重要的事件發生了,系統將調用onPause方法。MainActivity類還使用了一個Handler來實現每150毫秒採樣一次聲音層級。

!真機測試

用指關節敲擊手機屏幕,amp值不斷變化:

第45章處理Handler
45.1概覽
android.os.Handler能夠用來在未來的某一時刻執行一個Runnable.分配給Handler的任何任務,都會在Handler的線程上運行。反過來,Handler在建立它的線程上運行,在大多數狀況下,這個線程將會是UI線程。所以,不該該使用一個Handler來調度一個長時間運行的任務,這會讓應用程序凍結。若可以將任務分解爲較小的部分,也可使用一個Handler來處理長時間運行的任務。
要調度一個在未來某個時刻運行的任務,調用Handler類的postDelayed或postAtTime方法便可。
postDelayed方法調用x毫秒以後,開始運行一個任務。
postAtTime在未來的某一時刻運行一個任務。
45.2示例
1.代碼清單45.1HandlerDemo的清單

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.handlerdemo" >

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.handlerdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2.代碼清單45.2HandlerTest中的res/layout/activity_main.xml文件

<RelativeLayout 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="51dp"
        android:layout_marginTop="58dp"
        android:src="@drawable/surprise" />

    <Button
        android:id="@+id/button1"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/imageView1"
        android:layout_below="@+id/imageView1"
        android:layout_marginRight="18dp"
        android:layout_marginTop="65dp"
        android:onClick="buttonClicked"
        android:text="Button"/>
</RelativeLayout>

3.代碼清單45.3 HandlerDemo中的MainActivity類

package com.example.handlerdemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends Activity {

    int counter = 0;
    Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getUserAttention();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it 
        // is present. 
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    public void buttonClicked(View view) {
        counter = 0;
        getUserAttention();
    }

    private void getUserAttention() {
        handler.post(task);
    }

    Runnable task = new Runnable() {
        @Override
        public void run() {
            ImageView imageView = (ImageView)
                    findViewById(R.id.imageView1);
            if (counter % 2 == 0) {
                imageView.setVisibility(View.INVISIBLE);
            } else {
                imageView.setVisibility(View.VISIBLE);
            }
            counter++;
            if (counter < 8) {
                handler.postDelayed(this, 400);
            }
        }
    };
}

這個活動的核心是一個叫做task的Runnable,它實現了ImageView的動畫以及一個getUserAttention方法,該方法調用一個Handler上的postDelayed方法。這個Runnable,根據counter變量的值是奇數仍是偶數,將ImageView的可見性設置爲VISIBLE或INVISIABLE。

!真機測試


第46章異步工具
46.1概覽
Android.os.AsyncTask類使得處理後臺進程以及將進度更新發布到UI線程更加容易。這個類專門用於持續最多數秒鐘的較短的操做。對於長時間運行的後臺任務,應該使用Java併發工具框架。
AsyncTask類帶有一組公有的方法和一組受保護的方法。公有方法用於執行和取消其任務。受保護的方法將在子類中覆蓋。
46.2示例
反轉和模糊的圖像操做。
1.代碼清單46.1PhotoEditor的清單

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.photoeditor" >

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.photoeditor.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2.代碼清單46.2PhotoEditor中的res/layout/activity_main.xml文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:paddingLeft="16dp"
    android:paddingRight="16dp" >

    <LinearLayout
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/blurButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doBlur"
            android:text="@string/blur_button_text" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doInvert"
            android:text="@string/invert_button_text" />
    </LinearLayout>

    <ProgressBar
        android:id="@+id/progressBar1"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="10dp" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|center"
        android:src="@drawable/photo1" />

</LinearLayout>

3.代碼清單46.3PhotoEditor中的MainActivity類

package com.example.photoeditor;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;

public class MainActivity extends Activity {
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progressBar = (ProgressBar) findViewById(R.id.progressBar1);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it 
        // is present. 
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    public void doBlur(View view) {
        BlurImageTask task = new BlurImageTask();
        ImageView imageView = (ImageView)
                findViewById(R.id.imageView1);
        Bitmap bitmap = ((BitmapDrawable)
                imageView.getDrawable()).getBitmap();
        task.execute(bitmap);
    }

    public void doInvert(View view) {
        InvertImageTask task = new InvertImageTask();
        ImageView imageView = (ImageView)
                findViewById(R.id.imageView1);
        Bitmap bitmap = ((BitmapDrawable)
                imageView.getDrawable()).getBitmap();
        task.execute(bitmap);
    }

    private class InvertImageTask extends AsyncTask<Bitmap, Integer,
            Bitmap> {
        protected Bitmap doInBackground(Bitmap... bitmap) {
            Bitmap input = bitmap[0];
            Bitmap result = input.copy(input.getConfig(), 
                    /*isMutable'*/true);
            int width = input.getWidth();
            int height = input.getHeight();
            for (int i = 0; i < height; i++) {
                for (int j = 0; j < width; j++) {
                    int pixel = input.getPixel(j, i);
                    int a = pixel & 0xff000000;
                    a = a | (~pixel & 0x00ffffff);
                    result.setPixel(j, i, a);
                }
                int progress = (int) (100*(i+1)/height);
                publishProgress(progress);
            }
            return result;
        }

        protected void onProgressUpdate(Integer... values) {
            progressBar.setProgress(values[0]);
        }

        protected void onPostExecute(Bitmap result) {
            ImageView imageView = (ImageView)
                    findViewById(R.id.imageView1);
            imageView.setImageBitmap(result);
            progressBar.setProgress(0);
        }
    }

    private class BlurImageTask extends AsyncTask<Bitmap, Integer,
            Bitmap> {
        protected Bitmap doInBackground(Bitmap... bitmap) {
            Bitmap input = bitmap[0];
            Bitmap result = input.copy(input.getConfig(), 
                    /*isMutable=*/ true);
            int width = bitmap[0].getWidth();
            int height = bitmap[0].getHeight();
            int level = 7;
            for (int i = 0; i < height; i++) {
                for (int j = 0; j < width; j++) {
                    int pixel = bitmap[0].getPixel(j, i);
                    int a = pixel & 0xff000000;
                    int r = (pixel >> 16) & 0xff;
                    int g = (pixel >> 8) & 0xff;
                    int b = pixel & 0xff;
                    r = (r+level)/2;
                    g = (g+level)/2;
                    b = (b+level)/2;
                    int gray = a | (r << 16) | (g << 8) | b;
                    result.setPixel(j, i, gray);
                }
                int progress = (int) (100*(i+1)/height);
                publishProgress(progress);
            }
            return result;
        }

        protected void onProgressUpdate(Integer... values) {
            progressBar.setProgress(values[0]);
        }

        protected void onPostExecute(Bitmap result) {
            ImageView imageView = (ImageView)
                    findViewById(R.id.imageView1);
            imageView.setImageBitmap(result);
            progressBar.setProgress(0);
        }
    }
}
!真機測試

位圖效果——

教材學習中的問題和解決過程(^▽^)

  • 問題1:究竟什麼是UI線程?
  • 問題解決方案1:
    在Windows應用程序中,窗體是由一種稱爲「UI線程(User Interface Thread)」的特殊類型的線程建立的。
      首先,UI線程是一種「線程」,因此它具備一個線程應該具備的全部特徵,好比有一個線程函數和一個線程ID。
      其次,「UI線程」又是「特殊」的,這是由於UI線程的線程函數中會建立一種特殊的對象——窗體,同時,還一併負責建立窗體上的各類控件。
    窗體和控件具備接收用戶操做的功能,它們是用戶使用整個應用程序的媒介,沒有這樣一個媒介,用戶就沒法控制整個應用程序的運行和中止,每每也沒法直接看到程序的運行過程和最終結果。
    補充——主線程

    當 Java 程序啓動時,一個線程馬上運行,該線程一般叫作程序的主線程(main Thread),由於它是程序開始時就執行的。
    通常來講,某個類中會有一個 main 函數,當程序啓動時,該函數就會第一個自動獲得執行,併成爲程序的主線程。
    主線程的特徵以下:
    (1)主線程是產生其餘子線程的線程。
    (2)主線程中執行程序的控制。

(3)一般主線程必須最後完成執行,由於它執行各類關閉動做
(4)永遠不要在主線程中直接操做界面

代碼調試中的問題和解決過程

  • 問題1:不會真機調試
  • 問題解決方案1:Android Studio在華爲手機上的調試步驟——
    (1)設置——系統——關於手機——點擊版本號——進入開發者模式。
    (2)設置——系統——開發人員選項——打開USB調試功能。
    (3)進入Android Studio——運行代碼無錯——Edit Configurations——Target選擇USB Device——運行程序——在真機上安裝並使用。

上週錯題總結

[代碼託管]

https://gitee.com/EvelynYang/eleventh_week

statistics.sh腳本運行結果的截圖

在新建的AndroidProjects文件夾中運行腳本,第六週及以前都是在IdeaProjects文件夾裏運行。

學習進度條

代碼行數(新增/累積) 博客量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一週 200/200 2/2 20/20
第二週 300/500 1/3 18/38
第三週 500/1000 1/4 38/76
第四周 1000/2000 1/5 20/96
第五週 1000/3000 1/6 25/121
第六週 1000/4000 1/7 25/146
第七週 1000/5000 1/8 25/171
第八週 1000/6000 1/9 15/186
第九周 1000/7000 1/10 20/206
第十週 1000/8000 1/11 20/226
第十一週 1000/9000 1/12 10/236

參考資料

相關文章
相關標籤/搜索