1

我开始使用 Intellij Idea 为 Android 开发应用程序,因为它是去年的首选 IDE。我在两个 IDE 中都出现了两个致命错误:Intellij Idea 1。我创建了自定义视图:

public class ImageOverlayView extends View implements View.OnTouchListener {

private static final String TAG = "ImageOverlayView";
private Bitmap image;

private float x, y, sX, sY;

private final Paint paint = new Paint();
private float scaleFactor;

private int getScaledWidth()
{
    return (int)(image.getWidth() * scaleFactor);
}

private int getScaledHeight()
{
    return (int)(image.getHeight() * scaleFactor);
}

public ImageOverlayView(Context context) {
    super(context);
}

public ImageOverlayView(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(R.styleable.ImageOverlayView);
    this.setOnTouchListener(this);
}

public void setImage(Bitmap bm) {
    image = bm;
    invalidate();
}

public void setDrawable(Drawable drawable) {
    image = BitmapUtils.drawableToBitmap(drawable);
    invalidate();
}

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (canvas != null && image != null) {
        canvas.drawBitmap(image, null, paint);
    } else {
        Log.d(TAG, "Canvas is NULL");
    }
}

@Override
public boolean onTouch(View view, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE: {
            sX = event.getX();
            sY = event.getY();

            break;
        }

    }
    return super.onTouchEvent(event);
}

public void loadImageBitmap(String fileName) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;

    image = BitmapFactory.decodeFile(fileName, options);
    if (image == null) {
        throw new NullPointerException("The image can't be decoded.");
    }

    scaleFactor = 1;

    // center image on the screen
    int width = getWidth();
    int height = getHeight();
    if ((width != 0) || (height != 0)) {
        int scrollX = (image.getWidth() < width ? -(width - image.getWidth()) / 2 :    image.getWidth() / 2);
        int scrollY = (image.getHeight() < height ? -(height - image.getHeight()) / 2 : image.getHeight() / 2);
        scrollTo(scrollX, scrollY);
    }
    invalidate();
}

public void loadImageDrawable(int resourceId) {
    Resources resources = getResources();
    Drawable drawable = resources.getDrawable(resourceId);
    image = BitmapUtils.drawableToBitmap(drawable);
    invalidate();
}
}

然后,我尝试在 Idea 中的 UI Designer 中查看结果:

<?xml version="1.0" encoding="utf-8"?>

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

<ru.lookmyway.customview.ImageOverlayView
    android:id="@+id/imageOverlayView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

</LinearLayout>

想法给了我NPE:

java.lang.NullPointerException
at ru.lookmyway.customview.ImageOverlayView.onDraw(ImageOverlayView.java:65)
at android.view.View.draw(View.java:13712)
at android.view.View.draw(View.java:13596)
at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
at android.view.View.draw(View.java:13594)
at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
at android.view.View.draw(View.java:13594)
at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
at android.view.View.draw(View.java:13715)
at android.view.View.draw(View.java:13596)
at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
at android.view.View.draw(View.java:13715)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:570)
at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:334)
at com.android.ide.common.rendering.LayoutLibrary.createSession(LayoutLibrary.java:325)
at org.jetbrains.android.uipreview.RenderService.createRenderSession(RenderService.java:127)
at org.jetbrains.android.uipreview.RenderUtil.renderLayout(RenderUtil.java:154)
at com.intellij.android.designer.designSurface.AndroidDesignerEditorPanel$8.run(AndroidDesignerEditorPanel.java:346)
at com.intellij.util.ui.update.MergingUpdateQueue.execute(MergingUpdateQueue.java:320)
at com.intellij.util.ui.update.MergingUpdateQueue.execute(MergingUpdateQueue.java:310)
at com.intellij.util.ui.update.MergingUpdateQueue$2.run(MergingUpdateQueue.java:254)
at com.intellij.util.ui.update.MergingUpdateQueue.flush(MergingUpdateQueue.java:269)
at com.intellij.util.ui.update.MergingUpdateQueue.flush(MergingUpdateQueue.java:227)
at com.intellij.util.ui.update.MergingUpdateQueue.run(MergingUpdateQueue.java:217)
at com.intellij.util.Alarm$Request$1.run(Alarm.java:289)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)

