Android Things -> Flickering while controlling 8x8 LED matrix by 74hc595 multiplexing - java

Hi I am stuck while i was trying to control 8x8 led matrix by cascading two 74hc595 shift registers. I had build the circuit and the program, which I am including here. It's actually giving me the right output. But the major problem is visible flickering. Can somebody guide me what can i do to remove the flickering?
public class MainActivity extends Activity {
private static final String SR_SRCLK_PIN = "BCM27"; //clock pins shcp
private static final String SR_RCLK_PIN = "BCM18"; //latch pin stcp
private static final String SR_SDI_PIN = "BCM17"; //data pin
private static final String TAG = "MAT21";
private Gpio mRCLK;
private Gpio mSRCLK;
private Gpio mSDI;
private int charSeq=0;
int data[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //NULL
0x00,0x00,0x3C,0x42,0x42,0x3C,0x00,0x00, //0
0x00,0x00,0x00,0x44,0x7E,0x40,0x00,0x00, //1
0x00,0x00,0x44,0x62,0x52,0x4C,0x00,0x00, //2
0x00,0x00,0x78,0x14,0x12,0x14,0x78,0x00, //A
0x00,0x00,0x60,0x90,0x90,0xFE,0x00,0x00, //d
0x00,0x00,0x1C,0x2A,0x2A,0x2A,0x24,0x00, //e
0x00,0x00,0x7E,0x12,0x12,0x0C,0x00,0x00, //p
0x00,0x00,0x08,0x7E,0x88,0x40,0x00,0x00, //t
0x3C,0x42,0x95,0xB1,0xB1,0x95,0x42,0x3C, //:)
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PeripheralManagerService pms = new PeripheralManagerService();
try {
mRCLK = pms.openGpio(SR_RCLK_PIN);
mRCLK.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
mSRCLK = pms.openGpio(SR_SRCLK_PIN);
mSRCLK.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
mSDI = pms.openGpio(SR_SDI_PIN);
mSDI.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
}
try {
thread.start();
while (true){
Thread.sleep(2000);
charSeq++;
if(charSeq==10){
charSeq=0;
}
}
} catch (Exception sd) {
}
}
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
for (int rowNum = 0; rowNum < 8; rowNum++) {
mRCLK.setValue(false);
shiftOut(data[(charSeq * 8) + rowNum],rowNum);
mRCLK.setValue(true);
}
}
}catch (Exception ex){
}
}
});
#Override
protected void onDestroy() {
super.onDestroy();
// Clean all resources
if (mSDI != null) {
try {
mSDI.setValue(false);
mSDI.close();
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
}
}
if (mRCLK != null) {
try {
mRCLK.setValue(false);
mRCLK.close();
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
}
}
if (mSRCLK != null) {
try {
mSRCLK.setValue(false);
mSRCLK.close();
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
}
}
}
void shiftOut(int data, int rowNum) {
try {
for (int i = 7; i >= 0; i--) {
mSRCLK.setValue(false);
mSDI.setValue((((data >> i) & 1) == 0));
mSRCLK.setValue(true);
}
for (int i = 0; i <8; i++) {
mSRCLK.setValue(false);
mSDI.setValue(i==rowNum?true:false);
mSRCLK.setValue(true);
}
} catch (Exception sd) {
}
}
}
Schemetic Diagram

It's not entirely clear from your question what clock frequency you need to achieve to drive your matrix display properly, but regardless it's unlikely you will be able to get there bit-banging the GPIO in this fashion. The flickering you see is probably because the I/O is not toggling fast enough in your code.
I would recommend moving to an external hardware controller for your display (something like the MAX7219, for example) that you can control over a serial port like I2C or SPI.

Related

How to download a file after clicking a button (Android Studio)

I recently created an activity in my app. Now I wanted the user to download a .pdf file when he/she wants to view the guidelines. I wanted to implement this on a button. Any idea how to do this properly?
Heres my code below:
public class Exhibitor_Registration_Activity extends AppCompatActivity {
Button buttonDownload;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exhibitor_registration_);
this.setTitle("Buyer Registration");
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
myToolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
final Button buttonDownload = (Button) findViewById(R.id.buttonDownload);
buttonDownload.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
try {
//this is the file you want to download from the remote server
String path ="http://www.manilafame.com/website-assets/downloads/exhibitor-application-kit/local/201704/1-Summary-of-Participation-Details-April-2017_MN_002.pdfp";
//this is the name of the local file you will create
String targetFileName = null;
boolean eof = false;
URL u = new URL(path);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
FileOutputStream f = new FileOutputStream(new File("c:\\junk\\"+targetFileName));
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) > 0 ) {
f.write(buffer,0, len1);
}
f.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
I also got the source code from here and here.
if you want resumable, speed of download ...
follow this steps
create a class DownloadManager.java
public class DownloadManager extends AsyncTask<String,String,String>{
String downloadlink,fileDestination;
public static final int ON_INIT=100,ON_ERROR=102,ON_PROGRASS=103,ON_COMPLETED=104,STATUS_DOWNLOADED=1500,STATUS_NOT_YET=1501;
private onUpdateListener onUpdateListener;
private String downloadedPath="";
private long downloaded=0;
private File file;
private String returnData=null;
private File cacheDownloadFile;
public DownloadManager(String downloadlink,String fileDestinationPath){
this.downloadlink=downloadlink;
this.fileDestination=fileDestinationPath;
file=new File(fileDestination, Tools.getFileName(downloadlink));
cacheDownloadFile=new File(AppCostants.CHACHE_PATH+Tools.getFileName(downloadlink));
try {
if(cacheDownloadFile.isFile())
downloaded=Tools.getFileSize(cacheDownloadFile);
else
downloaded=0;
Log.d("FILE_DOWNLOAD_TAG_p",downloaded+" <- "+cacheDownloadFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
fireOnUpdate(ON_INIT,"init ...");
}
#Override
protected String doInBackground(String... params) {
try {
File dir=new File(fileDestination);
File chacheDir=new File(AppCostants.CHACHE_PATH);
if(!chacheDir.isDirectory())
chacheDir.mkdirs();
if(!dir.isDirectory()){
dir.mkdirs();
}
if(file.exists()) {
Log.d("FILE_DOWNLOAD_TAG","File exist return complete");
return "COMPLETED";//file exist
}
if(!cacheDownloadFile.exists()){
cacheDownloadFile.createNewFile();
}
Log.d("FILE_DOWNLOAD_TAG","LINK "+downloadlink);
URL url=new URL(downloadlink);
HttpURLConnection urlConnection= (HttpURLConnection) url.openConnection();
if(downloaded>0)
urlConnection.setRequestProperty("Range","byte="+downloaded);
urlConnection.connect();
int status = urlConnection.getResponseCode();
InputStream inputStream=urlConnection.getInputStream();
int totalSize=urlConnection.getContentLength();
if(totalSize<=downloaded){
returnData= "COMPLETED";
publishProgress("File checked "+Tools.getFileName(file.getAbsolutePath()));
return returnData;
}
this.downloadedPath=cacheDownloadFile.getAbsolutePath();
byte[] buffer=new byte[1024];
int bufferLength=0;
FileOutputStream fileOutput=new FileOutputStream(cacheDownloadFile);
long d=0;
long starttime=System.currentTimeMillis();
while ((bufferLength=inputStream.read(buffer))>0){
fileOutput.write(buffer,0,bufferLength);
downloaded+=bufferLength;
d+=bufferLength;
//String l=" "+Tools.getFileName(file.getAbsolutePath())+" ( "+Tools.convertMemory(downloaded)+" / "+Tools.convertMemory(totalSize)+" )";
String l=" "+Tools.convertMemory(downloaded)+" / "+Tools.convertMemory(totalSize)+" ( "+getDownloadSpeed(starttime,d)+" )";
publishProgress(l);
if(downloaded>=totalSize){
break;
}
}
Log.d("FILE_DOWNLOAD_TAG","DWONLOADED TO "+downloadedPath+" ("+cacheDownloadFile.length()+")");
fileOutput.close();
if(Tools.fileCopy(file,cacheDownloadFile)){
Log.d("FILE_DOWNLOAD_TAG","file Copied, delete cache");
cacheDownloadFile.delete();
}
returnData="COMPLETED";
} catch (MalformedURLException e) {
returnData=null;
e.printStackTrace();
publishProgress(e.toString());
Log.d("###################",e+"");
} catch (IOException e) {
returnData=null;
e.printStackTrace();
publishProgress(e.toString());
}
return returnData;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
fireOnUpdate(ON_PROGRASS,values[0]);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if(s!=null){
fireOnUpdate(ON_COMPLETED,downloadedPath);
}else{
fireOnUpdate(ON_ERROR,"Download failed");
}
}
public interface onUpdateListener{
void onUpdate(int code,String message);
}
public void setOnUpdateListener(onUpdateListener onUpdateListener){
this.onUpdateListener=onUpdateListener;
}
private void fireOnUpdate(int code,String message){
if(onUpdateListener!=null)
onUpdateListener.onUpdate(code,message);
}
private String getDownloadSpeed(long starttime,float totalDownloaded) {
long elapsedTime = System.currentTimeMillis() - starttime;
//byte :
float speed=1000f * totalDownloaded / elapsedTime;
return convert(speed);
}
private String convert(float value){
long kb=1024
,mb=kb*1024
,gb=mb*1024;
if(value<kb){
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.')+2);
return speed+" B/s";
}else if(value<mb){
value=value/kb;
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.'));
return (speed)+" KB/s";
}else if(value<gb){
value=(value/mb);
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.'));
return speed+" MB/s";
}
return "";
}
}
use this code in onClick()
DownloadManager downloadManager = new DownloadManager(url,filepath);
set event
downloadManager.setOnUpdateListener(new DownloadManager.onUpdateListener() {
#Override
public void onUpdate(int code, String message) {
if (code == DownloadManager.ON_COMPLETED) {
}
if(DownloadManager.ON_PROGRASS==code){}
}
});
start download by
downloadManager.execute();
lib setup
compile "commons-io:commons-io:+"
Tools.java
public static long getFileSize(File file) throws IOException {
FileOutputStream fileOutputStream=new FileOutputStream(file);
fileOutputStream.close();
return file.length();
}
public static boolean fileCopy(File dest,File source){
try {
FileUtils.copyFile(source,dest);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
It is really bad idea to download file in main thread.
Use separate Thread for this
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
//your downloading here
}
});
thread.start();
it`s better, but still not so good. There are some problems with it:
1) User know nothing about downloading
So better to show additional layout which overlays screen with progress bar, probably indeterminate if you want to write less code. Then after downloading is finished you just hide your layout.
You can use runOnUiThread inside run method in thread for it.
runOnUiThread(new Runnable() {
#Override
public void run() {
//just hide some popup
//or do what you want after downloading is finished
popupLayout.serVisibility(View.GONE);
}
});
2) If user will do action which re-creates activity/fragment (like changing screen orientaion) with running thread you will get memory leak and probably activity will not know about end of download.
There are few ways to solve this problem:
You can block screen orientation at this screen, at least while downloading. Probably easiest way in your case.
You can use downloading in foreground service. Its really good
practice, but you will have to learn about services.
You can try to interrupt downloading by calling thread.interrupt()
method in onDestroy of your Activity/Fragment
You can use something like rxJava/rxAndroid (so you don not use threads at all, but you need some time for learn rxJava)
UPD
About threads
Not so bad tutorial about threads in android
You can use AsyncTask instead of Thread, but I highly recommend to use threads especially for long operations.

Android: how to get data from Runnable using postDelayed method?

I am using Runnable to get data from GPS device, but sometimes cannot get data from outside although value inside always has value.
BaseSevice.java
protected Handler mHandler = new Handler();
protected volatile String mRawLine;
protected Runnable mReadDeviceDataTask = new Runnable() {
public void run() {
int delay = Constants.DEFAULT_GET_DATA_INTERVAL; //interval = 100ms
if (deviceType() == DeviceSupport.GPS) {
delay = Constants.GPS_GET_DATA_INTERVAL; //interval = 10ms
}
if (mDevice == null) {
mHandler.postDelayed(mReadDeviceDataTask, delay);
return;
}
try {
if (mInputStream.available() > 0) {
mRawLine = "some data here get from GPS device"; //data got continuously & many lines
}
} catch (IOException ioEx) {
throw new RuntimeException("Can not read lines from socket", ioEx);
} catch (Exception e) {
throw new RuntimeException("Error while read from input stream", e);
}
mHandler.postDelayed(mReadDeviceDataTask, delay);
}
};
GPSService.java extends BaseService
public String getmRawLine() {
Log.e("debug","return mRawLine:" + mRawLine);
return mRawLine;//<--- sometimes there is no value
}

How to send (from Native code) a android.content.Context parameter to a Java fct (via JNI)

I am developping an application for my android phone, and I am trying to enable the Wifi hotspot.
I am using Qt 5.4.1 so I developp in C++.
As there is not any function to do this in the NDK, I am using JNI to call Java Methods.
My java code is (thanks to Ashish Sahu's answer in stackoverflow thread) :
package org.app.test;
import android.content.*;
import android.net.wifi.*;
import java.lang.reflect.*;
//Class that handles Wifi Hotspot (access point) configuration
public class ApManager {
//Is Wifi hotspot on or off ?
public static boolean isApOn(Context context) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
try {
Method method = wifimanager.getClass().getDeclaredMethod("isWifiApEnabled");
method.setAccessible(true);
return (Boolean) method.invoke(wifimanager);
}
catch (Throwable ignored) {}
return false;
}
//Turn Wifi hotspot on or off
public static boolean configApState(Context context, boolean b) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
WifiConfiguration wificonfiguration = null;
try {
//if Wifi is on, turn it off
if(isApOn(context)) {
wifimanager.setWifiEnabled(false);
}
Method method = wifimanager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method.invoke(wifimanager, wificonfiguration, b);
return true;
}
catch(Exception e) {
e.printStackTrace();
}
return false;
}
}
C++ code sample :
setWifiApEnabled(QAndroidJniObject context, bool b)
{
return QAndroidJniObject::callStaticMethod<jboolean>("org/app/test/ApManager"
, "configApState"
, "(Ljava/lang/Object;Z)Z" //Or (Landroid/content/Context;Z)Z ???
, context.object<jobject>()
, b);
}
But now I have a problem ; how to get the parameter context to pass to the function setWifiApEnabled(context, b) when I call it ?
I am a little lost, I read some threads about this problem (like this one) but I do not totally understand what the people who answered meant.
Could you help me with this ?
EDIT : I found on this stackoverflow thread a way to get the context :
interface = QApplication::platformNativeInterface();
activiti = (jobject)interface->nativeResourceForIntegration("QtActivity");
at = new QAndroidJniObject(activiti);
appctx = at->callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
if(appctx.isValid()) qDebug() << "I am valid !";
else qDebug() << "I ain't valid !";
appctx is valid, but the Wifi hotspot doesn't get enabled and I cannot get its state.
EDIT 2 : : I successfully managed to enable the Wifi hotspot in java, using Android Studio. The code is the following :
WifiApManager.java :
public class WifiApManager {
private WifiManager wifiMan;
protected Method setWifiApEnabledMethod, isWifiApEnabledMethod;
protected final static int MAX_ITER = 10;
public WifiApManager(WifiManager wifiMan) {
this.wifiMan = wifiMan;
getHiddenMethods();
}
private void getHiddenMethods() {
try {
setWifiApEnabledMethod = wifiMan.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
isWifiApEnabledMethod = wifiMan.getClass().getMethod("isWifiApEnabled");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public boolean isWifiApEnabled() {
try {
return (Boolean)isWifiApEnabledMethod.invoke(wifiMan);
} catch (Exception e) {
return false;
}
}
public boolean isWifiEnabled() {
return wifiMan.isWifiEnabled();
}
public boolean setWifiApEnabled(WifiConfiguration conf, boolean enabled) {
try {
return (Boolean) setWifiApEnabledMethod.invoke(wifiMan, conf, true);
} catch (Exception e) {
return false;
}
}
public boolean toggleWifi(String ssid) {
// WifiConfiguration creation:
WifiConfiguration conf = new WifiConfiguration();
conf.SSID = ssid;
conf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
// If AP Wifi is enabled, disables it and returns:
if(isWifiApEnabled()) {
//setWifiApEnabled(null, false); Won't work, see two further lines
wifiMan.setWifiEnabled(true);
wifiMan.setWifiEnabled(false);
int maxIter = MAX_ITER;
while (isWifiApEnabled() && maxIter-- >= 0) {
try {Thread.sleep(500);} catch (Exception e) {}
}
return isWifiApEnabled();
}
// If standard Wifi is enabled, disables it:
if (isWifiEnabled()) {
if (wifiMan.setWifiEnabled(false)) {
int maxIter = MAX_ITER;
while (wifiMan.isWifiEnabled() && maxIter-- >= 0) {
try {Thread.sleep(500);} catch (Exception e) {}
}
}
if (isWifiEnabled()) {
return false;
}
}
// Enables AP Wifi
try {
if (! setWifiApEnabled(conf, true)) {
System.out.println("setWifiApEnabledMethod failed.");
return false;
}
int maxIter = MAX_ITER;
while (! isWifiApEnabled() && maxIter-- > 0) {
try {Thread.sleep(500);} catch (Exception e) {}
}
} catch(Exception e) {
e.printStackTrace();
return false;
}
return true;
}
}
Main class :
public class AndroidMenusActivity extends Activity implements OnClickListener {
private WifiApManager wifiMan;
private ToggleButton wifiButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wifiMan = new WifiApManager((WifiManager) this.getSystemService(Context.WIFI_SERVICE));
setContentView(R.layout.activity_android_menus);
makeUI();
}
private void makeUI() {
LinearLayout subLayout = (LinearLayout) findViewById(R.id.subLayout);
wifiButton = new ToggleButton(this);
wifiButton.setTextOn("Disable Wifi");
wifiButton.setTextOff("Enable AP Wifi");
wifiButton.setChecked(wifiMan.isWifiApEnabled());
wifiButton.setOnClickListener(this);
subLayout.addView(wifiButton);
}
#Override
public void onClick(View sender) {
if (!wifiButton.equals(sender))
return;
AsyncTask<Object, Void, Boolean> task = new AsyncTask<Object, Void, Boolean>() {
private ToggleButton bt;
private WifiApManager wm;
#Override
protected Boolean doInBackground(Object... args) {
bt = (ToggleButton) args[0];
wm = (WifiApManager) args[1];
return wm.toggleWifi("test.com");
}
#Override
protected void onPostExecute (Boolean result) {
bt.setChecked(result.booleanValue());
bt.setEnabled(true);
}
};
wifiButton.setEnabled(false);
task.execute(wifiButton, wifiMan);
}
}
But I cannot find a way to do the same in C++, any help ?
Just in order to transfer context object from C++ to JNI, use auto-injection like that:
QtAndroid::androidActivity().callStaticMethod<void>(
"com/company/project/MyApp",
"myFunc", // method name
"(Landroid/content/Context;)V" // auto-injection
);

Android UI from other thread

I'm creating an application that gets the get the homestatus from a server in json but this happens on another thread. this isn't a problem when i try to set most Items on the ui because i can set them in a static void. but when i try to create a new switch and space i can't call 'this' to create a new.
code for getting the homestatus:
public void loadHomeStatus()
{
if(socket != null) {`enter code here`
if (socket.isConnected()) {
Log.d("BtnUpdate","already connected");
return;
}
}
swAlarm = (Switch) findViewById(R.id.swAlarmState);
tvTemperature = (TextView) findViewById(R.id.tvTemprateur);
tvHumidity = (TextView) findViewById(R.id.tvHumidity);
llDevices = (LinearLayout) findViewById(R.id.llDevices);
new Thread() {
public void run() {
try
{
busyConnecting = true;
Log.d("loadHomeStatus","trying to connect to: " + host + ":" + port);
socket = new Socket(host, port);
uiConnected();
Log.d("loadHomeStatus","Connected");
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
DataInputStream is = new DataInputStream(socket.getInputStream());
os.writeBytes(password);
Log.d("Connect", "send: " + password);
while (socket.isConnected()) {
byte[] data = new byte[500];
int count = is.read(data);
String recieved = new String(data).trim();
Log.d("loadHomeStatus","recieved " + recieved );
if(recieved.toLowerCase() == "failed")
{
Log.d("loadHomeStatus","failed to log in");
}
else
{
try
{
homeStatus = new Gson().fromJson(recieved, HomeStatus.class);
uiLoadStatus();
} catch (Exception e)
{
Log.d("Error", e.toString());
}
}
}//end of while loop
Log.w("loadHomeStatus", "end connection thread ");
//ends thread
Thread.currentThread().interrupt();
return;
}
catch (UnknownHostException e)
{
e.printStackTrace();
Log.w("loadHomeStatus", "no Failed to connect: " + host + "-" + 8001);
}
catch (IOException e)
{
e.printStackTrace();
Log.w("loadHomeStatus", "no Failed to connect: " + host + "-" + 8001);
}
Log.w("loadHomeStatus","Connection ended");
socket = null;
busyConnecting = false;
uiDisconnected();
}
}.start();
}`
Code for setting ui
public static void uiLoadStatus()
{
if (homeStatus != null)
{
try {
tvTemperature.post(new Runnable()
{
public void run()
{
//Log.d("uiLoadStatus to string",homeStatus.toString());
tvTemperature.setText(homeStatus.temperature + "°C");
tvHumidity.setText(homeStatus.humidity + "%");
}
});
}
catch(Exception e)
{
Log.d("uiLoadStatus status fragment", e.toString());
}
try {
swAlarm.post(new Runnable()
{
public void run() {
swAlarm.setChecked(homeStatus.alarmState);
}
});
}
catch (Exception e)
{
Log.d("uiLoadStatus alarm fragment", e.toString());
}
}
try {
llDevices.post(new Runnable()
{
public void run() {
uiLoadDevices(); //this gives and error because it's not static
}
});
}
catch (Exception e)
{
Log.d("uiLoadStatus alarm fragment", e.toString());
}
}
public void uiLoadDevices()
{
for (int i = 0; i < homeStatus.lstDevices.size(); i++) {
String deviceAdd = homeStatus.lstDevices.get(i);
Space mySpace = new Space(this);
Switch mySwitch = new Switch(this);
mySpace.setMinimumHeight(50);
mySwitch.setText(homeStatus.getName(deviceAdd));
mySwitch.setChecked(homeStatus.getState(deviceAdd));
mySwitch.setTextSize(18);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.LEFT;
llDevices.addView(mySpace, lp);
llDevices.addView(mySwitch, lp);
}
}
You should use AsyncTask and put the network interaction part in the doInBackground() method. To update the UI components, implement those logics in the onPostExecute() method
uiLoadStatus is a static method (not sure why or if it has to be without looking at all of your code) and therefore you cannot call non-static methods from within it, such as uiLoadDevices
I would advise taking a look at your code and update your uiLoadStatus to not be static if at all possible. Abusing static can lead to sloppy code.

Service takes too much memory

I have a service that extracting html code from an URL, converting it to text only (with Jsoup) and then checks something on the string, and if some conditions are true it launches a notification and writes something to a file.
As far as I know, this kind of service shouldn't take much memory, and in Watchdog, it takes ~65 MB, and it is way too much. It takes more than any other process (even more than tw launcher and Android System).
I would like you to tell me what have I done wrong.
Heres my service class:
public class NotifyService extends Service
{
private int number=0;
private Timer timer=new Timer();
private long INTERVAL=1*1000*60*60;//1 hour
public static String Oldhtml;
public static String Newhtml;
public static String currHtml;
// hooks main activity here
/*
* not using ipc...but if we use in future
*/
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate()
{
super.onCreate();
_startService();
Log.w("myApp", "START");
}
#Override
public void onDestroy()
{
super.onDestroy();
_shutdownService();
Log.w("myApp", "STOPPED");
}
/*
* starting the service
*/
private void _startService()
{
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
try {
doServiceWork();
} catch (ClientProtocolException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},0,INTERVAL);
;
}
/*
* start the processing, the actual work, getting config params, get data from network etc
*/
private void doServiceWork() throws ClientProtocolException, IOException
{
String FILENAME="blichData";
String info=null;
String classLetter = null,classNum1=null;
int classNum = 0;
try{
FileInputStream fis=openFileInput(FILENAME);
byte[] dataArray = new byte[fis.available()];
while(fis.read(dataArray)!=-1)
{
info = new String(dataArray);
}
classLetter = info.substring(0, info.lastIndexOf(" "));
classNum1 =info.substring(info.lastIndexOf(" ")+1);
classNum=Integer.parseInt(classNum1);
fis.close();
}catch (Exception e){
}
if (classLetter!=null && classNum1!=null) {
Oldhtml=readHTMLfromFile();
if (GetHTML.isHavingChanges(classLetter,classNum))
{
myNotify();
writeHTMLtoFile(currHtml);
/*
try {
String data= "false";
FileOutputStream fos = openFileOutput("blichService", Context.MODE_PRIVATE);
fos = openFileOutput("blichService",Context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
}
catch (Exception e) {}
*/
}
}
;
}
/*
* shutting down the service
*/
private void _shutdownService()
{
if (timer != null) timer.cancel();
Log.i(getClass().getSimpleName(), "Timer stopped...");
}
public void writeHTMLtoFile(String html) {
try {
String FILENAME = "blichNotifyData";
String data= html;
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos = openFileOutput(FILENAME,Context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
}
catch (Exception e){}
}
public String readHTMLfromFile() {
String FILENAME = "blichNotifyData";
String info="";
try{
FileInputStream fis=openFileInput(FILENAME);
if (fis.available()>0)
{
byte[] dataArray = new byte[fis.available()];
while(fis.read(dataArray)!=-1)
{
info = new String(dataArray);
}
fis.close();
}
else {
Oldhtml="null";
}
}
catch (Exception e) {}
return info;
}
public void myNotify()
{
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent= new Intent (this,SchoolBlichActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
String body = " בליך";
String title = "ישנם שינויים חדשים!";
Notification n =new Notification(R.drawable.table, body, System.currentTimeMillis());
n.flags |=Notification.FLAG_AUTO_CANCEL;
n.setLatestEventInfo(getApplicationContext(), title, body, pi);
n.defaults = Notification.DEFAULT_ALL;
number++;
n.number=number;
nm.notify(0,n);
}
}
And if it is needed, the HTML extracting class:
public class GetHTML {
public static boolean isHavingChanges(String classLetter,int classNum) throws ClientProtocolException, IOException {
int classLetterCode = 0;
int timeTableCode=1;
if (classLetter.equals("ט"))
classLetterCode=0;
else if (classLetter.equals("י"))
classLetterCode=1;
else if (classLetter.equals("יא"))
classLetterCode=2;
else if (classLetter.equals("יב"))
classLetterCode=3;
switch(classLetterCode)
{
case 0:
if (classNum>=1 && classNum<=7)
timeTableCode=1;
else if (classNum>7 && classNum<=14)
timeTableCode=2;
break;
case 1:
if (classNum>=1 && classNum<=7)
timeTableCode=3;
else if (classNum>7 && classNum<=14)
timeTableCode=4;
break;
case 2:
if (classNum>=1 && classNum<=7)
timeTableCode=5;
else if (classNum>7 && classNum<=14)
timeTableCode=6;
break;
case 3:
if (classNum>=1 && classNum<=7)
timeTableCode=7;
else if (classNum>7 && classNum<=14)
timeTableCode=8;
break;
}
String url = "http://blich.iscool.co.il/DesktopModules/IS.TimeTable/MainScreen.aspx?pid=17&mid=6264&page="+timeTableCode+"&msgof=0&static=1";
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
String html = "";
InputStream in = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder str = new StringBuilder();
String line = null;
while((line = reader.readLine()) != null)
{
str.append(line);
}
in.close();
html = str.toString();
html = Jsoup.parse(html).text();
if (NotifyService.Oldhtml.equalsIgnoreCase(html)) {
return false;
}
if (timeTableCode%2!=0){
for (int i=0;i<8;i++) {
if (!html.contains(i+" "+i)) {
NotifyService.currHtml=html;
return true;
}
}
}
if (timeTableCode%2==0) {
for (int i=8;i<15;i++) {
if (!html.contains(i+" "+i)) {
NotifyService.currHtml=html;
return true;
}
}
}
return false;
}
}
Ignore the foreign language. xD
I just want to understand what have I done wrong?
Thanks
While I cannot tell out-of-the-box what portion of your code is problematic, you may try to analyze the memory usage through a heap dump taken with DDMS using Eclipse MAT. You will need to use the hprofconv tool to convert your Android heap dump into a format that MAT understands.
To get the HPROF Heap Dump, open the Dalvik Debug Monitor (DDMS), connect it you your emulator, select the process of your application and hit the "Dump HPROF file" icon.

Categories

Resources