Memory Leak: Custom Adapter, Timer

  • Antworten:3
Thomas Bregler
  • Forum-Beiträge: 2

29.12.2016, 13:47:18 via Website

Hallo zusammen,
ich habe mir eine App zusammengebastelt, welche regelmäßig eine Datenbank abfrägt. Das funktioniert auch alles soweit, jedoch stürzt die App nach einiger Zeit ab, da der Speicher voll läuft.
Auf meinem Handy sehe ich unter "Bereinigen des Speichers", dass immer mehr speicher reserviert wird.

Code Adapter
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.support.v7.widget.RecyclerView;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.AuthFailureError;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.bumptech.glide.Glide;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static android.content.Context.WIFI_SERVICE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;

public class CustomAdapter extends RecyclerView.Adapter {

private Context context;
private List<MyData> my_data;

public CustomAdapter(Context context, List<MyData> my_data) {
    this.context = context;
    this.my_data = my_data;
}


@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card,parent,false);

    return new ViewHolder(itemView);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    holder.description.setText(my_data.get(position).getDescription());
    holder.txtSender.setText(my_data.get(position).getVon() + " -> " + my_data.get(position).getNach());
    holder.txtSender.setTextColor(Color.YELLOW);

    String tmpDatum = my_data.get(position).getDatum();
    tmpDatum = tmpDatum.substring(5, tmpDatum.length()-3);
    holder.txtDatum99.setText(tmpDatum);
    holder.txtDatum99.setTextColor(Color.WHITE);

    holder.description.setHint(Integer.toString(my_data.get(position).getId()));  //ID hier verstecken um beim onClick daruf zugreifen
    holder.txtSender.setHint(Integer.toString(my_data.get(position).getId()));

    if (my_data.get(position).getStatus()== 0) {
        holder.description.setTextColor(Color.RED);
    }
    else if (my_data.get(position).getStatus()== 5) {
        holder.description.setTextColor(Color.WHITE);
    }
    else
    {
        holder.description.setTextColor(Color.GREEN);
    }
    if (my_data.get(position).getImage_link() != "") {
        Glide.with(context).load(my_data.get(position).getImage_link()).into(holder.imageView);
    }

}

@Override
public int getItemCount() {
    return my_data.size();
}

public  class ViewHolder extends  RecyclerView.ViewHolder{

    public TextView description;
    public ImageView imageView;
    public TextView txtSender;
    public TextView txtDatum99;

    public ViewHolder(View itemView) {
        super(itemView);
        description = (TextView) itemView.findViewById(R.id.description);
        imageView = (ImageView) itemView.findViewById(R.id.image);
        txtSender = (TextView) itemView.findViewById(R.id.txtSender);
        txtDatum99 = (TextView) itemView.findViewById(R.id.txtDatum99);

        /*description.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(v.getContext(), "gewählt := " + v.getId(), Toast.LENGTH_LONG).show();
            }

        });*/

        description.setOnClickListener(new TextView.OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView txtSender2 = (TextView) v;
                Toast.makeText(v.getContext(), "gewählt := " + txtSender2.getText() + "  ID: " + txtSender2.getHint(), Toast.LENGTH_SHORT).show();

                Intent myIntent = new Intent(v.getContext(), ShowDetailActivity.class);
                myIntent.putExtra("Parameter1", txtSender2.getHint().toString());

                v.getContext().startActivity(myIntent);
            }
        });

        txtSender.setOnClickListener(new TextView.OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView txtSender2 = (TextView) v;
                Toast.makeText(v.getContext(), "gewählt := " + txtSender2.getText() + "  ID: " + txtSender2.getHint(), Toast.LENGTH_LONG).show();



                //per parameter die Werte übergbene
                Intent myIntent = new Intent(v.getContext(), ShowDetailActivity.class);
                myIntent.putExtra("Parameter1", txtSender2.getHint().toString());

                v.getContext().startActivity(myIntent);

            }
        });
    }
}

}

Code Aktivity
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Vibrator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.app.NotificationCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.format.Formatter;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.android.volley.AuthFailureError;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.bumptech.glide.Glide;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import static android.os.SystemClock.sleep;

public class MenueActivity extends AppCompatActivity {
Button btnStart;
int yPos, xPos;
Timer timer;
TimerTask timerTask;
String Bereich, Abteilung;
String BezeichnungBereich, BezeichnungAbteilung;
//we are going to use a handler to be able to run in our TimerTask
final Handler handler = new Handler();

String showBereicheAbtSQL = "showBereicheAbteilungen.php";
String showSQLTest = "script.php";
String showSQLTest2 = "statusMeldung.php";
String showSQLTest3 = "statusMeldungChangeStatus.php";

RequestQueue requestQueue;

private RecyclerView recyclerView;
private GridLayoutManager gridLayoutManager;
private CustomAdapter adapter;
private List<MyData> data_list;

ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 1000);