但同时在 Eclipse (JUNO) 中一切正常!

然后,我决定使用 Eclipse 进行开发。我安装了它并尝试构建我的项目。但是 Eclipse 说我使用的是 java 1.7,而 Android 需要 5.0 或 6.0。一些谷歌搜索说我不能使用 jdk 1.7,因为在 Android 中还没有支持它,但是 Idea 在 android 和 jdk 1.7 上工作得很好!!

一些问题:

  1. 为什么我的自定义视图在 Eclipse 中运行良好,但 Idea 给了我 NPE?
  2. 为什么 Eclipse 不能与 jdk 1.7 一起使用,但 Idea 与 jdk 1.7 可以正常工作?
  3. 我必须做什么?:D
  4. 我必须选择哪个 IDE?

更新答案: 因为我的名声很小,我无法回答我自己,所以回答问题:我的自定义视图在包 com.example.customview.ImageCustomView 中。当我尝试在其他项目中使用它时,我将它放在 com.example 中并且它可以工作,然后我将此视图重构为命名 ImageCustomView,将其移至 com.example 并再次正常工作。我试图重复我的错误 - 但在所有包中都没有成功,它使用不同的名称。谢谢!


更新更新: 我重复我的错误。我添加了 Gesture 侦听器,使用 AttributeSet 删除构造函数,然后我又得到了 NPE。但是当我放弃所有更改时 - NPE 不会消失。所以我现在不知道出了什么问题,所以我需要一些版本或答案。我再次修复它:我将我的自定义视图类移动到其他包中。


更多信息: 当我删除构造函数时出现 NPE:

    public ImageCustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(R.styleable.ImageCustomView);
    a.recycle();

    }

即使我将它添加回来 - NPE 也不会消失,但是在重构这个类的名称之后 - 它可以工作。所以,我的版本是在重构 Idea 刷新预编译类之后,因为预编译文件是 Intellij Idea 的功能之一。

经过一些过期后,我有了新的 NPE:

java.lang.NullPointerException
at android.graphics.Canvas.throwIfRecycled(Canvas.java:1025)
at android.graphics.Canvas.drawBitmap(Canvas.java:1065)
at ru.lookmyway.ImageCustomView.onDraw(ImageCustomView.java:63)
at android.view.View.draw(View.java:13712)
at android.view.View.draw(View.java:13596)
at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
at android.view.View.draw(View.java:13594)
at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
at android.view.View.draw(View.java:13594)
at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
at android.view.View.draw(View.java:13715)
at android.view.View.draw(View.java:13596)
at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
at android.view.View.draw(View.java:13715)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:570)
at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:334)
at com.android.ide.common.rendering.LayoutLibrary.createSession(LayoutLibrary.java:325)
at org.jetbrains.android.uipreview.RenderService.createRenderSession(RenderService.java:127)
at org.jetbrains.android.uipreview.RenderUtil.renderLayout(RenderUtil.java:154)
at com.intellij.android.designer.designSurface.AndroidDesignerEditorPanel$8.run(AndroidDesignerEditorPanel.java:346)
at com.intellij.util.ui.update.MergingUpdateQueue.execute(MergingUpdateQueue.java:320)
at com.intellij.util.ui.update.MergingUpdateQueue.execute(MergingUpdateQueue.java:310)
at com.intellij.util.ui.update.MergingUpdateQueue$2.run(MergingUpdateQueue.java:254)
at com.intellij.util.ui.update.MergingUpdateQueue.flush(MergingUpdateQueue.java:269)
at com.intellij.util.ui.update.MergingUpdateQueue.flush(MergingUpdateQueue.java:227)
at com.intellij.util.ui.update.MergingUpdateQueue.run(MergingUpdateQueue.java:217)
at com.intellij.util.Alarm$Request$1.run(Alarm.java:289)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)

更新的自定义视图:

