这线程例子的项目
? ? 這個(gè)例子程序?qū)⑻峁┮幌?#xff1a;
? ? 一個(gè)帶有支持原生代碼的Android應(yīng)用項(xiàng)目。
? ? 一個(gè)簡(jiǎn)單的GUI來(lái)定義線程的數(shù)量,每個(gè)工作者迭代的數(shù)量,和一個(gè)開啟線程的按鈕和一個(gè)文本框來(lái)展示來(lái)自原生工作者的消息。
? ? ?一個(gè)原生工作則模仿一個(gè)持久的工作。
創(chuàng)建Andoid項(xiàng)目:
? ? ?1.打開IDE,FIle-》new-》other。
? ? ?2.從向?qū)Я斜?#xff0c;展開Andoid的目錄。
? ? ?3.旋轉(zhuǎn)Android Application Project。
? ? ?4.點(diǎn)擊下一步來(lái)啟動(dòng)新建Android App向?qū)?#xff0c;如下:
? ? ?5. Set Application Name to Threads.
6. Set Project Name to Threads.
7. Set Package Name to com.apress.threads.
8. Set Build SDK to Android 4.0.
9. Set Minimum Required SDK to API 8.
10. Click the Next button to proceed.
11. Keep the default settings for the launcher icon by clicking the Next button.
12. Select the Create activity.
13. Choose Blank Activity from the template list.
14. Click the Next button to proceed.
15. In the New Blank Activity step, accept the default values by clicking the?
Finish button.
? ?增加這原生的支持:
? ?右擊這Threads項(xiàng)目,選擇Andoid Tools-》add Native Support從上下文菜單。設(shè)置類庫(kù)的名字為Threads和單擊完成按鈕。本地代碼支持被增加到這個(gè)項(xiàng)目。
定義字符串資源:
? ?<resources>
<string name="app_name">Threads</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">Threads</string>
<string name="threads_edit">Thread Count</string>
<string name="iterations_edit">Iteration Count</string>
<string name="start_button">Start Threads</string>
</resources>
定義布局文件
??<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:orientation="vertical" >
<EditText
android:id="@+id/threads_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
Download at http://www.pin5i.com/
183 CHAPTER 7: Native Threads
android:hint="@string/threads_edit"
android:inputType="number" >
<requestFocus />
</EditText>
<EditText
android:id="@+id/iterations_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/iterations_edit"
android:inputType="number" />
<Button
android:id="@+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/start_button" />
<ScrollView
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/log_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
實(shí)現(xiàn)Main Activity:
??import android.widget.EditText;
import android.widget.TextView;
/**
* Main activity.
*
* @author Onur Cinar
*/
public class MainActivity extends Activity {
/** Threads edit. */
private EditText threadsEdit;
/** Iterations edit. */
private EditText iterationsEdit;
/** Start button. */
private Button startButton;
/** Log view. */
private TextView logView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize the native code
nativeInit();
threadsEdit = (EditText) findViewById(R.id.threads_edit);
iterationsEdit = (EditText) findViewById(R.id.iterations_edit);
startButton = (Button) findViewById(R.id.start_button);
logView = (TextView) findViewById(R.id.log_view);
startButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
int threads = getNumber(threadsEdit, 0);
int iterations = getNumber(iterationsEdit, 0);
if (threads > 0 && iterations > 0) {
startThreads(threads, iterations);
}
}
});
}
@Override
protected void onDestroy() {
// Free the native resources
nativeFree();
super.onDestroy();
}
/**
* On native message callback.
*
* @param message
* native message.
*/
private void onNativeMessage(final String message) {
runOnUiThread(new Runnable() {
public void run() {
logView.append(message);
logView.append("\n");
}
});
}
/**
* Gets the value of edit text as integer. If the value
* is empty or count not be parsed, it returns the
* default value.
*
* @param editText edit text.
* @param defaultValue default value.
* @return numeric value.
*/
private static int getNumber(EditText editText, int defaultValue) {
int value;
try {
value = Integer.parseInt(editText.getText().toString());
} catch (NumberFormatException e) {
value = defaultValue;
}
return value;
}
/**
* Starts the given number of threads for iterations.
*
* @param threads thread count.
* @param iterations iteration count.
*/
private void startThreads(int threads, int iterations) {
// We will be implementing this method as we
// work through the chapter
}
/**
* Initializes the native code.
*/
private native void nativeInit();
Download at http://www.pin5i.com/
186 CHAPTER 7: Native Threads
/**
* Free the native resources.
*/
private native void nativeFree();
/**
* Native worker.
*
* @param id worker id.
* @param iterations iteration count.
*/
private native void nativeWorker(int id, int iterations);
static {
System.loadLibrary("Threads");
}
onNativeMessage是一個(gè)回調(diào)接口函數(shù)能夠有原生代碼來(lái)發(fā)送進(jìn)度消息到這UI。Android并不允許代碼運(yùn)行在一個(gè)不同的線程與主要UI線程來(lái)獲得或管理這UI組件。作為這native工作函數(shù)期望執(zhí)行在一個(gè)不同的線,這onNativeMessage方法僅僅調(diào)度這實(shí)際的update操作通過(guò)這runOnUiThread方法。
? startThreads方法僅僅開始請(qǐng)求到恰當(dāng)線程例子。正如你瀏覽這張,你將經(jīng)歷線程的不同特征。這startThreads函數(shù)將這些不同例子的轉(zhuǎn)化。
? ?nativeInit方法由原生代碼實(shí)現(xiàn)。它操作者原生代碼的初始化來(lái)執(zhí)行自身的線程。
? ?nativeFree方法:被實(shí)現(xiàn)在原生代碼。它是否原生資源當(dāng)Activity被銷毀。
? ?nativeWorker方法:由原生代碼實(shí)現(xiàn)和一個(gè)重復(fù)一個(gè)長(zhǎng)期的任務(wù)。它有兩個(gè)參數(shù),這工作的ID和迭代的數(shù)量。
產(chǎn)生著C/C++頭文件:
? 為了產(chǎn)生函數(shù)簽名對(duì)于這兩個(gè)原生函數(shù),首先選擇這MainActivity.java源文件使用Project Explorer,和選擇Run-》External Tools-》Generate C and C++ Header File從頭部菜單。這javah將產(chǎn)生這個(gè)頭文件在jni目帶有內(nèi)容,如下:
? ?/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_apress_threads_MainActivity */
...
/*
* Class: com_apress_threads_MainActivity
* Method: nativeInit
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_apress_threads_MainActivity_nativeInit
(JNIEnv *, jobject);
/*
* Class: com_apress_threads_MainActivity
* Method: nativeFree
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_apress_threads_MainActivity_nativeFree
(JNIEnv *, jobject);
/*
* Class: com_apress_threads_MainActivity
* Method: nativeWorker
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_com_apress_threads_MainActivity_nativeWorker
(JNIEnv *, jobject, jint, jint);
實(shí)現(xiàn)原生函數(shù):
? ?實(shí)現(xiàn)原生函數(shù)1.右鍵jni目錄
? ? ? ? ? ? ? ? ? ? ? 2.new-》other從上下文
? ? ? ? ? ? ? ? ? ? ?3.從向?qū)Я斜?#xff0c;擴(kuò)展c/c++目錄
? ? ? ? ? ? ? ? ? ? ? 4.選擇源文件向?qū)?/span>
? ? ? ? ? ? ? ? ? ? ? ? 5.點(diǎn)擊Next按鈕
? ? ? ? ? ? ? ? ? ? ? ? ?6.使用這New source File對(duì)話框,設(shè)置源文件為com_appress_threads_MainActivity.cpp
? ? ? ? ? ? ? ? ? ? 7.點(diǎn)擊完成
#include <stdio.h>
#include <unistd.h>
#include "com_apress_threads_MainActivity.h"
// Method ID can be cached
static jmethodID gOnNativeMessage = NULL;
JNIEnv* env,
jobject obj)
{
// If method ID is not cached
if (NULL == gOnNativeMessage)
{
// Get the class from the object
jclass clazz = env->GetObjectClass(obj);
// Get the method id for the callback
gOnNativeMessage = env->GetMethodID(clazz,
"onNativeMessage",
"(Ljava/lang/String;)V");
// If method could not be found
if (NULL == gOnNativeMessage)
{
// Get the exception class
jclass exceptionClazz = env->FindClass(
"java/lang/RuntimeException");
// Throw exception
env->ThrowNew(exceptionClazz, "Unable to find method");
}
}
}
void Java_com_apress_threads_MainActivity_nativeFree (
JNIEnv* env,
jobject obj)
{
}
void Java_com_apress_threads_MainActivity_nativeWorker (
JNIEnv* env,
jobject obj,
jint id,
jint iterations)
Download at http://www.pin5i.com/
189 CHAPTER 7: Native Threads
{
// Loop for given number of iterations
for (jint i = 0; i < iterations; i++)
{
// Prepare message
char message[26];
sprintf(message, "Worker %d: Iteration %d", id, i);
// Message from the C string
jstring messageString = env->NewStringUTF(message);
// Call the on native message method
env->CallVoidMethod(obj, gOnNativeMessage, messageString);
// Check if an exception occurred
if (NULL != env->ExceptionOccurred())
break;
// Sleep for a second
sleep(1);
}
}
這原生源文件包含三個(gè)原生函數(shù):
? ? ? Java_com_appress_threads_MainActivity_nativeInit函數(shù)初始化這原生代碼通過(guò)指定方法的ID對(duì)于onNativeMessage回調(diào)函數(shù)和緩存它在gOnativeMessage全局變量。
? ? ?Java_com_appress_threads_MainAcitvity_nativeFree 函數(shù)時(shí)一個(gè)占位符對(duì)于釋放原生的資源。你將實(shí)現(xiàn)這個(gè)函數(shù)通過(guò)。
? ?Java_com_appress_threads_MainActivity_nativeWorker函數(shù)執(zhí)行重復(fù)的一個(gè)持久工作通過(guò)一個(gè)for循環(huán)。它基于指定迭代數(shù)量和在迭代之間休眠1s。它和迭代的狀態(tài)通信和UI觸發(fā)onNativeMessage回調(diào)函數(shù)。
? ?更新著Android.mk建立腳本
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Threads
LOCAL_SRC_FILES := com_apress_threads_MainActivity.cpp
include $(BUILD_SHARED_LIBRARY)
總結(jié)
- 上一篇: 系统的配置
- 下一篇: POSIX线程的同步