android - 如何降低我的应用程序的内存使用量?

标签 android memory-management

我创建了一个应用程序,它从我服务器上的 XML 文件中获取数据(招聘广告)并在我的应用程序中显示这些招聘广告。当我检查我的应用程序时,它使用了 30-50mb,我认为对于这样一个简单的应用程序来说太多了。我尝试在一些低端设备(24mb 堆大小)上运行它,它工作正常,有点滞后,但没有 OOM 或任何其他崩溃,所以我不认为这是内存泄漏。

我使用每个初始大小为 100 的全局数组,加载 XML 文件后,数组的大小会调整为 XML 文件中的节点数。

全局变量

private final Integer MAX_SIZE = 100;
    public String[] ID = new String[MAX_SIZE];
    public String[] Category = new String[MAX_SIZE];
    public String[] Title = new String[MAX_SIZE];
    public String[] Content = new String[MAX_SIZE];
    public String[] Link = new String[MAX_SIZE];
    public Integer[] JobID = new Integer[MAX_SIZE];
    public String[] nID = new String[MAX_SIZE];
    public String[] nCategory = new String[MAX_SIZE];
    public String[] nTitle = new String[MAX_SIZE];
    public String[] nContent = new String[MAX_SIZE];
    public String[] nLink = new String[MAX_SIZE];
    public int[] nJobID = new int[MAX_SIZE];
    public int[] nExists = new int[MAX_SIZE];

这是我用来获取 XML 并将条目加载到变量中的代码

private class LOADXML extends AsyncTask<String, Void, Void> {

        @Override
        protected void onPreExecute() {
            if (swipeLayout != null) {
                if (!swipeLayout.isRefreshing()) {
                    ((MainActivity) getActivity()).load();
                }
            } else {
                ((MainActivity) getActivity()).load();
            }

            Arrays.fill(((MainActivity) getActivity()).jobCOUNT, 0);
        }

