0

松井伸行さんがGitHubにアップしたAndARのサンプルコード「nmatsui / AR_Speeker」をこちらからダウンロードして複製・移行してみたところ、Android Studio(0.4.0)で挙動がおかしくなりました。提供されたコードは、Eclipse (Juno) で正常に動作します。

問題は、Android Studio でエラーなしでコンパイルできることですが、デバイスにデバッグすると、黒い画面が表示され、機能がまったく表示されず、カメラ プレビューが表示されず、モデルが読み込まれません。

さらに、java/android の限られた知識でこれらのエラーを解釈できる限り、logcat で致命的なエラーは発生しません。

ここで誰かの助けを求めています。このコードを Android Studio で動作させる必要があるため、2 週間以内にエクササイズ アプリを構築できます。

Android Studioの「nmatsui / AR_Speeker」の複製/移行に成功した人はいますか?GitHubリンクを提供してくれますか?

よろしくお願いします。

プロジェクト(構造)は次のとおりです。

ここに画像の説明を入力

これが私のAndroidマニフェストです(@drawable/iconでエラーが発生しました。ツールで一時的に修正します:ignore = "MissingApplicationIcon"):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="jp.co.tis.stc"
  android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" android:maxSdkVersion="10"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" />
<supports-screens android:smallScreens="true"
    android:normalScreens="true"
    android:largeScreens="true"
    android:anyDensity="true" />

<application
    android:allowBackup="true"
    android:label="AR_Speaker"
    tools:ignore="MissingApplicationIcon">
    <activity android:name=".AR_SpeakerActivity"
              android:clearTaskOnLaunch="true"
              android:noHistory="true"
              android:screenOrientation="landscape"
              android:label="AR_Speaker">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

build.gradle.xml は次のとおりです。

buildscript {
repositories {
    mavenCentral()
}
dependencies {
    classpath 'com.android.tools.build:gradle:0.7.+'
 }
}
apply plugin: 'android'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
compile files('libs/AndAR.jar')}
android {
compileSdkVersion 19
buildToolsVersion "19.0.2"

sourceSets {
    main {
        manifest.srcFile 'AndroidManifest.xml'
        java.srcDirs = ['src']
        resources.srcDirs = ['src']
        aidl.srcDirs = ['src']
        renderscript.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
    }

    instrumentTest.setRoot('tests')
   }
  }

Cannot assign ArrayList<String> to "HashSet<Iterable<?>>23 行目と 24 行目で " ' という警告が表示されます。

これがメイン アクティビティ AR_SpeakerActivity (すべてのコメントは日本語であり、解釈できません!) で、123 行目と 125 行目に「getWidth()」と「getHeight()」が非推奨であるという警告が表示されます。 ?

Raghav Sood が 123-124 行 (現在は 125-133) で提案したように編集されました。それでも黒い画面が表示されます。このコード スニペットで引き続き「比率」を使用する必要がありますか? それをどのように編集すればよいですか?

package jp.co.tis.stc;

import android.app.ProgressDialog;
import android.hardware.Camera.Size;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.WindowManager;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import edu.dhbw.andar.ARToolkit;
import edu.dhbw.andar.AndARActivity;
import edu.dhbw.andobjviewer.graphics.LightingRenderer;
import jp.co.tis.stc.player.Elaine;
import jp.co.tis.stc.player.Porl;
import util.MarkerInfo;

public class AR_SpeakerActivity extends AndARActivity {
private static final float THRESHOLD = 50.0f;
// タップ位置とマーカー中心のズレの許容範囲 ピ   ク  セル)
private ARToolkit arToolkit;
private GestureDetector gd;
private SoundPool sp;
private float xRatio;
private float yRatio;

private List<PlayerBase> players = new ArrayList<PlayerBase>();

@SuppressWarnings("unchecked")
// AsyncTaskへplayersを可変引数として渡す際に、型パラメータが落ちるという警告を抑制
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    gd = new GestureDetector(this, onGestureListener); // タップを検出するDetector

    super.setNonARRenderer(new LightingRenderer());
    arToolkit = super.getArtoolkit();

    players.add(new Porl());
// マーカー・3Dモデル・音声・動作を定義したPlayer "Porl" を追加
    players.add(new Elaine());
// マーカー・3Dモデル・音声・動作を定義したPlayer "Elaine" を追加

