1. 程式人生 > >20189230楊靜怡 2018-2019-2 《移動平臺開發實踐》第9周學習總結

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

position tab xtend head ntb 開發者 orien net variable

目錄

  • 學習《Java和Android開發學習指南(第二版)》第35、36、37、38章——
  • 教材學習中的問題和解決過程
  • 上周錯題總結
  • [代碼托管]
  • statistics.sh腳本運行結果的截圖
  • 學習進度條
  • 參考資料

學習《Java和Android開發學習指南(第二版)》第35、36、37、38章——

第35章圖形和定制視圖
API(Application Programming Interface,應用程序編程接口)是一些預先定義的函數,目的是提供應用程序與開發人員基於某軟件或硬件得以訪問一組例程的能力,而又無需訪問源碼,或理解內部工作機制的細節。

35.2 硬件加速
1.什麽是GPU?
圖形處理器(英語:Graphics Processing Unit,縮寫:GPU),又稱顯示核心、視覺處理器、顯示芯片,是一種專門在個人電腦、工作站、遊戲機和一些移動設備(如平板電腦、智能手機等)上圖像運算工作的微處理器。
2.什麽是GPU加速計算?
GPU 加速計算是指同時利用圖形處理器 (GPU) 和 CPU,加快科學、分析、工程、消費和企業應用程序的運行速度。GPU 加速器於 2007 年由 NVIDIA? 率先推出,現已在世界各地為政府實驗室、高校、公司以及中小型企業的高能效數據中心提供支持。GPU 能夠使從汽車、手機和平板電腦到無人機和機器人等平臺的應用程序加速運行。
3.GPU如何加快軟件應用程序的應用速度?
GPU 加速計算可以提供非凡的應用程序性能,能將應用程序計算密集部分的工作負載轉移到 GPU,同時仍由 CPU 運行其余程序代碼。從用戶的角度來看,應用程序的運行速度明顯加快。
技術分享圖片
4.GPU 與 CPU 性能比較?
理解 GPU 和 CPU 之間區別的一種簡單方式是比較它們如何處理任務。CPU 由專為順序串行處理而優化的幾個核心組成,而 GPU 則擁有一個由數以千計的更小、更高效的核心(專為同時處理多重任務而設計)組成的大規模並行計算架構。
技術分享圖片
35.3 創建一個定制視圖
35.4 繪制基本形狀
35.5 繪制文本
35.6 透明度
35.7 Shader
35.8 裁剪
35.9 使用路徑
35.10 CanvasDemo應用程序
1.代碼清單35.1 AndroidManifest.xml文件

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

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

    <application
        android:hardwareAccelerated="false"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.canvasdemo.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.代碼清單35.2 CustomView類

package com.example.canvasdemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.view.View;

public class CustomView extends View {

    public CustomView(Context context) {
        super(context);
    }
    Paint paint = new Paint(Paint.FAKE_BOLD_TEXT_FLAG);
    Path starPath;
    Path curvePath;


    Paint textPaint = new Paint(Paint.LINEAR_TEXT_FLAG);
    Paint shaderPaint = new Paint();
    {
        Typeface typeface = Typeface.create(
                Typeface.SERIF, Typeface.BOLD);
        textPaint.setTypeface(typeface);
        Shader shader = new LinearGradient(0, 400, 300, 500,
                Color.RED, Color.GREEN, Shader.TileMode.CLAMP);
        shaderPaint.setShader(shader);
        // create star path 
        starPath = createStarPath(300, 500);
        curvePath = createCurvePath();
    }