@Override
protected void onCreate(Bundle savedInstanceState) {
    yPos = 5;
    xPos = 5;
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_menue);

    Resources r = getResources();
    showBereicheAbtSQL = showBereicheAbtSQL.replace("xxxx", r.getString(R.string.IP));
    showSQLTest = showSQLTest.replace("xxxx", r.getString(R.string.IP));
    showSQLTest2 = showSQLTest2.replace("xxxx", r.getString(R.string.IP));
    showSQLTest3 = showSQLTest3.replace("xxxx", r.getString(R.string.IP));

    recyclerView = (RecyclerView) findViewById(R.id.recycle_viewer);
    data_list  = new ArrayList<>();
    load_data_from_server(0);
    gridLayoutManager = new GridLayoutManager(this,1);
    recyclerView.setLayoutManager(gridLayoutManager);

    adapter = new CustomAdapter(this,data_list);
    recyclerView.setAdapter(adapter);

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

            if(gridLayoutManager.findLastCompletelyVisibleItemPosition() == data_list.size()-1){
                //load_data_from_server(data_list.get(data_list.size()-1).getId());
            }

        }
    });






    requestQueue = Volley.newRequestQueue(getApplicationContext());

    Intent i = getIntent();
    if (i != null){
        Bereich = i.getStringExtra("Parameter1");
        if (Bereich == null)
        {
            Bereich = "0";
        }
        BezeichnungBereich = i.getStringExtra("Parameter3");
    }
    else
    {
        Bereich = "0";
    }

    if (i != null){
        Abteilung = i.getStringExtra("Parameter2");
        if (Abteilung == null)
        {
            Abteilung = "0";
        }
        BezeichnungAbteilung = i.getStringExtra("Parameter4");
    }
    else
    {
        Abteilung = "0";
    }
    setTitle(BezeichnungBereich + ": " + BezeichnungAbteilung);

    btnStart = (Button) findViewById(R.id.btnStart);
    btnStart.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            Intent myIntent = new Intent(MenueActivity.this, MenueActivity.class);
            myIntent.putExtra("Parameter1", "0");
            myIntent.putExtra("Parameter2", "0");
            finish();
            startActivity(myIntent);
        }
    });

    Button btnNew = (Button) findViewById(R.id.btnNewMessage);
    btnNew.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            //stoptimertask(view);
            Intent myIntent = new Intent(MenueActivity.this, NewMessageActivity.class);
            myIntent.putExtra("Parameter1", Bereich);
            startActivity(myIntent);
        }
    });


    //Bereiche auslesen
    final StringRequest request = new StringRequest(com.android.volley.Request.Method.POST, showBereicheAbtSQL, new com.android.volley.Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            try {
                JSONObject jsonObj = new JSONObject(response.toString());
                JSONArray students = jsonObj.getJSONArray("bereiche");
                int buttonNr = 0;

                for (int i = 0; i < students.length(); i++) {
                    JSONObject student = students.getJSONObject(i);

                    int id = student.getInt("ID");
                    String firstname = student.getString("BEREICH");
                    String lastname = student.getString("VORGAENGER_ID");

                    RelativeLayout layout = (RelativeLayout) findViewById(R.id.activity_menue);

                    Button btnTag = new Button(MenueActivity.this);
                    // btnTag.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                    btnTag.setText(firstname);
                    btnTag.setId(id);
                    btnTag.setY(yPos);
                    btnTag.setX(xPos);
                    btnTag.setWidth(300);
                    btnTag.setBackgroundResource(R.drawable.buttonshape2);
                    btnTag.setOnClickListener(new View.OnClickListener() {

                        @Override
                        public void onClick(View view) {
                            stoptimertask(view);
                            Button btn = (Button) view;
                            Intent myIntent = new Intent(MenueActivity.this, MenueActivity.class);
                            myIntent.putExtra("Parameter1", String.valueOf(view.getId()));
                            myIntent.putExtra("Parameter2", Abteilung);
                            myIntent.putExtra("Parameter3", btn.getText());
                            myIntent.putExtra("Parameter4", BezeichnungAbteilung);

                            finish();
                            startActivity(myIntent);
                        }
                    });

                    layout.addView(btnTag);

                    if (xPos == 5)
                    {
                        xPos = 310;
                    }
                    else
                    {
                        yPos = yPos + 100;
                        xPos = 5;
                    }
                }
                //yPos = yPos + 60;
                //View v = (View) findViewById(R.id.view3);
                //v.setY(yPos);
                yPos = yPos + 30;


                if ("0".equals(Abteilung)) {
                    students = jsonObj.getJSONArray("abteilungen");

                    for (int i = 0; i < students.length(); i++) {
                        JSONObject student = students.getJSONObject(i);


                        int id = student.getInt("ID");
                        String firstname = student.getString("ABTEILUNG");

                        RelativeLayout layout = (RelativeLayout) findViewById(R.id.activity_menue);

                        Button btnTag = new Button(MenueActivity.this);
                        btnTag.setText(firstname);
                        btnTag.setId(id);
                        btnTag.setY(yPos);
                        btnTag.setX(xPos);
                        btnTag.setWidth(300);
                        btnTag.setBackgroundResource(R.drawable.buttonshape);
                        btnTag.setOnClickListener(new View.OnClickListener() {

                            @Override
                            public void onClick(View view) {
                                stoptimertask(view);
                                Button btn = (Button) view;
                                Intent myIntent = new Intent(MenueActivity.this, MenueActivity.class);

                                myIntent.putExtra("Parameter1", Bereich);
                                myIntent.putExtra("Parameter2", String.valueOf(view.getId()));
                                myIntent.putExtra("Parameter3", BezeichnungBereich);
                                myIntent.putExtra("Parameter4", btn.getText());

                                finish();
                                startActivity(myIntent);
                            }
                        });

                        layout.addView(btnTag);

                        if (xPos == 5) {
                            xPos = 310;
                        } else {
                            yPos = yPos + 100;
                            xPos = 5;
                        }
                    }
                }

                RecyclerView test = (RecyclerView) findViewById(R.id.recycle_viewer);
                test.setY(yPos+120);

                requestQueue = null;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }, new com.android.volley.Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {


        }
    }) {

        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> parameters = new HashMap<String, String>();
            parameters.put("ID", Bereich);
            parameters.put("Abteilung", Abteilung);


            return parameters;
        }
    };
    requestQueue.add(request);
}

