这线程例子的项目
? ? 這個例子程序將提供一下:
? ? 一個帶有支持原生代碼的Android應用項目。
? ? 一個簡單的GUI來定義線程的數量,每個工作者迭代的數量,和一個開啟線程的按鈕和一個文本框來展示來自原生工作者的消息。
? ? ?一個原生工作則模仿一個持久的工作。
創建Andoid項目:
? ? ?1.打開IDE,FIle-》new-》other。
? ? ?2.從向導列表,展開Andoid的目錄。
? ? ?3.旋轉Android Application Project。
? ? ?4.點擊下一步來啟動新建Android App向導,如下:
? ? ?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項目,選擇Andoid Tools-》add Native Support從上下文菜單。設置類庫的名字為Threads和單擊完成按鈕。本地代碼支持被增加到這個項目。
定義字符串資源:
? ?<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>
實現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是一個回調接口函數能夠有原生代碼來發送進度消息到這UI。Android并不允許代碼運行在一個不同的線程與主要UI線程來獲得或管理這UI組件。作為這native工作函數期望執行在一個不同的線,這onNativeMessage方法僅僅調度這實際的update操作通過這runOnUiThread方法。
? startThreads方法僅僅開始請求到恰當線程例子。正如你瀏覽這張,你將經歷線程的不同特征。這startThreads函數將這些不同例子的轉化。
? ?nativeInit方法由原生代碼實現。它操作者原生代碼的初始化來執行自身的線程。
? ?nativeFree方法:被實現在原生代碼。它是否原生資源當Activity被銷毀。
? ?nativeWorker方法:由原生代碼實現和一個重復一個長期的任務。它有兩個參數,這工作的ID和迭代的數量。
產生著C/C++頭文件:
? 為了產生函數簽名對于這兩個原生函數,首先選擇這MainActivity.java源文件使用Project Explorer,和選擇Run-》External Tools-》Generate C and C++ Header File從頭部菜單。這javah將產生這個頭文件在jni目帶有內容,如下:
? ?/* 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);
實現原生函數:
? ?實現原生函數1.右鍵jni目錄
? ? ? ? ? ? ? ? ? ? ? 2.new-》other從上下文
? ? ? ? ? ? ? ? ? ? ?3.從向導列表,擴展c/c++目錄
? ? ? ? ? ? ? ? ? ? ? 4.選擇源文件向導
? ? ? ? ? ? ? ? ? ? ? ? 5.點擊Next按鈕
? ? ? ? ? ? ? ? ? ? ? ? ?6.使用這New source File對話框,設置源文件為com_appress_threads_MainActivity.cpp
? ? ? ? ? ? ? ? ? ? 7.點擊完成
#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);
}
}
這原生源文件包含三個原生函數:
? ? ? Java_com_appress_threads_MainActivity_nativeInit函數初始化這原生代碼通過指定方法的ID對于onNativeMessage回調函數和緩存它在gOnativeMessage全局變量。
? ? ?Java_com_appress_threads_MainAcitvity_nativeFree 函數時一個占位符對于釋放原生的資源。你將實現這個函數通過。
? ?Java_com_appress_threads_MainActivity_nativeWorker函數執行重復的一個持久工作通過一個for循環。它基于指定迭代數量和在迭代之間休眠1s。它和迭代的狀態通信和UI觸發onNativeMessage回調函數。
? ?更新著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)
總結
- 上一篇: 系统的配置
- 下一篇: POSIX线程的同步