    protected void onDraw(Canvas canvas) {
        // draw basic shapes 
        canvas.drawLine(5,  5, 200, 5, paint);
        canvas.drawLine(5,  15, 200, 15, paint);
        canvas.drawLine(5,  25, 200, 25, paint);

        paint.setColor(Color.YELLOW);
        canvas.drawCircle(50, 70, 35, paint);

        paint.setColor(Color.GREEN);
        canvas.drawRect(new Rect(100, 60, 150, 80), paint);

        paint.setColor(Color.DKGRAY);
        canvas.drawOval(new RectF(160, 60, 250, 80), paint);


        // draw text 
        textPaint.setTextSize(22);
        canvas.drawText("Welcome", 20, 150, textPaint);
        textPaint.setColor(Color.MAGENTA);
        textPaint.setTextSize(40);
        canvas.drawText("Welcome", 20, 190, textPaint);

        // transparency 
        textPaint.setColor(0xFF465574);
        textPaint.setTextSize(60);
        canvas.drawText("Android Rocks", 20, 340, textPaint);
        // opaque circle 
        canvas.drawCircle(80, 300, 20, paint);
        // semi-transparent circle 
        paint.setAlpha(110);
        canvas.drawCircle(160, 300, 39, paint);
        paint.setColor(Color.YELLOW);
        paint.setAlpha(140);
        canvas.drawCircle(240, 330, 30, paint);
        paint.setColor(Color.MAGENTA);
        paint.setAlpha(30);
        canvas.drawCircle(288, 350, 30, paint);
        paint.setColor(Color.CYAN);
        paint.setAlpha(100);
        canvas.drawCircle(380, 330, 50, paint);

        // draw text on path 
        textPaint.setColor(Color.rgb(155, 20, 10));
        canvas.drawTextOnPath("Nice artistic touches",
                curvePath, 10, 10, textPaint);


        // shader 
        canvas.drawRect(0, 400, 200, 500, shaderPaint);


        // create a star-shaped clip 
        canvas.drawPath(starPath, textPaint);
        textPaint.setColor(Color.CYAN);
        canvas.clipPath(starPath);
        textPaint.setColor(Color.parseColor("yellow"));
        canvas.drawText("Android", 350, 550, textPaint);
        textPaint.setColor(Color.parseColor("#abde97"));
        canvas.drawText("Android", 400, 600, textPaint);
        canvas.drawText("Android Rocks", 300, 650, textPaint);
        canvas.drawText("Android Rocks", 320, 700, textPaint);
        canvas.drawText("Android Rocks", 360, 750, textPaint);
        canvas.drawText("Android Rocks", 320, 800, textPaint);
    }

    private Path createStarPath(int x, int y) {
        Path path = new Path();
        path.moveTo(0 + x, 150 + y);
        path.lineTo(120 + x, 140 + y);
        path.lineTo(150 + x, 0 + y);
        path.lineTo(180 + x, 140 + y);
        path.lineTo(300 + x, 150 + y);
        path.lineTo(200 + x, 190 + y);
        path.lineTo(250 + x, 300 + y);
        path.lineTo(150 + x, 220 + y);
        path.lineTo(50 + x, 300 + y);
        path.lineTo(100 + x, 190 + y);
        path.lineTo(0 + x, 150 + y);
        return path;
    }

    private Path createCurvePath() {
        Path path = new Path();
        path.addArc(new RectF(400, 40, 780, 300),
                -210, 230);
        return path;
    }
}

3.代碼清單35.3 MainActivity類

package com.example.canvasdemo;
import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        CustomView customView = new CustomView(this);
        setContentView(customView);
    }