private void load_data_from_server(int id) {
    if (requestQueue == null) {
        requestQueue = Volley.newRequestQueue(getApplicationContext());

        StringRequest request = new StringRequest(com.android.volley.Request.Method.POST, showSQLTest, new com.android.volley.Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                    if (response.toString().contains("[]") != true) {
                        System.gc();
                        JSONArray array = new JSONArray(response.toString());
                        recyclerView.removeAllViews();
                        if (data_list.size() > 0)
                        {
                            data_list.clear();
                        }

                        System.gc();

                        for (int i = 0; i < array.length(); i++) {

                            JSONObject object = array.getJSONObject(i);

                            MyData data = new MyData(object.getInt("ID"), object.getString("TEXT"),
                                    object.getString("BILD_KLEIN"), object.getInt("STATUS"), object.getString("VON_BEREICH"), object.getString("NACH_BEREICH"), object.getString("DATUM"));

                            statusMeldung(object.getInt("ID"));

                            data_list.add(data);
                        }

                    }
                    //requestQueue = null;
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new com.android.volley.Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {

            }
        }) {

            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> parameters = new HashMap<String, String>();
                parameters.put("BEREICH", Bereich);
                parameters.put("ABTEILUNG", Abteilung);
                return parameters;
            }
        };

        requestQueue.add(request);
    }
}










@Override
protected void onResume() {
    super.onResume();

    //onResume we start our timer so it can start when the app comes from the background
    startTimer();
}

public void startTimer() {
    //set a new Timer
    timer = new Timer();

    //initialize the TimerTask's job
    initializeTimerTask();

    //schedule the timer, after the first 5000ms the TimerTask will run every 10000ms
    timer.schedule(timerTask, 2000, 10000); //
}

public void stoptimertask(View v) {
    //stop the timer, if it's not already null
    if (timer != null) {
        timer.cancel();
        timer = null;
    }
}

public void initializeTimerTask() {

    timerTask = new TimerTask() {
        public void run() {

            //use a handler to run a toast that shows the current timestamp
            handler.post(new Runnable() {
                public void run() {
                    /*//get the current timeStamp
                    Calendar calendar = Calendar.getInstance();
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
                    final String strDate = simpleDateFormat.format(calendar.getTime());

                    //show the toast
                    int duration = Toast.LENGTH_SHORT;
                    Toast toast = Toast.makeText(getApplicationContext(), strDate, duration);
                    toast.show();*/
                    System.gc();
                    tg.stopTone();
                    load_data_from_server(0);
                    System.gc();

                }
            });
        }
    };
}


private String IPAdresse(){
    WifiManager wifiMgr = (WifiManager) getSystemService(WIFI_SERVICE);
    WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
    int ip = wifiInfo.getIpAddress();
    String ipAddress = Formatter.formatIpAddress(ip);

    return  ipAddress;
}

