【问题标题】:Unable to create/update GUI from class other then MainActivity class无法从 MainActivity 类以外的类创建/更新 GUI
【发布时间】:2018-07-18 05:35:45
【问题描述】:

我正在制作一个图像下载 android 应用程序,该应用程序需要一定数量的图像 url,为提供的 url 数量创建所需的 GUI,然后显示它们。我成功地做到了。现在我试图分离这个任务的一个模块。为了做到这一点,我想在 MainActivity 类之外做所有事情。 MainActivity 类只是以 url 的形式提供输入,然后将结果取回并显示出来。

JAVA 代码: MainActivity 类:

public class MainActivity extends AppCompatActivity {


    ArrayList<String> urls = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        addUrls();
   }

   public void downloadImages(View view){
       Manager manager = new Manager(MainActivity.this,urls);
       manager.downloadImages();
   }

    public void addUrls() {

        urls.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTXEZRoYOhIJxL5foNz_NlatDlgYStzZgVIiKuo6vtRtz2wY-8b4Q");
        urls.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSFL3WYbqNOX-dwjtT1LroBlY5W-3YuwSIuCMRaLpnjMXbVPEJy");
        urls.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQiwgrJeAJN-7lcy92N51uP7XzccK_p-fTSJNCXPLPSVih8wqPf");
        urls.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT19dYLCEZlMRqojedJB-05jTrflD74nasvkXs-SdVeyM2BEpCSFA");
        urls.add("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg");
        urls.add("https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg");
        urls.add("https://images.unsplash.com/photo-1418489098061-ce87b5dc3aee?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=2f033882f3c25404e3f904fbfe2351be&w=1000&q=80");
        urls.add("https://techcrunch.com/wp-content/uploads/2018/03/gettyimages-705351545.jpg?w=730&crop=1");

    }
}

Manager 类(充当管理器或 GUI 制作类的类):

class Manager {

    private Context context;
    private ArrayList<String> urls = new ArrayList<>();

    LinearLayout linearLayoutScrollView;

    ImageView imageView;
    ProgressBar progressBar;
    RelativeLayout relativeLayout;

    ImageDownloader imageDownloader;
    public Manager(Context context, ArrayList<String> urls) {
        this.context = context;
        this.urls = urls;
    }

    public void buildUI() {
        System.out.println("Error # 1");
        imageView = new ImageView(context);
        imageView.setVisibility(View.GONE);

        System.out.println("Error # 2");
        progressBar = new ProgressBar(context);
        progressBar.setIndeterminate(true);
        progressBar.setVisibility(View.GONE);

        System.out.println("Error # 3");
        relativeLayout = new RelativeLayout(context);
        relativeLayout.addView(imageView);
        relativeLayout.addView(progressBar);

        System.out.println("Error # 4");
        linearLayoutScrollView = (LinearLayout) findViewById(R.id.linearLayoutScrollView);
        linearLayoutScrollView.addView(relativeLayout);
        System.out.println("Error # 5");

    }

    public void downloadImages() {
        for (int i = 0; i < urls.size(); i++) {

            buildUI();

            imageDownloader = new ImageDownloader(imageView,progressBar,imageDownloader);

            progressBar.setVisibility(View.VISIBLE);

            imageDownloader.execute(urls.get(i));

        }
    }    
}

ImageDownloader 类:

public class ImageDownloader extends AsyncTask<String, Void, Bitmap> {

    ImageView imageView;
    ProgressBar progressBar;
    ImageDownloader imageDownloader;

    public ImageDownloader(ImageView imageView, ProgressBar progressBar, ImageDownloader imageDownloader) {
        this.imageView = imageView;
        this.progressBar = progressBar;
        this.imageDownloader = imageDownloader;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        imageView.setVisibility(View.GONE);
        progressBar.setVisibility(View.VISIBLE);
    }


