Adrian P.

Adrian P. pamiętaj o tym, kto
chce latać musi
skoczyć

Temat: własna aplikacja i kilka pytań

Cześć,

właśnie jestem w trakcie pisania swojej pierwszej aplikacji.
Ogólnie chcę zrobić aplikację w której będzie można przeglądać artykuły i czytać swoje pw (logowanie).
I mam kilka pytań:
1. Jak zrobić aby po wciśnięciu lewego przycisku na klawiaturze wyskoczyło menu a w nim kilka akcji?
2. Po ustawieniu telefonu poziomo lub pionowo od nowa pobiera artykuły, jak to zablokować? Wzorowałem się na tym artykule: http://www.androidhive.info/2012/05/how-to-connect-and...
3. http://www.androidhive.info/2012/02/android-custom-lis... - dzięki temu artykułowi zrobiłem cache'owanie obrazków, ale zastanawiam się jak zrobić aby po jakimś czasie były one usuwane, jak to zrobić?
W klasie LazyAdapter dałem warunek:
if (article.get(CustomizedListView.KEY_THUMB_URL).length()>0) {	imageLoader.DisplayImage(song.get(CustomizedListView.KEY_THUMB_URL), thumb_image);
} else {
image.setVisibility(View.GONE);
}

Zauważyłem, że jak przewinę listę i wrócę na górę to obrazki znikają - czemu to dzieje się? Jak to poprawić?
4. http://www.androidhive.info/2012/01/android-login-and-... - czy taki proces logowania jest bezpieczny?
5. Niektóre aplikacje mają możliwość przeniesienia ich na kartę pamięci - jak coś takiego wykonać?
6. Gdy nie mam połączenia z internetem wywala mi błąd i zamyka aplikację. Podejrzewam, że chodzi o to ciągłe pobieranie artykułów, tylko jak temu zapobiec?

Dziękuję za odpowiedziTen post został edytowany przez Autora dnia 22.07.13 o godzinie 18:42

Temat: własna aplikacja i kilka pytań

Adrian P.:
Cześć,

właśnie jestem w trakcie pisania swojej pierwszej aplikacji.
Ogólnie chcę zrobić aplikację w której będzie można przeglądać artykuły i czytać swoje pw (logowanie).
I mam kilka pytań:
1. Jak zrobić aby po wciśnięciu lewego przycisku na klawiaturze wyskoczyło menu a w nim kilka akcji?

Przechwycenie kliknięcia w menu button:
http://stackoverflow.com/questions/8137325/android-how...

Menu w Androidzie:
http://developer.android.com/guide/topics/ui/menus.html

Teraz odchodzi się od użycia przycisku menu na rzecz actionbara. Więcej informacji:
http://android-developers.blogspot.com/2012/01/say-goo...
2. Po ustawieniu telefonu poziomo lub pionowo od nowa pobiera artykuły, jak to zablokować? Wzorowałem się na tym artykule: http://www.androidhive.info/2012/05/how-to-connect-and...

Podczas obrotu ekranu activity jest niszczone i tworzone na nowo.

Należy dodać następujący atrybut w swoim activity w Manifeście:
android:configChanges="orientation"

W Androidzie 2.1. może to nie wystarczyć, dlatego warto trochę zmodyfikować ten kod:
android:configChanges="keyboardHidden|orientation"


Po tym zabiegu activity zostanie "podtrzymane przy życiu". Nie zawsze jest to najlepsze rozwiązanie, ale w Twoim przypadku powinno się sprawdzić.
3. http://www.androidhive.info/2012/02/android-custom-lis... - dzięki temu artykułowi zrobiłem cache'owanie obrazków, ale zastanawiam się jak zrobić aby po jakimś czasie były one usuwane, jak to zrobić?

Po jakim czasie? Możesz zapisać datę utworzenia cache i podczas uruchamiania aplikacji czyścić cache, jeśli jest ono przestarzałe. Możesz też puścić serwis (Service) w tle, który będzie czyścił lub tworzył cache.
W klasie LazyAdapter dałem warunek:
if (article.get(CustomizedListView.KEY_THUMB_URL).length()>0) {	imageLoader.DisplayImage(song.get(CustomizedListView.KEY_THUMB_URL), thumb_image);
} else {
image.setVisibility(View.GONE);
}

Zauważyłem, że jak przewinę listę i wrócę na górę to obrazki znikają - czemu to dzieje się? Jak to poprawić?

Nie wczytywałem się w cały kod, ale ustawiasz widoczność grafik na GONE, gdy nie spełniają wcześniejszego warunku, więc ich nie widać. Jeśli usuniesz warunek w instrukcji else, grafiki nie będą ukrywane.
4. http://www.androidhive.info/2012/01/android-login-and-... - czy taki proces logowania jest bezpieczny?

Ciężko powiedzieć. Praktycznie każde żądanie, które nie jest przesyłane za pośrednictwem połączenia szyfrowanego po SSL-u jest niebezpieczne. Niemniej jednak, w tym artykule są zastosowane dość dobre praktyki, tj. użycie algorytmu sha1 zamiast md5, solenie haseł, unikalne id dla użytkowników. Nie wygląda to najgorzej. Jeśli nie piszesz aplikacji dla banku, to możesz z takiego rozwiązania skorzystać.
5. Niektóre aplikacje mają możliwość przeniesienia ich na kartę pamięci - jak coś takiego wykonać?

Dodaj atrybut
android:installLocation="auto"

do tagu <manifest> w pliku AndroidManifest.xml
Target API musi być ustawione na conajmniej: 8. Gdy skompilujesz i uruchomisz aplikację, a następnie wejdziesz w ustawienia, zarządzanie aplikacjami i ustawienia Twojej aplikacji, powinna się pojawić opcja "Przenieś aplikację na kartę SD".
6. Gdy nie mam połączenia z internetem wywala mi błąd i zamyka aplikację. Podejrzewam, że chodzi o to ciągłe pobieranie artykułów, tylko jak temu zapobiec?


Przed każdą próbą pobrania danych, sprawdzaj, czy masz połączenie z internetem.
Opis, jak to zrobić, znajdziesz w oficjalnej dokumentacji Androida: http://developer.android.com/training/monitoring-devic...
Dziękuję za odpowiedziTen post został edytowany przez Autora dnia 30.07.13 o godzinie 19:20
Adrian P.

Adrian P. pamiętaj o tym, kto
chce latać musi
skoczyć

Temat: własna aplikacja i kilka pytań

Dzięki za podpowiedzi...

Mam taki kod:
package com.testowa;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.http.NameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.testowa.lazylist.LazyAdapter;
import com.example.testowa.R;

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Toast;

public class MainActivity extends ListActivity {
// Progress Dialog
private ProgressDialog pDialog;

// Creating JSON Parser object
JSONParser jParser = new JSONParser();

ArrayList<HashMap<String, String>> productsList;

private static String url_all_articles = "http://localhost/articles.xml";

// JSON Node names
public static final String TAG_SUCCESS = "success";
public static final String TAG_ARTICLES = "articles";
public static final String TAG_ID = "id";
public static final String TAG_TITLE = "title";
public static final String TAG_DATE_END = "date_end";
public static final String TAG_DATA = "data";
public static final String TAG_IMAGE = "image";

ListView list;
LazyAdapter adapter;

// przyciski
Button home, articles, forum, logowanie;

// products JSONArray
JSONArray products = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// aktywacja buttonów
home = (Button) findViewById(R.id.button1);
articles = (Button) findViewById(R.id.button2);
forum = (Button) findViewById(R.id.button3);
logowanie = (Button) findViewById(R.id.button4);
articles.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
Intent in = new Intent(getApplicationContext(),Articles.class);
in.putExtra("action", "cat");

if(isIntentActivityAvailable(in)) {
startActivityForResult(in, 100);
} else {
Toast.makeText(getApplicationContext(),"Your system hasn't necessary application for this intent", Toast.LENGTH_LONG).show();
}
Log.i("Content ","Kategorie artykulow");
}
});

// Hashmap for ListView
productsList = new ArrayList<HashMap<String, String>>();

if(!isNetworkConnected(this)) {
Toast.makeText(this, "Brak połączenia z internetem", Toast.LENGTH_LONG).show();
} else {
new LoadAllProducts().execute();
}
// Get listview
ListView lv = getListView();
// on seleting single product
// launching Edit Product Screen
lv.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
String pid = ((TextView) view.findViewById(R.id.id)).getText()
.toString();

// Starting new intent
Intent in = new Intent(getApplicationContext(),
Contest_info.class);
// sending pid to next activity
in.putExtra(TAG_ID, pid);

// starting new activity and expecting some response back
if(isIntentActivityAvailable(in)) {
startActivityForResult(in, 100);
} else {
Toast.makeText(getApplicationContext(),"Your system hasn't necessary application for this intent", Toast.LENGTH_LONG).show();
}

}
});
}

protected boolean isIntentActivityAvailable(Intent intent) {
PackageManager packageManager = getApplicationContext().getPackageManager();
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return resolveInfo.size() > 0;
}

class LoadAllProducts extends AsyncTask<String, String, String> {

/**
* Before starting background thread Show Progress Dialog
* */
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Trwa wczytywanie ostatnio dodanych artykulow...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}

/**
* getting All products from url
* */
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
JSONObject json = jParser.makeHttpRequest(url_all_products, "GET", params);

// Check your log cat for JSON reponse
try {
// Checking for SUCCESS TAG
int success = json.getInt(TAG_SUCCESS);

if (success == 1) {
// products found
// Getting Array of Products
products = json.getJSONArray(TAG_ARTICLES);
// looping through All Products
for (int i = 0; i < products.length(); i++) {
JSONObject c = products.getJSONObject(i);
// Storing each json item in variable
String id = c.getString(TAG_ID);
String title = c.getString(TAG_TITLE);
String data = c.getString(TAG_DATA);
String date_end = c.getString(TAG_DATE_END);
String image = c.getString(TAG_IMAGE);

// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();

// adding each child node to HashMap key => value
map.put(TAG_ID, id);
map.put(TAG_TITLE, title);
map.put(TAG_DATA, data);
map.put(TAG_DATE_END, date_end);
map.put(TAG_IMAGE, image);
// adding HashList to ArrayList
productsList.add(map);
}

}
} catch (JSONException e) {
e.printStackTrace();
}

return null;
}
protected void onPostExecute(String file_url) {

// dismiss the dialog after getting all products
pDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {

public void run() {
/**
* Updating parsed JSON data into ListView
* */
adapter=new LazyAdapter(MainActivity.this, productsList);
// updating listview
setListAdapter(adapter);

}
});

}

public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.game_menu, menu);
return true;
}
}

public boolean isNetworkConnected(Context context)
{
ConnectivityManager connectionManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectionManager.getActiveNetworkInfo() != null && connectionManager.getActiveNetworkInfo().isAvailable() && connectionManager.getActiveNetworkInfo().isConnected())
{
return true;
}

else
{
return false;
}
}
}

menu z przycisku nie działa...

w manifeście dałem:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testowa"
android:versionCode="1"
android:versionName="1.0"
android:installLocation="auto"
android:configChanges="keyboardHidden|orientation" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />

i niestety po przechyleniu telefonu wczytuje od nowa...

Temat: własna aplikacja i kilka pytań

Po pierwsze, masz w tym kodzie okropny bałagan i pewnie dlatego ciężko Ci się w tym połapać. Poczytaj sobie o zasadach SOLID i wzorcach projektowych.
Po drugie, czy dostajesz jakiś błąd lub komunikat wyjątku w LogCacie?
Poza tym, napisałeś "menu z przycisku nie działa...". Jakie menu i z jakiego przycisku? Tam masz kilka przycisków i co to znaczy "nie działa"? Jaki efekt chciałeś osiągnąć? Co miało się stać po kliknięciu w przycisk i w który?
Ponadto, jeśli działasz w obrębie jednego Activity, to nie ma sensu ciągle odwoływać się do kontekstu aplikacji (metoda getApplicationContext()). Możesz odwołać się do bieżącego Activity za pomocą słowa kluczowego "this".
Dodatkowo, w Manifeście, parametr android:configChanges należy podać w tagu definiującym konkretne Activity, a nie w głównym tagu Manifestu. Np.


<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden"/>
Adrian P.

Adrian P. pamiętaj o tym, kto
chce latać musi
skoczyć

Temat: własna aplikacja i kilka pytań

Trochę uporządkowałem kod:
public class MainActivity extends Activity {
// przyciski
Button home, artykuly, forum, logowanie;
// lista ostatnio dodanych artykulow
private ListView lv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// aktywacja buttonów
home = (Button) findViewById(R.id.button1);
artykuly = (Button) findViewById(R.id.button2);
forum = (Button) findViewById(R.id.button3);
logowanie = (Button) findViewById(R.id.button4);
lv = (ListView) findViewById(R.id.list);
// inicjalizacja buttonów
initButtonsOnClickListeners();
// inicjalizacja ListView
initLastAddedArticlesListView();
}

private void initLastAddedArticlesListView() {
if(!isNetworkConnected(this)) {
Toast.makeText(this, "Brak połączenia z internetem", Toast.LENGTH_LONG).show();
} else {
new LoadLastAddedArticles(this).execute();
}
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// getting values from selected ListItem
String pid = ((TextView) view.findViewById(R.id.id)).getText().toString();
Intent in = new Intent(getApplicationContext(), Articles_info.class);
in.putExtra(Tags.TAG_ID, pid);
if(isIntentAvailable(in)) {
startActivityForResult(in, 100);
} else {
Toast.makeText(getApplicationContext(),"Your system hasn't necessary application for this intent", Toast.LENGTH_LONG).show();
}
Log.i("Content "," Kategorie artykulow");
}
});
}

private void initButtonsOnClickListeners() {
artykuly.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
openArticlesList();
}
});
}

protected void openArticlesList() {
Intent in = new Intent(getApplicationContext(), Artykuly.class);
in.putExtra("action", "cat");
if(isIntentAvailable(in)) {
startActivityForResult(in, 100);
} else {
Toast.makeText(getApplicationContext(),"Your system hasn't necessary application for this intent", Toast.LENGTH_LONG).show();
}
Log.i("Content "," Kategorie konkursów");
}

protected boolean isIntentAvailable(Intent intent) {
PackageManager packageManager = getApplicationContext().getPackageManager();
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return resolveInfo.size() > 0;
}


public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.game_menu, menu);
return true;
}

public boolean isNetworkConnected(Context context)
{
ConnectivityManager connectionManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectionManager.getActiveNetworkInfo() != null && connectionManager.getActiveNetworkInfo().isAvailable() && connectionManager.getActiveNetworkInfo().isConnected())
{
return true;
}

else
{
return false;
}
}
}


i działa :)

Dziękuję za pomoc :)

Mam jeszcze jednak jedno pytanie.
Mam LoadLastAddedContest.class i w niej:
	public LoadLastAddedContest(Object cxts) {
cxt = cxts;
pDialog = new ProgressDialog((Context) cxt);
}
protected void onPreExecute() {
super.onPreExecute();
pDialog.setMessage("Trwa wczytywanie ostatnio dodanych artykułów...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting all products
pDialog.dismiss();
adapter=new LazyAdapter((Activity) context, productsList);
//setListAdapter(adapter); - to nie działało...
Activity activity = (Activity) cxt;
ListView lv = (ListView) activity.findViewById(R.id.list);
lv.setAdapter(adapter);
}

czy takie wywołanie jest poprawne?

Temat: własna aplikacja i kilka pytań

Jeżeli działa, to znaczy, że jest poprawne.
Jedyne, nad czym można się zastanowić, to jak napisać ten kod lepiej.
Np. tworzenie obiektu o nazwie "lv" możesz przenieść do konstruktora lub wyciągnąć do Activity. Domyślam się, że jest to kod klasy dziedziczącej po klasie AsyncTask ze względu na implementowane metody. To samo można zrobić z adapterem oraz zmienną "activity". Nie ma sensu tworzyć nowych obiektów za każdym razem w metodach onPreExecute() lub onPostExecute().
Przypisanie: cxt = cxts; też jest bez sensu, bo możesz odwołać się bezpośrednio do zmiennej cxts.
Poza tym, zamiast ogólnego obiektu typu Object najlepiej przekazać interfejs, który będzie implementowany przez Activity i będzie pewną fasadą (kontraktem) pomiędzy AsyncTaskiem a Activity. W tym interfejsie możemy zawrzeć odpowiednie gettery, aby móc odwoływać się do elementów z Activity. Ponadto, najlepiej wszystkie klasy, w tym AsyncTask, trzymać w osobnych plikach.

Mówiąc krótko, jeżeli kod działa, to znaczy, że aplikacja jest napisana dobrze, ale z pewnością ten kod można napisać znacznie lepiej i sprawić, że wszystko będzie lepiej zorganizowane i będzie działało szybciej.

Abstrahując od tego kodu, sama architektura Androida nie jest idealna i najlepiej tworzyć osobne klasy kontrolerów dla wszystkich klas typu Activity oraz odpowiednie dla nich interfejsy. Wtedy możemy dobrze zorganizować kod i "odchudzić" Activity. Większość tutoriali dostępnych w internecie kultywuje sposób programowania polegający na wrzucaniu wszystkiego do Activity, co nie jest najlepszym pomysłem i nie jest to dobra praktyka. Niestety reorganizacja kodu wymaga dodatkowej zabawy i przeprojektowywania aplikacji. Jest to temat na osobą dyskusję.
Adrian P.

Adrian P. pamiętaj o tym, kto
chce latać musi
skoczyć

Temat: własna aplikacja i kilka pytań

Przeniosłem lv do LoadLastAddedArticles, isIntentAvailable dałem public, niestety dalej LoadLastAddedArticles(Object cxts) a w nim this.activity = (MainActivity) cxts; i this.context = (Context) cxts;

Dałem Object bo ProgressDialog wymaga Context, a nie wiem jak to wyciągnąć z Activity, bo .getApplicationContext() nie działa...
Sebastian Wroni

Sebastian Wroni Account Manager,
Własna działaność

Temat: własna aplikacja i kilka pytań

W zakresie poszukiwań konkretnej firmy świadczącej usługi w zakresie tworzenia rozbudowanych aplikacji w branży retail oraz ecommerce to mogę jak najbardziej polecić Wam kontakt z firmą https://appchance.com/pl/ którzy mają ogromne doświadczenie w branży i co najważniejsze biznes może się skutecznie rozwijać docierając do nowych osób i ułatwiając im zakupy. U nas poszło super, kawał dobrej pracy na partnerskich warunkach. Pozdrawiam serdecznie!



Wyślij zaproszenie do