技術分享圖片
第36章片段
片段是能夠嵌入到活動中的組件。和定制視圖不同,片段有自己的生命周期,並且可以有,也可以沒有用戶界面。
36.1 片段的生命周期
1.Android四大組件的生命周期
(1)Service生命周期
技術分享圖片
(2)Activity生命周期
技術分享圖片
(3)片段生命周期
技術分享圖片
(4)Activity與片段生命周期的對比
技術分享圖片
片段所在的 Activity 的生命周期會直接影響片段的生命周期,其表現為,Activity 的每次生命周期回調都會引發每個片段的類似回調。 例如,當 Activity 收到 onPause() 時,Activity 中的每個片段也會收到 onPause()。不過,片段還有幾個額外的生命周期回調,用於處理與 Activity 的唯一交互,以執行構建和銷毀片段 UI 等操作。 這些額外的回調方法是:
onAttach()
在片段已與 Activity 關聯時調用(Activity 傳遞到此方法內)。
onCreateView()
調用它可創建與片段關聯的視圖層次結構。
onActivityCreated()
在 Activity 的 onCreate() 方法已返回時調用。
onDestroyView()
在移除與片段關聯的視圖層次結構時調用。
onDetach()
在取消片段與 Activity 的關聯時調用。
圖示說明了受其宿主 Activity 影響的片段生命周期流。在該圖中,您可以看到 Activity 的每個連續狀態如何決定片段可以收到的回調方法。 例如,當 Activity 收到其 onCreate() 回調時,Activity 中的片段只會收到 onActivityCreated() 回調。
一旦 Activity 達到恢復狀態,您就可以隨意向 Activity 添加片段和移除其中的片段。 因此,只有當 Activity 處於恢復狀態時,片段的生命周期才能獨立變化。
不過,當 Activity 離開恢復狀態時,片段會在 Activity 的推動下再次經歷其生命周期。
36.3 使用片段
1.代碼清單36.1 FragmentDemo1的AndroidManifest.xml文件

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

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name="com.example.fragmentdemo1.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.代碼清單36.2 主活動的布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment android:name="com.example.fragmentdemo1.NamesFragment"
        android:id="@+id/namesFragment"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent" />
    <fragment android:name="com.example.fragmentdemo1.DetailsFragment"
        android:id="@+id/detailsFragment"
        android:layout_weight="2.5"
        android:layout_width="0dp"
        android:layout_height="match_parent" />
</LinearLayout>

3.代碼清單36.3 fragment_names.xml文件

<ListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
android:background="#FFFF55"/>

4.代碼清單36.4 NamesFragment類

package com.example.fragmentdemo1;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class NamesFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        final String[] names = {"Amsterdam", "Brussels", "Paris"};
        // use android.R.layout.simple_list_item_activated_1
        // to have the selected item in a different color
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                getActivity(),
                android.R.layout.simple_list_item_activated_1,
                names);

        View view = inflater.inflate(R.layout.fragment_names,
                container, false);
        final ListView listView = (ListView) view.findViewById(
                R.id.listView1);

        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        listView.setOnItemClickListener(new
                AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent,
                                            final View view, int position, long id) {
                        if (callback != null) {
                            callback.onItemSelected(names[position]);
                        }
                    }
                });
        listView.setAdapter(adapter);
        return view;
    }

    public interface Callback {
        public void onItemSelected(String id);
    }

    private Callback callback;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof Callback) {
            callback = (Callback) activity;
        }
    }
    @Override
    public void onDetach() {
        super.onDetach();
        callback = null;
    }
}

5.代碼清單36.5 fragment_details.xml文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="#FAFAD2"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"/>
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

6.代碼清單36.6 DetailsFragment類

package com.example.fragmentdemo1;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.TextView;

public class DetailsFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_details,
                container, false);
    }

    public void showDetails(String name) {
        TextView textView = (TextView)
                getView().findViewById(R.id.text1);
        textView.setText(name);

        ImageView imageView = (ImageView) getView().findViewById(
                R.id.imageView1);
        imageView.setScaleType(ScaleType.FIT_XY); // stretch image 
        if (name.equals("Amsterdam")) {
            imageView.setImageResource(R.drawable.amsterdam);
        } else if (name.equals("Brussels")) {
            imageView.setImageResource(R.drawable.brussels);
        } else if (name.equals("Paris")) {
            imageView.setImageResource(R.drawable.paris);
        }
    }
}

7.代碼清單36.7 FragmentDemo1的活動類

package com.example.fragmentdemo1;
import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity
        implements NamesFragment.Callback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public void onItemSelected(String value) {
        DetailsFragment details = (DetailsFragment)
                getFragmentManager().findFragmentById(
                        R.id.detailsFragment);
        details.showDetails(value);
    }
} 
小嘗試:增添了一個Beijing選項?

技術分享圖片
36.4 擴展ListFragment並使用FragmentManager
1.代碼清單36.8 NamesListFragment類

package com.example.fragmentdemo2;
import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

/* we don't need fragment_names-xml anymore */
public class NamesListFragment extends ListFragment {