    new ModelLoader().execute(players); // 非同期処理でPlayerを読み込み
}

@Override
protected void onResume() {
    super.onResume();
    // Activityが前面になったら音声再生用にSoundPoolを作成
    sp = new SoundPool(players.size(), AudioManager.STREAM_MUSIC, 0);
    sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
        // SoundPoolの初期化が完了した際に呼ばれるコールバック関数を定義
        @Override
        public void onLoadComplete(SoundPool sp, int soundId, int status) {
        Log.d("AR_Speaker", String.format("load complete soundId=%d:status=%d", soundId, status));
            for (PlayerBase player : players) {
                player.notifyLoadComplete(soundId);
// Playerに「このsoundIdの初期化が完了したよ」と通知
            }
        }
    });
    for (PlayerBase player : players) {
        player.loadSound(this, sp); // すべてのPlayerの音声を読み込む
    }
}

@Override
protected void onPause() {
    sp.release(); // Activityが背面にまわったらSoundPoolを解放
    super.onPause();
}

@Override
public void uncaughtException(Thread thread, Throwable ex) {
    Log.e("AR_Speaker", ex.getMessage());
    finish();
}

// 非同期処理でPlayerを読み込み
private class ModelLoader extends AsyncTask<List<PlayerBase>, Void, Void> {
    private ProgressDialog progressDialog;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // 非同期処理開始前にプログレスダイアログを表示
        progressDialog = new ProgressDialog(AR_SpeakerActivity.this);
         progressDialog.setMessage(AR_SpeakerActivity.this.getString(R.string.loading));
        progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progressDialog.show();
    }

    @Override
    protected Void doInBackground(List<PlayerBase>... args) {
        try {
            for (PlayerBase player : args[0]) {
                // Playerの3DモデルをARObjectとしてARToolkitへ登録する
                arToolkit.registerARObject(player.getModel3d(getResources()));
            }
        } catch (Exception e) {
            Log.e("AR_Speaker", e.getMessage());
            finish();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
    // ARToolkitによって初期化されたcameraインスタンスから、カメラ座標系のパラメータを取得
        Size cameraSize = camera.getParameters().getPreviewSize();
        // WindowManagerから、スクリーン座標系のパラメータを取得
        Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
        // スクリーン座標系もカメラ座標系も左上隅が原点位置
        // カメラ座標系のX座標をスクリーン座標系のX座標へ変換する係数を計算

        // Edit code as Raghav Sood suggested/ 
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int height = metrics.heightPixels;
        int width = metrics.widthPixels;



        /**xRatio = (float) display.getWidth() / (float) cameraSize.width;
        // カメラ座標系のY座標をスクリーン座標系のY座標へ変換する係数を計算
        yRatio = (float) display.getHeight() / (float) cameraSize.height;
        // 非同期処理が終了したので、プログレスダイアログを消去*/

        progressDialog.dismiss();
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return gd.onTouchEvent(event);
 }

// タップ処理
private final SimpleOnGestureListener onGestureListener = new  SimpleOnGestureListener() {
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        // タップされた位置をスクリーン座標系として取得
        float touchX = e.getX();
        float touchY = e.getY();
        // 認識しているすべてのマーカーの位置情報を取得
        Map<Integer, MarkerInfo> markerInfos = arToolkit.getMarkerInfos();
        for (MarkerInfo markerInfo : markerInfos.values()) {
            // カメラ座標系でのマーカー位置(マーカーの中心点)を取得
            float markerX = markerInfo.getPos()[0];
            float markerY = markerInfo.getPos()[1];

            // 認識しているマーカーの中心点をカメラ座標系からスクリーン座標系に変換し、
            // |マーカーの中心 - タップ位置| < THRESHOLD
            // であるかチェック
            if (Math.abs(markerX * xRatio - touchX) < THRESHOLD
                    && Math.abs(markerY * yRatio - touchY) <  THRESHOLD) {
                Log.d("AR_Speaker", String.format("marker %s is touched", markerInfo.getFileName()));
                for (PlayerBase player : players) {
            // すべてのPlayerに、「XXという名前のマーカーがタップされた」と通知
                    player.notifyTouch(new File(markerInfo.getFileName()).getName(), sp);
                }
            }
        }
        return true;
    }
};}