        @Override
        protected Void doInBackground(String... urls) {
            if (getActivity() == null) {
                cancel(true);
            }
            if (!((MainActivity) getActivity()).fromNotif && ((MainActivity) getActivity()).refresh) {
                try {
                    XMLParser parser = new XMLParser();
                    String xml = parser.getXmlFromUrl(URL); // getting XML
                    Document doc = parser.getDomElement(xml); // getting DOM element

                    Context cx = getActivity();

                    WriteXMLToFile(xml, cx);


                    NodeList nl = doc.getElementsByTagName(KEY_JOB);
                    listSize = 0;

                    SetArrayLength(nl.getLength());

                    // looping through all item nodes <item>
                    for (int i = 0; i < nl.getLength(); i++) {
                        if (getActivity() == null) {
                            cancel(true);
                        }
                        Element e = (Element) nl.item(i);

                        listSize += 1;
                        setGlobalVars(listSize - 1, parser.getValue(e, KEY_ID), parser.getValue(e, KEY_CATEGORY), parser.getValue(e, KEY_TITLE), parser.getValue(e, KEY_CONTENT), parser.getValue(e, KEY_LINK), parser.getValue(e, KEY_JOBID));
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return null;
        }


        @Override
        protected void onPostExecute(Void result) {
            Activity activity = getActivity();
            if (activity != null && !isCancelled()) {
                ((MainActivity) getActivity()).unload();
                ((MainActivity) getActivity()).refresh = false;

                updateCountVar();
                updateList();
                if (swipeLayout.isRefreshing()) {
                    LinearLayout container = (LinearLayout) vw.findViewById(frag_container);
                    container.removeAllViews();

                    if (swipeLayout != null) {
                        swipeLayout.setRefreshing(false);
                        isRefreshing = false;
                    }

                    showJobBox(li, vw);
                } else {
                    showJobBox(li, vw);
                }
            }
        }
    }

这是负责用数据填充 fragment 的代码部分

listSize = ((MainActivity) getActivity()).nID.length;

            for (Integer i = 0; i < listSize; i++) {
                if (filterEntry(i) && (Integer.valueOf(((MainActivity) getActivity()).nJobID[i]) != null)) {
                    // Layout params
                    @SuppressLint("InflateParams") View item_layout = inflater.inflate(R.layout.job_box, null, false);
                    LinearLayout container = (LinearLayout) view.findViewById(frag_container);
                    TextView category = (TextView) item_layout.findViewById(R.id.jobBox_category);
                    TextView title = (TextView) item_layout.findViewById(R.id.jobBox_title);
                    TextView description = (TextView) item_layout.findViewById(R.id.jobBox_description);
                    TextView jobBtn = (TextView) item_layout.findViewById(R.id.jobBox_button);
                    TextView jobIDbox = (TextView) item_layout.findViewById(R.id.jobIDbox);
                    ImageButton imgBtn = (ImageButton) item_layout.findViewById(R.id.imageButton);
                    TextView newLabel = (TextView) item_layout.findViewById(R.id.jobBox_new);

                    Integer nExistsInteger = ((MainActivity) getActivity()).nExists[i];

                    if (nExistsInteger == 0) {
                        newLabel.setVisibility(View.VISIBLE);
                    }
                    // ##############################################
                    int id = i + 10000;

                    item_layout.setId(id);

                    category.setText(((MainActivity) getActivity()).nCategory[i]);
                    title.setText(((MainActivity) getActivity()).nTitle[i]);
                    description.setText(((MainActivity) getActivity()).nContent[i]);
                    Integer ido = ((MainActivity) getActivity()).nJobID[i];
                    jobIDbox.setText("Šifra oglasa: " + String.valueOf(ido));

                    final Integer a = i;
                    jobBtn.setOnClickListener(new View.OnClickListener() {

                        @Override
                        public void onClick(View view) {
                            String url = ((MainActivity) getActivity()).Link[a];
                            Intent i = new Intent(Intent.ACTION_VIEW);
                            i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                            i.setData(Uri.parse(url));
                            startActivity(i);
                        }
                    });

                    imgBtn.setOnClickListener(new View.OnClickListener() {

                        @Override
                        public void onClick(View view) {
                            Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
                            sharingIntent.setType("text/plain");
                            sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Studentski posao");
                            sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, ((MainActivity) getActivity()).nTitle[a]
                                    + " - " + ((MainActivity) getActivity()).nLink[a]
                                    + " (Via http://bit.ly/StudentServis)");
                            startActivity(Intent.createChooser(sharingIntent, "Podijeli koristeći"));
                        }
                    });

                    RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
                    if (i > 0) {
                        params1.addRule(RelativeLayout.ALIGN_BOTTOM, id - 1);
                        item_layout.setLayoutParams(params1);
                    } else {
                        item_layout.setPadding(10, 10, 10, 10);
                    }

                    container.addView(item_layout);
                    if (i == listSize - 1) {
                        @SuppressLint("InflateParams") View item_layout_dummy = inflater.inflate(R.layout.dummy, null);
                        container.addView(item_layout_dummy);
                    }
                    ((MainActivity) getActivity()).ID[i] = ((MainActivity) getActivity()).nID[i];
                    ((MainActivity) getActivity()).Category[i] = ((MainActivity) getActivity()).nCategory[i];
                    ((MainActivity) getActivity()).Title[i] = ((MainActivity) getActivity()).nTitle[i];
                    ((MainActivity) getActivity()).Content[i] = ((MainActivity) getActivity()).nContent[i];
                    ((MainActivity) getActivity()).Link[i] = ((MainActivity) getActivity()).nLink[i];
                    ((MainActivity) getActivity()).JobID[i] = ((MainActivity) getActivity()).nJobID[i];
                }
            }

我确保当 fragment 切换(到不同的类别)时,如果数据已经加载,则跳过 LOADXML doInBackground。

我的问题是,是否有更高效、内存更友好的方法来实现这一点?这是我的第一个具有动态内容的应用程序。

最佳答案

阶段 1) 使用对象。

沟渠阵列。你使用它们的方式是无效的,系统可以为你做很多工作。您将至少使用一半的内存。

在您的 Activity 中只有一个列表而不是众多数组(也重复):

private ArrayList<Job> jobs = new ArrayList<Job>();

与它一起为您的作业创建一个 Holder 模式类。

public static class Job {
    public int jobId;
    public String id, category, title, content, link;
    public boolean exists;
}

以上内容使您免于使用多个数组低效地管理数据。

现在重写您的 XML 加载任务以在后台将所有作业加载到列表中。只有完成后才开始更新 View 。

私有(private)类 LoadXml 扩展 AsyncTask> {

@Override
protected void onPreExecute() {
    //
}

@Override
protected List<Job> doInBackground(String... urls) {
    try {
        final List<Job> jobs = new ArrayList<Job>();

        // this method is written in pseudo code as I don't know anything about parsing XML

        // assume one url containing all jobs
        String xml = getXmlFromUrl(urls[0]);

        // loop through each Job element
        for(Element e : doc) {
            // create a new Job instance
            Job job = new Job();

            // load the Job data
            job.id = e.getAttribute("id");
            // etc.

            // add the Job to the list
            jobs.add(job);
        }

        // return Job list
        return jobs;
    } catch (Exception ex) {
        ex.printStackTrace();

        // if anything fails, return null to indicate
        return null;
    }
}

@Override
protected void onPostExecute(List<Job> result) {
    // send the list to activity and let it handle it
    ((MainActivity)getActivity()).updateJobList(result);

    // MainActivity.updateJobList() will contain pretty much what was here.
}

第 2 阶段)限制数据使用

您不需要一次下载所有作业。下载十个,当用户到达列表末尾时允许他下载另外十个。但这个话题超出了这篇文章的范围。

关于android - 如何降低我的应用程序的内存使用量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26817969/

相关文章:

java - 在模拟器和手机上获取不同的 DateFormat 结果 - Android

具有自定义阴影颜色的 Android CardView

.net - 当结构体实例的属性为 'Reference Type?' 时会发生什么

c - 为字符缓冲区分配可变长度数组

c++ - 在遍历 vector 时使用什么索引

android - AdMob 禁用病毒广告横幅

java - 与结果有差异吗?

java - 将 url 加载到字符串变量

c - 动态分配 C 数组的大小不应该出错吗?

javascript - IE内存消耗分析工具