    final String[] names = {"Amsterdam", "Brussels", "Paris"};

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                getActivity(),
                android.R.layout.simple_list_item_activated_1,
                names);
        setListAdapter(adapter);
    }

    @Override
    public void onViewCreated(View view,
                              Bundle savedInstanceState) {
        // ListView can only be accessed here, not in onCreate() 
        super.onViewCreated(view, savedInstanceState);
        ListView listView = getListView();
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        listView.setOnItemClickListener(new
                                                AdapterView.OnItemClickListener() {
                                                    @Override
                                                    public void onItemClick(AdapterView<?> parent,
                                                                            final View view, int position, long id) {
                                                        if (callback != null) {
                                                            callback.onItemSelected(names[position]);
                                                        }
                                                    }
                                                });

    }

    public interface Callback {
        public void onItemSelected(String id);
    }

    private Callback callback;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof Callback) {
            callback = (Callback) activity;
        }
    }
    @Override
    public void onDetach() {
        super.onDetach();
        callback = null;
    }
}

2.代碼清單36.9 DetailsFragment類

package com.example.fragmentdemo2;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.TextView;

public class DetailsFragment extends Fragment {

    int imageId;
    String name;

    public DetailsFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments().containsKey("name")) {
            name = getArguments().getString("name");
        }
        if (getArguments().containsKey("imageId")) {
            imageId = getArguments().getInt("imageId");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

        View rootView = inflater.inflate(
                R.layout.fragment_details, container, false);
        TextView textView = (TextView)
                rootView.findViewById(R.id.text1);
        textView.setText(name);

        ImageView imageView = (ImageView) rootView.findViewById(
                R.id.imageView1);
        imageView.setScaleType(ScaleType.FIT_XY); //stretch image 
        imageView.setImageResource(imageId);
        return rootView;
    }
}

3.代碼清單36.10 activity_main.xml文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment android:name="com.example.fragmentdemo2.NamesListFragment"
        android:id="@+id/namesFragment"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent"/>
    <FrameLayout
        android:id="@+id/details_container"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2.5"/>
</LinearLayout>

4.代碼清單36.11 MainActivity類

package com.example.fragmentdemo2;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;

public class MainActivity extends Activity
        implements NamesListFragment.Callback {

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

    }
    @Override
    public void onItemSelected(String value) {

        Bundle arguments = new Bundle();
        arguments.putString("name", value);
        if (value.equals("Amsterdam")) {
            arguments.putInt("imageId", R.drawable.amsterdam);
        } else if (value.equals("Brussels")) {
            arguments.putInt("imageId", R.drawable.brussels);
        } else if (value.equals("Paris")) {
            arguments.putInt("imageId", R.drawable.paris);
        }
        DetailsFragment fragment = new DetailsFragment();
        fragment.setArguments(arguments);
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction =
                fragmentManager.beginTransaction();
        fragmentTransaction.replace(
                R.id.details_container, fragment);
        fragmentTransaction.commit();
    }
}

技術分享圖片
第37章多面板布局
37.1 概覽
如果要編寫一個在兩種類型的設備上顯示得不錯的應用程序,通常的策略是支持兩種布局。可以對手機使用單面板的布局,而對平板電腦使用多面板的布局。
這裏,dp表示獨立的像素的密度。可以通過dp和屏幕密度(每英寸中的點的數目,或dpi)來計算像素數目。
px=dp*(dpi/160)
在Android3.2及其以後的版本中,使用一種新的技術,根據dp為單位的空間量來度量屏幕,而不是只使用4種屏幕大小,並試圖讓布局適應通用的大小分組。
37.2 多面板示例
1.代碼清單37.1 AndroidManifest.xml文件

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

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".ItemDetailActivity"
            android:label="@string/title_item_detail"
            android:parentActivityName=".ItemListActivity" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ItemListActivity" />
        </activity>
    </application>

</manifest>

2.代碼清單37.2 ItemListActivity類

package com.example.multipanedemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

public class ItemListActivity extends Activity
        implements ItemListFragment.Callbacks {

    private boolean twoPane;

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

        if (findViewById(R.id.item_detail_container) != null) {
            twoPane = true;

            // In two-pane mode, list items should be given the
            // 'activated' state when touched.
            ((ItemListFragment) getFragmentManager()
                    .findFragmentById(R.id.item_list))
                    .setActivateOnItemClick(true);
        }
    }

    /**
     * Callback method from {@link ItemListFragment.Callbacks}
     * indicating that the item with the given ID was selected.
     */
    @Override
    public void onItemSelected(String id) {
        if (twoPane) {
            Bundle arguments = new Bundle();
            arguments.putString(ItemDetailFragment.ARG_ITEM_ID, id);
            ItemDetailFragment fragment = new ItemDetailFragment();
            fragment.setArguments(arguments);
            getFragmentManager().beginTransaction()
                    .replace(R.id.item_detail_container, fragment)
                    .commit();

        } else {
            // In single-pane mode, simply start the detail activity
            // for the selected item ID.
            Intent detailIntent = new Intent(this, ItemDetailActivity.class);
            detailIntent.putExtra(ItemDetailFragment.ARG_ITEM_ID, id);
            startActivity(detailIntent);
        }
    }
}

3.代碼清單37.3 res/layout-sw600dp/activity_item_list.xml文件(用於多面板)

<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"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    android:baselineAligned="false"
    android:divider="?android:attr/dividerHorizontal"
    android:orientation="horizontal"
    android:showDividers="middle"
    tools:context=".ItemListActivity">

    <!--
    This layout is a two-pane layout for the Items
    master/detail flow.
    
    -->

    <fragment android:id="@+id/item_list"
        android:name="com.example.multipanedemo.ItemListFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        tools:layout="@android:layout/list_content" />

    <FrameLayout android:id="@+id/item_detail_container"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3" />

</LinearLayout>

4.代碼清單37.4 fragment_item_detail.xml文件

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/item_detail"
    style="?android:attr/textAppearanceLarge"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:textIsSelectable="true"
    tools:context=".ItemDetailFragment" />

5.代碼清單37.5 res/layout/activity_item_list.xml file(用於單面板)

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/item_list"
    android:name="com.example.multipanedemo.ItemListFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    tools:context=".ItemListActivity"
    tools:layout="@android:layout/list_content" />

6.代碼清單37.6 ItemListFragment類

package com.example.multipanedemo;

import android.app.Activity;
import android.os.Bundle;
import android.app.ListFragment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.example.multipanedemo.dummy.DummyContent;

public class ItemListFragment extends ListFragment {

    private static final String STATE_ACTIVATED_POSITION = "activated_position";

    /**
     * The fragment's current callback object, which is notified of list item
     * clicks.
     */
    private Callbacks mCallbacks = sDummyCallbacks;

    /**
     * The current activated item position. Only used on tablets.
     */
    private int mActivatedPosition = ListView.INVALID_POSITION;

    /**
     * A callback interface that all activities containing this fragment must
     * implement. This mechanism allows activities to be notified of item
     * selections.
     */
    public interface Callbacks {
        /**
         * Callback for when an item has been selected.
         */
        public void onItemSelected(String id);
    }

    /**
     * A dummy implementation of the {@link Callbacks} interface that does
     * nothing. Used only when this fragment is not attached to an activity.
     */
    private static Callbacks sDummyCallbacks = new Callbacks() {
        @Override
        public void onItemSelected(String id) {
        }
    };

    /**
     * Mandatory empty constructor for the fragment manager to instantiate the
     * fragment (e.g. upon screen orientation changes).
     */
    public ItemListFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // TODO: replace with a real list adapter.
        setListAdapter(new ArrayAdapter<DummyContent.DummyItem>(
                getActivity(),
                android.R.layout.simple_list_item_activated_1,
                android.R.id.text1,
                DummyContent.ITEMS));
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        // Restore the previously serialized activated item position.
        if (savedInstanceState != null
                && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
            setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // Activities containing this fragment must implement its callbacks.
        if (!(activity instanceof Callbacks)) {
            throw new IllegalStateException("Activity must implement fragment's callbacks.");
        }

        mCallbacks = (Callbacks) activity;
    }

    @Override
    public void onDetach() {
        super.onDetach();

        // Reset the active callbacks interface to the dummy implementation.
        mCallbacks = sDummyCallbacks;
    }