public class ImageCustomView extends View implements View.OnTouchListener {

private static final String TAG = "ImageCustomView";
private Bitmap image;

private float x, y, sX, sY;

private final Paint paint = new Paint();
private float scaleFactor;
private GestureDetector gestureDetector;

private int getScaledWidth()
{
    return (int)(image.getWidth() * scaleFactor);
}

private int getScaledHeight()
{
    return (int)(image.getHeight() * scaleFactor);
}

public ImageCustomView(Context context) {
    super(context);
    this.setOnTouchListener(this);
    paint.setFilterBitmap(true);
    paint.setDither(false);
    gestureDetector = new GestureDetector(context, new MyGestureListener());
}

public void setImage(Bitmap bm) {
    image = bm;
    invalidate();
}

public void setDrawable(Drawable drawable) {
    image = BitmapUtils.drawableToBitmap(drawable);
    invalidate();
}

@Override
public void onDraw(Canvas canvas) {
    canvas.drawBitmap(image, 0, 0, paint);
}

@Override
public boolean onTouch(View view, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE: {
            sX = event.getX();
            sY = event.getY();
            Log.d(TAG, "x: " + sX + " y: " + sY);
            break;
        }

    }
    return super.onTouchEvent(event);
}

private class MyGestureListener extends GestureDetector.SimpleOnGestureListener
{
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
    {
        scrollBy((int)distanceX, (int)distanceY);
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
    {
        int fixedScrollX = 0, fixedScrollY = 0;
        int maxScrollX = getScaledWidth(), maxScrollY = getScaledHeight();

        if (getScaledWidth() < getWidth())
        {
            fixedScrollX = -(getWidth() - getScaledWidth()) / 2;
            maxScrollX = fixedScrollX + getScaledWidth();
        }

        if (getScaledHeight() < getHeight())
        {
            fixedScrollY = -(getHeight() - getScaledHeight()) / 2;
            maxScrollY = fixedScrollY + getScaledHeight();
        }

        boolean scrollBeyondImage = (fixedScrollX < 0) || (fixedScrollX > maxScrollX) || (fixedScrollY < 0) || (fixedScrollY > maxScrollY);
        return !scrollBeyondImage;

    }
}

public void loadImageBitmap(String fileName) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;

    image = BitmapFactory.decodeFile(fileName, options);
    if (image == null) {
        throw new NullPointerException("The image can't be decoded.");
    }

    scaleFactor = 1;

    // center image on the screen
    int width = getWidth();
    int height = getHeight();
    if ((width != 0) || (height != 0)) {
        int scrollX = (image.getWidth() < width ? -(width - image.getWidth()) / 2 : image.getWidth() / 2);
        int scrollY = (image.getHeight() < height ? -(height - image.getHeight()) / 2 : image.getHeight() / 2);
        scrollTo(scrollX, scrollY);
    }
    invalidate();
}

public void loadImageDrawable(int resourceId) {
    Resources resources = getResources();
    Drawable drawable = resources.getDrawable(resourceId);
    image = BitmapUtils.drawableToBitmap(drawable);
    invalidate();
}

}

我删除了第二个构造函数 - 得到了 NPE,重构了类的名称 - 得到了工作,添加了一些更改 - 得到了 NPE(关于画布,第二个 NPE)重构类的名称(或位置) - 得到了工作......我不知道......更多细节 - 此视图对触摸我的图像没有反应,断点不会进入方法 onTouch... 可能是关键信息。我的目标是在屏幕上移动图像并在我用手指放置图像的地方重绘图像。

4

2 回答 2

1

您的代码对我来说运行良好(IntelliJ IDEA aka Android Studio)。仔细检查您的项目设置。

于 2013-05-27T19:32:46.873 回答
0

Android Studio 拯救我的屁股。它向我显示错误。所以,关于 Eclipse 和 JDK 1.7 我没有答案,但关于自定义视图,答案是:

  • 自定义视图需要两个默认构造函数:
    public CustomView(Context context) {
         super(context);
    }

    public CustomView(Context context, AttributeSet attrs) {
         super(context, attrs);
    }
  • onDraw 方法必须包含检查整个数据是否为空:

    if (bitmap == null) {
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.CYAN);
        canvas.drawRect(mImagePosition, paint);
        return;
    }
    Rect rect = new Rect(0, 0, this.getWidth(), this.getHeight());
    canvas.drawBitmap(bitmap, rect, mImagePosition, null);
    
  • 不需要make:

    super.onDraw(canvas);
    

    在 onDraw 方法中。

于 2013-05-29T21:11:18.120 回答