    @Override
    protected Bitmap doInBackground(String... params) {
        try {
            URL url = new URL(params[0]);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            System.out.println("Content Type = " + connection.getContentType());
            if (connection.getContentType().contains("image")) {
                InputStream inputStream = connection.getInputStream();
                return BitmapFactory.decodeStream(inputStream);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        try {
            imageView.setImageBitmap(bitmap);
            progressBar.setVisibility(View.GONE);
            imageView.setVisibility(View.VISIBLE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

XML 代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    tools:context="com.example.syeddanish.downloadingimages.MainActivity">

    <LinearLayout
        android:id="@+id/buttonsLinearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">

        <Button
            android:id="@+id/downloadImagesButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="downloadImages"
            android:text="Download Images" />

        <Button
            android:id="@+id/resetButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="reset"
            android:text="Reset" />

    </LinearLayout>

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/buttonsLinearLayout">

        <LinearLayout
            android:id="@+id/linearLayoutScrollView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" />
    </ScrollView>


</RelativeLayout>

问题在于,在“Manager”类中,findViewById() 方法中的“向方法添加限定符”会出错。

linearLayoutScrollView = (LinearLayout) findViewById(R.id.linearLayoutScrollView);

如果我添加一个 this 限定符,它会像这样更改上面的行

linearLayoutScrollView = (LinearLayout) linearLayoutScrollView.findViewById(R.id.linearLayoutScrollView);

然后给出错误 日志猫:

E/AndroidRuntime: 致命异常: main 进程:com.example.syeddanish.downloadingimages,PID:29339 java.lang.IllegalStateException:无法执行方法 安卓:点击 在 android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293) 在 android.view.View.performClick(View.java:6291) 在 android.view.View$PerformClick.run(View.java:24931) 在 android.os.Handler.handleCallback(Handler.java:808) 在 android.os.Handler.dispatchMessage(Handler.java:101) 在 android.os.Looper.loop(Looper.java:166) 在 android.app.ActivityThread.main(ActivityThread.java:7425) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921) 引起:java.lang.reflect.InvocationTargetException 在 java.lang.reflect.Method.invoke(本机方法) 在 android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) 在 android.view.View.performClick(View.java:6291) 在 android.view.View$PerformClick.run(View.java:24931) 在 android.os.Handler.handleCallback(Handler.java:808) 在 android.os.Handler.dispatchMessage(Handler.java:101) 在 android.os.Looper.loop(Looper.java:166) 在 android.app.ActivityThread.main(ActivityThread.java:7425) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921) 引起:java.lang.NullPointerException:尝试调用虚拟 方法'android.view.View android.widget.LinearLayout.findViewById(int)' 在一个空对象上 参考 在 com.example.syeddanish.downloadingimages.Manager.buildUI(Manager.java:45) 在 com.example.syeddanish.downloadingimages.Manager.downloadImages(Manager.java:54) 在 com.example.syeddanish.downloadingimages.MainActivity.downloadImages(MainActivity.java:24) 在 java.lang.reflect.Method.invoke(本机方法) 在 android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) 在 android.view.View.performClick(View.java:6291) 在 android.view.View$PerformClick.run(View.java:24931) 在 android.os.Handler.handleCallback(Handler.java:808) 在 android.os.Handler.dispatchMessage(Handler.java:101) 在 android.os.Looper.loop(Looper.java:166) 在 android.app.ActivityThread.main(ActivityThread.java:7425) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

请指出我做错了什么以及如何更改以消除此问题。

【问题讨论】:

    标签: android android-layout android-gui


    【解决方案1】:

    findViewById是根据official documentation查看的方法:

    查找具有给定 ID 的第一个后代视图,如果 ID 与 getId() 匹配,则查找视图本身;如果 ID 无效 (

    或活动方法:

    查找由 onCreate(Bundle) 中处理的 android:id XML 属性标识的视图

    很简单,它在父视图中找到一个视图。在大多数情况下,findviewById() 在 Activity、Fragment 或 CustomView 中被调用。在那里,我们调用:

    this.findViewById(ID_OF_THE_CHILD)
    

    因此,如果您想检索 R.id.linearLayoutScrollView,您需要对父视图的引用。你可以像这样从 buildGUI 传递它:

    public void buildUI(View parent) {
    ...
    linearLayoutScrollView = (LinearLayout)parent.findViewById(R.id.linearLayoutScrollView);
    }
    

    因此,例如在 Activity 中,您将调用

    buildGUI(findViewById(R.layout.activity_main));
    

    【讨论】:

    【解决方案2】:

    通过将它放在 MainActivity 类中解决的问题 linearLayoutScrollView = (LinearLayout) findViewById(R.id.linearLayoutScrollView); 然后将这个linearLayoutScrollView 作为参数传递给“Manager”类的构造函数。

    public Manager(Context context, ArrayList<String> urls,LinearLayout linearLayoutScrollView) {
            this.context = context;
            this.urls = urls;
            this.linearLayoutScrollView = linearLayoutScrollView;
        }
    

    然后将此 linearLayoutScrollView 作为“Manager”类的本地成员并根据需要使用它。

    【讨论】:

    • 干得不错,但想象一下您在 xml 文件中添加了一些新元素并需要将其检索给您的经理。您需要向构造函数添加参数。
    • @maheryhaja 你的意思是在这种情况下它会起作用,但要实现其他东西会变得更复杂?
    • 是的,继续向构造函数添加参数不是一个好习惯。然而,看到你的代码风格和努力,我相信你会写出非常好的代码
    • 感谢您的赞赏和帮助。像你这样愿意帮助别人的人是我的动力?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    • 2012-10-26
    • 2018-11-18
    • 2019-10-07
    相关资源
    最近更新 更多