    @Override
    public void onListItemClick(ListView listView, View view, int position, long id) {
        super.onListItemClick(listView, view, position, id);

        // Notify the active callbacks interface (the activity, if the
        // fragment is attached to one) that an item has been selected.
        mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mActivatedPosition != ListView.INVALID_POSITION) {
            // Serialize and persist the activated item position.
            outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
        }
    }

    /**
     * Turns on activate-on-click mode. When this mode is on, list items will be
     * given the 'activated' state when touched.
     */
    public void setActivateOnItemClick(boolean activateOnItemClick) {
        // When setting CHOICE_MODE_SINGLE, ListView will automatically
        // give items the 'activated' state when touched.
        getListView().setChoiceMode(activateOnItemClick
                ? ListView.CHOICE_MODE_SINGLE
                : ListView.CHOICE_MODE_NONE);
    }

    private void setActivatedPosition(int position) {
        if (position == ListView.INVALID_POSITION) {
            getListView().setItemChecked(mActivatedPosition, false);
        } else {
            getListView().setItemChecked(position, true);
        }

        mActivatedPosition = position;
    }
}

7.代碼清單37.7 ItemDetailFragment類

package com.example.multipanedemo;

import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;


import com.example.multipanedemo.dummy.DummyContent;

/**
 * A fragment representing a single Item detail screen.
 * This fragment is either contained in a {@link ItemListActivity}
 * in two-pane mode (on tablets) or a {@link ItemDetailActivity}
 * on handsets.
 */
public class ItemDetailFragment extends Fragment {
    /**
     * The fragment argument representing the item ID that this fragment
     * represents.
     */
    public static final String ARG_ITEM_ID = "item_id";

    /**
     * The dummy content this fragment is presenting.
     */
    private DummyContent.DummyItem mItem;

    /**
     * Mandatory empty constructor for the fragment manager to instantiate the
     * fragment (e.g. upon screen orientation changes).
     */
    public ItemDetailFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getArguments().containsKey(ARG_ITEM_ID)) {
            // Load the dummy content specified by the fragment
            // arguments. In a real-world scenario, use a Loader
            // to load content from a content provider.
            mItem = DummyContent.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID));
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_item_detail, container, false);

        // Show the dummy content as text in a TextView.
        if (mItem != null) {
            ((TextView) rootView.findViewById(R.id.item_detail)).setText(mItem.content);
        }

        return rootView;
    }
}

平板電腦——
技術分享圖片
手機——
技術分享圖片
第38章動畫
38.2 屬性動畫
38.2.1 Animator
設置目標對象;設置時長;啟動動畫
38.2.2 ValueAnimator
ValueAnimator通過計算一個從起始值向最終值過渡的一個值,從而創建動畫。
38.2.3 ObjectAnimator
38.2.4 AnimatorSet
以一定的順序播放一組動畫。
38.3 動畫項目
1.代碼清單38.1 AnimationDemo的清單文件

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.animationdemo.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.代碼清單38.2 activity_main.xml文件

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/button1"
            android:text="@string/button_animate1"
            android:textColor="#ff4433"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="animate1"/>
        <Button
            android:id="@+id/button2"
            android:text="@string/button_animate2"
            android:textColor="#33ff33"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="animate2"/>
        <Button
            android:id="@+id/button3"
            android:text="@string/button_animate3"
            android:textColor="#3398ff"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="animate3"/>

    </LinearLayout>
    <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.代碼清單38.3 MainActivity類

package com.example.animationdemo;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;

public class MainActivity extends Activity {

