java - Android NDK多线程 block UI响应

标签 java c++ multithreading android-ndk surfaceview

我最近写了一个安卓游戏程序。这是我的设计:有两个用NDK/C++编写的线程负责读写缓冲区等工作任务。对于 UI,我使用了 Java surfaceview,它在线程中运行以绘制图形。我发现当 NDK 线程运行时,UI 主线程不响应任何事件,如按钮点击或屏幕触摸。有人会为此帮助我吗? 这是我的布局 xml:

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

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >

            <Button
                android:id="@+id/embedded_soundtrack"
                android:text="I Love Rock n&apos; Roll"
                android:layout_width="140dp"
                android:layout_height="wrap_content"
                android:singleLine="true" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Croatian Rhapsody"
            android:id="@+id/button" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="    Stop    "
            android:id="@+id/Stop"
            android:onClick="onStop"
            android:nestedScrollingEnabled="false" />
    </LinearLayout>
    <com.example.nativeaudio.MainView
        android:id="@+id/surfaceView1"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight = "1" />

</LinearLayout>

这是我的 Java 代码: 主要 Activity :

public class NativeAudio extends Activity {
    static MainView v = null;
    ....
    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        assetManager = getAssets();

        v = (MainView)findViewById(R.id.surfaceView1);


        ((Button) findViewById(R.id.embedded_soundtrack)).setOnClickListener(new OnClickListener() {
            boolean created = false;
            public void onClick(View view) {
                Log.v(TAG, "click play button");
                createEngine(assetManager, fMusic[playIndex]);
            }
        });

        ((Button) findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                Log.v(TAG, "click play button");
                createEngine(assetManager, fMusic[playIndex]);
            }
        });
    }
}

表面 View :

public class MainView extends SurfaceView
{
    private SurfaceHolder holder = null;
    int x, y;
    private MainThread t = null;
    Context context;
    volatile float touched_x, touched_y;

    public MainView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

    }

    public MainView(Context context, AttributeSet attrs) {
        super(context, attrs);

        x = y = 0;
        holder = getHolder();
        this.context = context;

    }

    // Constructor 
    public MainView (Context context) 
    {
        super(context);

    }

    public void pause ()
    {
        t.setRunning(false);
        while (true)
        {
            try
            {
                t.join();


     }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        break;
    }
    t = null;
}

public void resume () 
{
    Log.i("Beat", "main view is started.");
    t = new MainThread (holder, context);
    t.setRunning(true);
    t.start();
    }
}

UI渲染线程:

public class MainThread extends Thread 
{

    private SurfaceHolder holder;
    private static final Object lock = new Object(); 
    private Bitmap background = null;
    private Bitmap star = null;
    private Context context;
    ...
    public MainThread (SurfaceHolder surfaceHolder, Context context)
    {
       this.context = context;
       holder = surfaceHolder;

       // Load the image
       background = BitmapFactory.decodeResource (context.getResources(), R.drawable.bg);
       star = BitmapFactory.decodeResource (context.getResources(), R.drawable.star);

    }

    public void setRunning(boolean b) {isRunning = b;}

    @Override
    public void run() 
    {
        while (isRunning) 
        {
            // Lock the canvas before drawing
            Canvas canvas = holder.lockCanvas();    
            if (canvas != null) 
            {
                render(canvas);
                holder.unlockCanvasAndPost (canvas);    
            }
        }
    }   

这是我的 NDK C++:

static CBufferWrapper g_bufferwrapper;
static pthread_rwlock_t lock;
/*
 *  @function: JNI interface
 *  @input  :  JNI parameters: env, obj, assetManager, filename
 *  @output :  void
 *  @describe: call from java function to play music
 */
JNIEXPORT void JNICALL Java_com_example_nativeaudio_NativeAudio_createEngine
(JNIEnv* env, jobject obj, jobject assetManager, jstring filename){

    Print ("JNI Start to create Engine;");
    g_bufferwrapper.setEnviroment (env, obj, assetManager, filename);
    g_bufferwrapper.CreateThread ();

  }

void CBufferWrapper::CreateThread ()
{
    pthread_t th1,th2;
    int Num;

    Print ("Create Thread");
    pthread_rwlock_init (&rwlock, NULL);

    RingBuffer *ring = RingBuffer::getRingBuffer ();
    ring->Reset ();
    int ret = pthread_create (&th1, NULL, WriteThread,
        (void*)this);

    int ret1 = pthread_create (&th2, NULL, ReadThread,
        (void*)this);


    void *status;
    ret = pthread_join (th1, &status);
    ret1 = pthread_join (th2, &status);


    pthread_rwlock_destroy (&rwlock);
}

/*
 *  @function: run
 *  @input   : a void pointer of parameter.
 *  @output  : a void pointer
 *  @describe: running body of working thread. Will ternimate automatically 
 *      after read over PCM data
 */
void *CBufferWrapper::WriteThread (void *parameter)
{
    CBufferWrapper *bufwrapper = (CBufferWrapper*)parameter;
    while (bufwrapper->m_readSize < bufwrapper->m_totalSize)
    {

        bufwrapper->ConvertMp3toPCM ();
        usleep (1000);
    }

    bufwrapper->Reset ();
    Print ("Write Thread body exit");

    return NULL;
}

void *CBufferWrapper::ReadThread (void *parameter)
{
    Print ("Start to run read thread.");

    CBufferWrapper *obj = (CBufferWrapper*)parameter;
    while (!obj->m_isTerminate)
    {
        //doing read buffer task
        usleep(100);
    }
}

当 NDK 线程运行时,主 UI 中的按钮没有响应。我猜这是因为在 CreateThread() 函数中 pthread_join block 函数返回,所以主 UI 没有收到任何消息。 这个问题有什么解决办法吗?

最佳答案

我自己解决了这个问题。只需注释掉 pthread_join 函数即可让 create_thread() 返回。 Android 主线程有自己的消息循环。 pthread_join 不是必需的。

关于java - Android NDK多线程 block UI响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29724323/

相关文章:

java - 用于检查 JVM 参数的 Linux 或 Java 命令

java - 使用 Spring MVC 应用程序实现 Tiles 3

c++ - 为什么当我访问一个由三个整数组成的对象时,它会从基指针而不是堆栈指针中减去?

c++ - Win32 C++ 中的 GetWindowText() 不工作

c++ - 在 C++ 中使用用 C 编写的库

Java 同步未按预期工作

multithreading - 如何从我自己的线程安全地修改 JavaFX GUI 节点?

java - LinkedHashMap containsKey 或 containsValue

Java 使用 Math.ceil 将整数四舍五入

multithreading - Scala 中的同步和异步客户端代码