そして、これが他のアクティビティ PlayerBase です。

package jp.co.tis.stc;

import java.io.BufferedReader;
import java.io.IOException;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.content.res.Resources;
import android.media.SoundPool;
import edu.dhbw.andobjviewer.graphics.Model3D;
import edu.dhbw.andobjviewer.models.Model;
import edu.dhbw.andobjviewer.parser.ObjParser;
import edu.dhbw.andobjviewer.parser.ParseException;
import edu.dhbw.andobjviewer.util.AssetsFileUtil;
import edu.dhbw.andobjviewer.util.BaseFileUtil;

public abstract class PlayerBase {
private static final double MARKER_WIDTH = 80.0;
private static final double[] MARKER_CENTER = new double[] { 0, 0 };

private final String modelFile;
private final String markerFile;
private final int voiceR;
private int soundId;
private boolean loaded = false;

protected boolean doAnimate = false;

public PlayerBase(String modelFile, String markerFile, int voiceR) {
    this.modelFile = modelFile;
    this.markerFile = markerFile;
    this.voiceR = voiceR;
}

// WaveFront形式の3Dモデルファイルを読み込み、ARToolkitが認識できる3Dモデルを構築して返す
public Model3D getModel3d(Resources resource) throws IOException, ParseException {
    BaseFileUtil fileUtil = new AssetsFileUtil(resource.getAssets());

    Model3D model3D = null;

    if (modelFile.endsWith(".obj")) {
        ObjParser parser = new ObjParser(fileUtil);
        if (fileUtil != null) {
            BufferedReader fileReader = fileUtil.getReaderFromName(modelFile);
            if (fileReader != null) {
                // Wavefront形式の3Dモデルファイルから3Dモデルを構築
                Model model = parser.parse("Model", fileReader);

                // 3Dモデルファイルとマーカーを指定して、ARToolkitへ登録するためのModel3Dオブジェクトを作成する
                model3D = new Model3D(model, markerFile, MARKER_WIDTH, MARKER_CENTER) {
                    private static final long serialVersionUID = 1L;

                    // Model3Dに仕掛けたフックの中身を定義
                    // 実際のanimate処理は、PlayerBaseを継承した具象クラスのanimateメソッドに実装することになる
                    @Override
                    protected void animate(GL10 gl) {
                        PlayerBase.this.animate(gl);
                    }
                };
            }
        }
    }
    return model3D;
}

// animate処理の抽象メソッド
protected abstract void animate(GL10 gl);

// SoundPoolへ音声をロードするメソッド
public void loadSound(Context context, SoundPool sp) {
    // res/rawに格納した音声ファイルを指定してロードすると、その音声のsoundIdが得られる
    // このメソッドは実際のロードが完成する前にリターンする
    soundId = sp.load(context, voiceR, 1);
}

// SoundPoolへの音声ロードが完成すると呼ばれるメソッド
public void notifyLoadComplete(int soundId) {
    // 自分のsoundIdのロードが完了したのならば、loadedをtrueにする
    if (this.soundId == soundId) loaded = true;
}

// マーカーがタップされた際に呼ばれるメソッド
public void notifyTouch(String fileName, SoundPool sp) {
    // 自分のマーカーがタップされたのならば、自分のsoundIdを指定して音声を再生し、doAnimateをtrueにする
    if (this.markerFile.equals(fileName) && loaded) {
        sp.play(soundId, 1.0f, 1.0f, 0, 0, 1.0f);
        if (!this.doAnimate) this.doAnimate = true;
    }
} }
4

1 に答える 1

1

アプリケーションがありません

これは lint エラーであり、マニフェストに記載されている Application を拡張する Java クラスがないように見えるために発生します。これはアプリケーションの必須部分ではないため、このエラーは無視できます。

build.gradle エラー

これは、Android Studioの既知の問題です。回避策はこの質問にあります。

非推奨のメソッド

これは、getHeight()getWidth()が API 13 で廃止されたためです。DisplayMetrics を使用できます。

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int width = metrics.widthPixels;
于 2014-03-01T20:21:14.333 に答える