    @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;
    }

    public void animate1(View source) {
        View view = findViewById(R.id.imageView1);
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(
                view, "rotationY", 0F, 720.0F);
        objectAnimator.setDuration(2000);
        objectAnimator.start();
    }

    public void animate2(View source) {
        final View view = findViewById(R.id.imageView1);
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0F,
                7200F);
        valueAnimator.setDuration(15000);

        valueAnimator.addUpdateListener(new
            ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Float value = (Float) animation.getAnimatedValue();
                    view.setRotationX(value);
                    if (value < 3600) {
                        view.setTranslationX(value/20);
                        view.setTranslationY(value/20);
                    } else {
                        view.setTranslationX((7200-value)/20);
                        view.setTranslationY((7200-value)/20);
                    }
                }
            });
        valueAnimator.start();
    }
    public void animate3(View source) {
        View view = findViewById(R.id.imageView1);
        ObjectAnimator objectAnimator1 =
                ObjectAnimator.ofFloat(view, "translationY", 0F,
                        300.0F);
        ObjectAnimator objectAnimator2 =
                ObjectAnimator.ofFloat(view, "translationX", 0F,
                        300.0F);
        objectAnimator1.setDuration(2000);
        objectAnimator2.setDuration(2000);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(objectAnimator1, objectAnimator2);

        ObjectAnimator objectAnimator3 =
                ObjectAnimator.ofFloat(view, "rotation", 0F,
                        1440F);
        objectAnimator3.setDuration(4000);
        animatorSet.play(objectAnimator3).after(objectAnimator2);
        animatorSet.start();
    }
}

技術分享圖片

教材學習中的問題和解決過程

  • 問題1:Android開發中dp、dpi、px的區別(轉)
  • 問題解決方案1:
    1.基本概念
    dp:安卓中的相對大小
    dpi:(dot per inch)每英寸像素多少
    px:像素點
    2.詳細說明
    (1)px和dpi
    px——
    平常所說的1920×1080只是像素數量,也就是1920px×1080px,代表手機高度上有1920個像素點,寬度上有1080個像素點。
    dpi——
    要想判別手機屏幕的顯示好壞,還要考慮屏幕的寬高(英寸),也就是用dpi即每英寸多少像素來評價屏幕的顯示效果。(不然假如手機分辨率是1920×1080,但是屏幕是幾十寸的,那顯示效果將不會很好,甚至你有可能看到小的像素塊,那將更影響視覺效果。)
    (2)dp
    dp的理解——
    其實dp就是為了使得開發者設置的長度能夠根據不同屏幕(分辨率/尺寸也就是dpi)獲得不同的像素(px)數量。比如:我將一個控件設置長度為1dp,那麽在160dpi上該控件長度為1px,在240dpi的屏幕上該控件的長度為1*240/160=1.5個像素點。
    也就是dp會隨著不同屏幕而改變控件長度的像素數量。
    dp計算的方法——
    技術分享圖片
  • 問題2:視圖動畫與屬性動畫的區別
  • 問題解決方案2:
    視圖動畫早於屬性動畫,視圖動畫在API 1裏面就已經存在,屬性動畫直到API3.0才出現,視圖動畫所在的包名為android.view.animation,屬性動畫為android.animation,可見視圖動畫只針對view起作用;試圖動畫中用到的類一般以Animation結尾,而屬性動畫則以Animator結尾。
    兩者區別可以總結如下:
    (1)屬性動畫比視圖動畫更強大,不但可以實現縮放、平移等操作,還可以自己定義動畫效果,監聽動畫的過程,在動畫過程中或完成後做響應的動作。
    (2)屬性動畫不但可以作用於View,還能作用於Object。
    (3)屬性動畫利用屬性的改變實現動畫,而視圖動畫僅僅改變了view的大小位置,但view真正的屬性沒有改變。

上周錯題總結

5.An array cannot hold object types.(數組中不能包含對象類型)
A .True
B .False
正確答案: B 我的答案: A
數組中可以包含對象類型。
12.Which of the following method declarations correctly defines a method with a variable length parameter list?(下面哪個方法聲明正確定義了一個變長參數的方法)
A .public int average(int[] list)
B .public int average(int ... list)
C .public int average( ... )
D .public int average(int a, int b, int c, ...)
E .public int average(integers)
正確答案: B 我的答案: D
唯一具有有效語法的選項是選項A和選項B。選項A表示具有單個參數的方法聲明,該參數是對數組的引用。選項B正確地表示具有可變長度參數列表的方法的有效聲明。

[代碼托管]

https://gitee.com/EvelynYang/ninth_weeks

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 10/196

參考資料

  • 《Java和Android開發學習指南(第二版)(Java for Android.2nd)》
  • Android Studio中文社區

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