private void statusMeldung(final int id) {



    requestQueue = Volley.newRequestQueue(getApplicationContext());

    StringRequest request = new StringRequest(com.android.volley.Request.Method.POST, showSQLTest2, new com.android.volley.Response.Listener<String>() {
        @Override
        public void onResponse(String response) {

            String test = response.toString();
            if (test.contains("[]") == true)
            {
                //Meldung
                tg.startTone(ToneGenerator.TONE_CDMA_INTERCEPT);


                PendingIntent pi = PendingIntent.getActivity(MenueActivity.this, 0, new Intent(MenueActivity.this, MenueActivity.class), 0);
                Resources r = getResources();
                Notification notification = new NotificationCompat.Builder(MenueActivity.this)
                        //.setTicker(r.getString(R.string.notification_title))
                        //
                        .setSmallIcon(R.mipmap.xxx_logo4)
                        .setContentTitle("Warnung")
                        .setContentText("Neue Meldung")
                        .setContentIntent(pi)
                        .setAutoCancel(true)
                        .build();

                NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                notificationManager.notify(0, notification);




                Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                v.vibrate(2000);
                sleep(3000);

                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //btnPush.setBackgroundResource(R.drawable.common_google_signin_btn_text_dark_normal);
                    }
                }, 3000);

                v.vibrate(2000);
                statusMeldungChangeState(id, IPAdresse(), 1);
            }
            requestQueue = null;
        }
    }, new com.android.volley.Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    }) {

        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> parameters = new HashMap<String, String>();
            parameters.put("ID", Integer.toString(id));
            parameters.put("IP", IPAdresse());

            return parameters;
        }
    };

    requestQueue.add(request);

}

private void statusMeldungChangeState(final int id, final String IP, final int status) {

    requestQueue = Volley.newRequestQueue(getApplicationContext());

    StringRequest request = new StringRequest(com.android.volley.Request.Method.POST, showSQLTest3, new com.android.volley.Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            requestQueue = null;
        }
    }, new com.android.volley.Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    }) {

        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> parameters = new HashMap<String, String>();
            parameters.put("ID", Integer.toString(id));
            parameters.put("IP", IPAdresse());
            parameters.put("SATUS", Integer.toString(status));

            return parameters;
        }
    };

    requestQueue.add(request);

}

}

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

29.12.2016, 20:16:42 via Website

Habe jetzt den Code nur überflogen, aber schmeißt du auch umötige Daten wieder raus indem du die Objekte mit finalize verwirfst?

— geändert am 29.12.2016, 20:18:13

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Thomas Bregler
  • Forum-Beiträge: 2

30.12.2016, 10:17:06 via Website

Es handelt sich um diese Funktion die ich regelmäßig aufrufe...habe da jetzt auch mal finalize hinzugefügt jedoch ohne Erfolg:

private void load_data_from_server(int id) {
        if (requestQueue == null) {
            requestQueue = Volley.newRequestQueue(getApplicationContext());

            StringRequest request = new StringRequest(com.android.volley.Request.Method.POST, showSQLTest, new com.android.volley.Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    try {
                        if (response.toString().contains("[]") != true) {
                            System.gc();
                            JSONArray array = new JSONArray(response.toString());
                            recyclerView.removeAllViews();
                            /*if (data_list.size() > 0)
                            {
                                data_list.clear();
                            }*/
                            int size = data_list.size();
                            if (size > 0) {
                                for (int i = 0; i < size; i++) {
                                    data_list.remove(0);
                                }
                            }
                            adapter.clearData();
                            try {
                                finalize();
                            } catch (Throwable throwable) {
                                throwable.printStackTrace();
                            }


                            System.gc();

                                for (int i = 0; i < array.length(); i++) {

                                    JSONObject object = array.getJSONObject(i);

                                    MyData data = new MyData(object.getInt("ID"), object.getString("TEXT"),
                                            object.getString("BILD_KLEIN"), object.getInt("STATUS"), object.getString("VON_BEREICH"), object.getString("NACH_BEREICH"), object.getString("DATUM"));

                                    statusMeldung(object.getInt("ID"));

                                    data_list.add(data);
                                }
                            }

                        //requestQueue = null;
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }, new com.android.volley.Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {

                }
            }) {

                @Override
                protected Map<String, String> getParams() throws AuthFailureError {
                    Map<String, String> parameters = new HashMap<String, String>();
                    parameters.put("BEREICH", Bereich);
                    parameters.put("ABTEILUNG", Abteilung);
                    return parameters;
                }
            };

            requestQueue.add(request);
        }
    }

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

30.12.2016, 10:33:04 via App

hmm komisch...
Mach mal ein Langzeitdebug und betrachte wie sich der RAM verändert. Vlt bekommst du über AS auch raus was wieviel RAM braucht

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten