ZMedia Purwodadi

Cara Membuat Project Di Android Studio, Aplikasi LaporIN (Anonim)

Daftar Isi

Cara Membuat Aplikasi Di Android Studio, LaporIN

Hallo Sobat Programmer!!, Pada artikel kali ini saya akan menjalaskan sebuah Aplikasi LaporIN serta memberikan tutorial singkat cara membuat sebuah project di AndroidStudio. bagi sobat programmer yang belum paham cara menginstall AndroidStudio, bisa lihat di Cara Install AndroidStudio jangan lupa dibaca ya sob!!

Aplikasi LaporIN merupakan sebuah aplikasi pengaduan layanan masyarakat yang terdapat permasalahan pada saat sekarang yang dimana problemnya itu masyarakat takut dalam melaporkan tindak kejahatan seperti pemakaian narkoba, dan rata - rata takut data yang melaporkan tindak kejahatan tersebut di cari oleh oknum. Maka dari itu, saya mengangkat permasalahan ini dan saya jadikan sebuah solusi mengenai Aplikasi LaporIN (Anonim). Sediakan kopi!! langsung saja simak artikel sampai habis ya sob!!

Persiapan Pembuatan Aplikasi

Sebelum sobat masuk dalam pembuatan project di android studio, sobat harus mempersiapkan beberapa tahap untuk mengembangkan aplikasi diandroidstudio. Emang penting? Ya penting dong sob!! karena jika sobat tidak melakukan persiapannya maka sobat akan kebingungan dan apa yang harus dilakukan!! berikut ini merupakan tahapan dalam pembuatan aplikasi android di AndroidStudio:

1. Identifikasi Kebutuhan
    Pada tahap awal ini, sobat harus mengidentifikasikan telebih dahulu apa saja kebutuhan aplikasi yang sobat inginkan, apa masalah yang ingin diselesaikan, target pengguna, fitur utama, platformnya apa. Nah, jika sudah di definisikan semuanya, maka bisa masuk ketahap 2.
2. Design
    Pada tahap kedua ini, sobat harus mengedesign tampilan yang dibutuhkan, dan sobat jadikan design tersebut ke prototipe, sobat bisa membuat designnya menggunakan figma, atau tools lainnya. Berikut dibawah ini merupakan design dari aplikasi LaporIN, dan ini link design figmanya.

Design LaporIN
Nah, persiapan diatas merupakan persiapan sederhana, dan pastikan tahap ke 2 itu sangat penting, agar sobat tidak bingung dalam pembuatan tampilan di androidStudio.

Cara Membuat Project Di AndroidStudio

Berikut ini merupakan cara membuat sebuah project di androidstudio, tutorial ini hanya disarankan untuk para pemula yang ingin terjun ke dunia mobile programming.

Langkah 1: Buka AndroidStudionya
Langkah 2: Ketika sudah sobat buka, maka silahkan klik new project. jika sudah mengkliknya maka akan menampilkan sebuah dialog halaman template seperti gambar dibawah ini:

New Project

Langkah 3: Jika sudah muncul dialog halaman template, maka silahkan sobat pilih basic templatenya, pada tutorial artikel ini saya menggunakan Empty Views Activity, lalu klik next jika sudah pilih salah satu templatenya.
Langkah 4: Kemudian, jika klik tombol next, maka akan muncul tampilan pengaturan target android versionnya seperti gambar dibawah ini. dan sobat bisa menyesuaikannya, pada pengaturan ini, saya menggunakan bahasa java, dan untuk api androidnya api version 24. Klik tombol finish jika sudah menyesuaikan peraturannya.

Pengaturan Android Version

Langkah 5: Setelah selesai, akan ada window yang dimana window tersebut merupakan workspace project androidstudio tadi yang telah sobat buat! dan tampilannya seperti gambar dibawah ini:

Workspace androidstudio

Nah, cukup mudah bukan untuk membuat sebuah project dasar aplikasi di androidstudio!!, jangan bosan dulu ya sobat, karena terdapat penjelasan aplikasi LaporIN! Sediakan kopi. 

Aplikasi LaporIN

Terdapat beberapa libray yang digunakan untuk membuat aplikasi LaporIN, berikut ini merupakan tools atau librarynya:

implementation("androidx.cardview:cardview:1.0.0")
implementation("com.google.android.gms:play-services-location:18.0.0")
implementation("org.osmdroid:osmdroid-android:6.1.10")
implementation("com.github.mkergall:osmbonuspack:6.9.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")
implementation("com.karumi:dexter:6.2.3")
implementation("com.android.volley:volley:1.2.1")
implementation("com.github.bumptech.glide:glide:4.15.1")
annotationProcessor("com.github.bumptech.glide:compiler:4.15.1")
Diatas merupakan library yang saya gunakan untuk membuat sebuah aplikasi LaporIN. Lalu, saya juga menggunakan openstreetmap digunakan untuk menampilkan maps, dikarena ini aplikasi sederhana, jadi saya menggunakan openstreetmap yang gratis. Setelah itu, berikut ini merupakan kode xml dibawah untuk list news berita pada home page.

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="12dp"
    android:background="@drawable/rounded_background"
    android:elevation="4dp"
    android:layout_marginBottom="16dp">

    <!-- Kontainer untuk Konten Berita -->
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">

        <!-- Kategori -->
        <TextView
            android:id="@+id/newsCategory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Kejahatan"
            android:textColor="#007AFF"
            android:textSize="12sp"
            android:fontFamily="sans-serif-medium"
            android:layout_marginBottom="4dp" />

        <!-- Judul Berita -->
        <TextView
            android:id="@+id/newsTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="10 Tips Untuk Orang Jahat dapat membantu Anda tetap hidup sehat dan bahagia."
            android:textSize="14sp"
            android:fontFamily="sans-serif-medium"
            android:lineSpacingExtra="2dp"
            android:layout_marginBottom="8dp" />

        <!-- Deskripsi Berita -->
        <TextView
            android:id="@+id/newsSummary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Deskripsi singkat berita"
            android:textSize="12sp"
            android:fontFamily="sans-serif"
            android:textColor="#808080"
            android:visibility="gone" />
    </LinearLayout>

    <!-- Gambar -->
    <ImageView
        android:id="@+id/newsImage"
        android:layout_width="72dp"
        android:layout_height="72dp"
        android:scaleType="centerCrop"
    />
</LinearLayout>
Nah, kenapa saya pisah dari xml awalnya, karena list_news.xml pada kode diatas agar saya mudah menghandlenya, jadi nanti tinggal menampilkannya menggunakan java, berikut dibawah ini merupakan kode javanya. dibawah ini class Article untuk menyimpan data sementara.

package com.mopro;
public class Article {
    private int id;
    private String category;
    private String title;
    private String content;
    private String image;
    public Article(int id, String category, String title, String content, String image) {
        this.id = id;
        this.category = category;
        this.title = title;
        this.content = content;
        this.image = image;
    }
    public int getId() {
        return id;
    }
    public String getCategory() {
        return category;
    }
    public String getTitle() {
        return title;
    }
    public String getContent() {
        return content;
    }
    public String getImage() {
        return image;
    }
}

Dan kode dibawah ini merupakan kode utama untuk menampilkan artikel. Terdapat Metode fetchArticles digunakan untuk mengambil data artikel dari API menggunakan library Volley di Android. Metode ini mengirimkan permintaan GET ke URL API, memproses respons JSON, dan memperbarui data pada antarmuka. Jika respons berhasil, metode memeriksa status success dan membaca data artikel dari array data. Setiap artikel diolah menjadi objek Article yang ditambahkan ke dalam daftar dan diperbarui melalui adapter. Jika judul artikel terlalu panjang, akan dipotong dan ditambahkan elipsis. Jika permintaan gagal, error ditangani dengan mencatat log dan menampilkan pesan kepada pengguna menggunakan Toast. Semua permintaan dijalankan secara asynchronous melalui queue Volley.

package com.mopro;


import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.widget.Button;
import android.content.Intent;
import android.view.View;
import android.widget.LinearLayout;

// Volley adalah library untuk melakukan HTTP request dengan lebih mudah
import com.android.volley.Request;
import com.android.volley.toolbox.JsonObjectRequest;  // Digunakan untuk melakukan request JSON
import com.android.volley.toolbox.Volley;  // Volley menyediakan queue untuk mengelola request
import com.android.volley.Response;  // Digunakan untuk menangani response
import com.android.volley.VolleyError;  // Digunakan untuk menangani error saat request

import org.json.JSONArray;  // Untuk membaca array JSON dari response
import org.json.JSONException;  // Untuk menangani kesalahan parsing JSON
import org.json.JSONObject;  // Untuk memanipulasi objek JSON

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

import android.util.Log;  // Untuk menambahkan log debug di Android

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;  // Komponen untuk menampilkan daftar data dalam format list atau grid
    private NewsAdapter adapter;  // Adapter bertugas untuk menghubungkan data dengan RecyclerView
    private List<Article> articleList = new ArrayList<>();  // List untuk menyimpan data artikel

    private LinearLayout addReport, search;

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

        // Inisialisasi tombol
        addReport = findViewById(R.id.addReport);
        search = findViewById(R.id.search);

        // Set listener untuk tombol
        addReport.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Arahkan ke ReportActivity
                Intent intent = new Intent(MainActivity.this, ReportActivity.class);
                startActivity(intent);
            }
        });
        // Set listener untuk tombol
        search.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Arahkan ke ReportActivity
                Intent intent = new Intent(MainActivity.this, ReportDetailActivity.class);
                startActivity(intent);
            }
        });

        // Inisialisasi RecyclerView
        recyclerView = findViewById(R.id.newsRecyclerView);  // Hubungkan RecyclerView dengan ID di layout XML
        recyclerView.setLayoutManager(new LinearLayoutManager(this));  // Atur layout menjadi Linear (list)

        // Inisialisasi adapter dan hubungkan dengan RecyclerView
        adapter = new NewsAdapter(this, articleList);
        recyclerView.setAdapter(adapter);

        // Panggil fungsi untuk mengambil artikel dari server
        fetchArticles();
    }

    private void fetchArticles() {
        // URL API untuk mengambil data artikel
        String url = "https://getkey.my.id/api/v1/getArticle"; // Ganti dengan URL API Anda

        // Membuat request GET menggunakan JsonObjectRequest
        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
                new Response.Listener<JSONObject>() {  // Listener untuk response
                    @Override
                    public void onResponse(JSONObject response) {
                        try {
                            // Periksa apakah response berhasil (dengan field "success" == true)
                            if (response.getBoolean("success")) {
                                // Ambil array "data" dari response
                                JSONArray articles = response.getJSONArray("data");
                                for (int i = 0; i < articles.length(); i++) {
                                    // Ambil setiap objek artikel dari array
                                    JSONObject articleObj = articles.getJSONObject(i);

                                    // Ambil dan potong judul jika terlalu panjang
                                    String title = articleObj.getString("title");
                                    int maxLength = 50;  // Panjang maksimum judul
                                    if (title.length() > maxLength) {
                                        title = title.substring(0, maxLength) + "...";  // Tambahkan elipsis jika dipotong
                                    }

                                    // Buat objek Article dengan data yang diambil dari response
                                    Article article = new Article(
                                            articleObj.getInt("id"),
                                            articleObj.getString("category"),  // Kategori artikel
                                            title,  // Judul artikel (sudah dipotong jika panjang)
                                            articleObj.getString("content"),  // Isi artikel
                                            articleObj.getString("image")  // URL gambar artikel
                                    );

                                    // Tambahkan artikel ke dalam list
                                    articleList.add(article);
                                }

                                // Beritahu adapter bahwa data telah berubah, agar RecyclerView di-update
                                adapter.notifyDataSetChanged();
                            } else {
                                // Jika response tidak mengandung "success", log pesan error
                                Log.e("API Response", "Failed to fetch data: " + response.getString("message"));
                            }
                        } catch (JSONException e) {
                            // Tangani kesalahan parsing JSON
                            Log.e("JSON Parsing Error", "Error parsing response: " + e.getMessage());
                            e.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {  // Listener untuk menangani error pada request
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        // Tampilkan log error jika request gagal
                        Log.e("API Request Error", "Error fetching data: " + error.getMessage());
                        // Tampilkan pesan kesalahan kepada pengguna
                        Toast.makeText(MainActivity.this, "Error fetching data", Toast.LENGTH_SHORT).show();
                    }
                });

        // Tambahkan request ke queue Volley untuk dieksekusi
        Volley.newRequestQueue(this).add(request);
    }
}

diatas merupakan penjelasan kode dari home page, dibawah ini merupakan kode dari form create laporan xml dan java. Berikut dibawah ini merupakan kodenya;

 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white">

    <!-- Toolbar -->
    <RelativeLayout
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:padding="16dp">

        <ImageButton
            android:id="@+id/btn_back"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_centerVertical="true"
            android:background="?attr/selectableItemBackgroundBorderless"
            android:src="@drawable/ic_arrow_back"
            android:contentDescription="Back button" />

        <TextView
            android:id="@+id/toolbar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Buat Laporan"
            android:textColor="@color/black"
            android:textSize="20sp"
            android:textStyle="bold" />
    </RelativeLayout>

    <!-- Main Content -->
    <ScrollView
        android:id="@+id/main_scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/btn_submit"
        android:layout_below="@id/toolbar"
        android:fillViewport="true">

        <LinearLayout
            android:id="@+id/form_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">

            <TextView
                android:id="@+id/label_form_instructions"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Lengkapi data laporan kamu!"
                android:textColor="@color/black"
                android:textSize="16sp"
                android:layout_marginBottom="24dp"/>

            <TextView
                android:id="@+id/label_basic_info"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Informasi dasar"
                android:textColor="@color/black"
                android:textSize="24sp"
                android:textStyle="bold"
                android:layout_marginBottom="32dp"/>

            <!-- Judul Laporan -->
            <TextView
                android:id="@+id/label_judul"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Judul Laporan"
                android:textColor="@color/black"
                android:textSize="16sp"
                android:layout_marginBottom="8dp"/>

            <EditText
                android:id="@+id/edt_judul"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/edit_text_background"
                android:textColorHint="@color/grey"
                android:textColor="@color/grey"
                android:hint="Judul Laporan"
                android:padding="16dp"

                android:textSize="16sp"
                android:layout_marginBottom="24dp"/>

            <!-- Penjelasan Laporan -->
            <TextView
                android:id="@+id/label_penjelasan"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Penjelasan Laporan"
                android:textColor="@color/black"
                android:textSize="16sp"
                android:layout_marginBottom="8dp"/>

            <EditText
                android:id="@+id/edt_penjelasan"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColorHint="@color/grey"
                android:textColor="@color/grey"
                android:background="@drawable/edit_text_background"
                android:hint="Contoh: Terdapat 2 orang pria menggunakan narkoba, dll"
                android:padding="16dp"
                android:minHeight="120dp"
                android:gravity="top"
                android:textSize="16sp"
                android:layout_marginBottom="8dp"/>

            <TextView
                android:id="@+id/label_penjelasan_limit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Maks 100 Karakter"
                android:textColor="@color/grey"
                android:textSize="12sp"
                android:layout_gravity="end"
                android:layout_marginBottom="24dp"/>

            <!-- File Pendukung -->
            <TextView
                android:id="@+id/label_file_pendukung"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="File Pendukung"
                android:textColor="@color/black"
                android:textSize="16sp"
                android:layout_marginBottom="8dp"/>

            <LinearLayout
                android:id="@+id/file_upload_container"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/edit_text_background"
                android:padding="16dp"
                android:gravity="center_vertical">

                <TextView
                    android:id="@+id/label_upload"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="Unggah"
                    android:textColor="@color/grey"
                    android:textSize="16sp"/>

                <ImageButton
                    android:id="@+id/btn_upload"
                    android:layout_width="24dp"
                    android:layout_height="24dp"
                    android:background="?attr/selectableItemBackgroundBorderless"
                    android:src="@drawable/camera"
                    android:contentDescription="Upload button"/>
            </LinearLayout>

            <TextView
                android:id="@+id/label_file_type"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Gambar"
                android:textColor="@color/grey"
                android:textSize="12sp"
                android:layout_gravity="end"
                android:layout_marginBottom="24dp"/>

            <!-- Alamat -->
            <TextView
                android:id="@+id/label_alamat"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Alamat"
                android:textColor="@color/black"
                android:textSize="16sp"
                android:layout_marginBottom="8dp"/>

            <EditText
                android:id="@+id/edt_alamat"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/edit_text_background"
                android:hint="Alamat kejahatan/kejadian"
                android:padding="16dp"
                android:minHeight="120dp"
                android:textColorHint="@color/grey"
                android:textColor="@color/grey"
                android:gravity="top"
                android:textSize="16sp"
                android:layout_marginBottom="8dp"/>

            <TextView
                android:id="@+id/label_alamat_limit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Maks 100 Karakter"
                android:textColor="@color/grey"
                android:textSize="12sp"
                android:layout_gravity="end"/>
        </LinearLayout>
    </ScrollView>

    <!-- Button Submit -->
    <Button
        android:id="@+id/btn_submit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_margin="16dp"
        android:background="@drawable/button_background"
        android:text="Lanjut"
        android:textColor="@color/white"
        android:textSize="16sp"/>

</RelativeLayout>

Kode di bawah adalah kode untuk mengirim laporan dengan file (gambar) menggunakan Retrofit. Pengguna mengisi judul, deskripsi, dan alamat, kemudian memilih file untuk diunggah. File dan data laporan dikirim melalui API menggunakan multipart request. Retrofit mengelola komunikasi HTTP, sedangkan file sementara disimpan di cache aplikasi untuk dikirimkan ke server. Setelah laporan berhasil dikirim, pengguna diarahkan ke layar lain, seperti peta, dengan ID laporan. Aplikasi juga menghapus file sementara saat aktivitas dihentikan untuk mencegah kebocoran memori pada hp pengguna.

package com.mopro;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitClient {
    private static final String BASE_URL = "https://getkey.my.id/api/v1/";
    private static Retrofit retrofit;

    public static Retrofit getInstance() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

package com.mopro;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;

public interface ApiService {
    @Multipart
    @POST("Report")
    Call uploadReport(
            @Part("title") RequestBody title,
            @Part("description") RequestBody description,
            @Part("address") RequestBody address,
            @Part MultipartBody.Part file
    );
}


package com.mopro;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.OpenableColumns;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class ReportActivity extends AppCompatActivity {

    private static final String TAG = "ReportActivity";

    private EditText edtJudul, edtPenjelasan, edtAlamat;
    private ImageButton btnUpload;
    private Button btnLanjut;
    private TextView labelUpload;
    private ImageView btn_back;
    private Uri fileUri;
    private File cachedFile; // File sementara untuk pengiriman

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_create_report);
        btn_back = findViewById(R.id.btn_back);
        btn_back.setOnClickListener(v -> finish());

        // Inisialisasi elemen UI
        edtJudul = findViewById(R.id.edt_judul);
        edtPenjelasan = findViewById(R.id.edt_penjelasan);
        edtAlamat = findViewById(R.id.edt_alamat);
        btnUpload = findViewById(R.id.btn_upload);
        btnLanjut = findViewById(R.id.btn_submit);
        labelUpload = findViewById(R.id.label_upload);

        // Pilih file untuk diunggah
        btnUpload.setOnClickListener(v -> pilihFile());

        // Tombol untuk mengirim laporan
        btnLanjut.setOnClickListener(v -> kirimLaporan());
    }

    private void pilihFile() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        startActivityForResult(intent, 1);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1 && resultCode == RESULT_OK && data != null && data.getData() != null) {
            fileUri = data.getData();
            labelUpload.setText(getFileName(fileUri));
            Log.d(TAG, "File URI: " + fileUri.toString());
        }
    }

    private void kirimLaporan() {
        String judul = edtJudul.getText().toString().trim();
        String penjelasan = edtPenjelasan.getText().toString().trim();
        String alamat = edtAlamat.getText().toString().trim();

        if (judul.isEmpty() || penjelasan.isEmpty() || alamat.isEmpty()) {
            Toast.makeText(this, "Harap isi semua data!", Toast.LENGTH_SHORT).show();
            return;
        }

        if (fileUri == null) {
            Toast.makeText(this, "Harap pilih file terlebih dahulu!", Toast.LENGTH_SHORT).show();
            return;
        }

        try {
            cachedFile = createCacheFile(fileUri);
            MultipartBody.Part filePart = MultipartBody.Part.createFormData(
                    "file", cachedFile.getName(),
                    RequestBody.create(MediaType.parse(getContentResolver().getType(fileUri)), cachedFile)
            );

            RequestBody judulPart = RequestBody.create(MediaType.parse("text/plain"), judul);
            RequestBody penjelasanPart = RequestBody.create(MediaType.parse("text/plain"), penjelasan);
            RequestBody alamatPart = RequestBody.create(MediaType.parse("text/plain"), alamat);

            ApiService apiService = RetrofitClient.getInstance().create(ApiService.class);
            Call<ReportResponse> call = apiService.uploadReport(judulPart, penjelasanPart, alamatPart, filePart);

            call.enqueue(new Callback<ReportResponse>() {
                @Override
                public void onResponse(Call<ReportResponse> call, Response<ReportResponse> response) {
                    if (response.isSuccessful() && response.body() != null) {
                        ReportResponse reportResponse = response.body();
                        if (reportResponse.isSuccess()) {
                            int idReport = reportResponse.getId(); // Ambil ID dari respons

                            // Beralih ke Maps.class dan kirimkan ID laporan
                            Intent intent = new Intent(ReportActivity.this, Maps.class);
                            intent.putExtra("id_report", idReport); // Kirim ID report ke Maps
                            startActivity(intent);
                            finish();
                        } else {
                            Toast.makeText(ReportActivity.this, reportResponse.getMessage(), Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        Log.e(TAG, "Gagal mengirim laporan. Response code: " + response.code());
                        Toast.makeText(ReportActivity.this, "Gagal mengirim laporan: " + response.message(), Toast.LENGTH_SHORT).show();
                    }
                }

                @Override
                public void onFailure(Call<ReportResponse> call, Throwable t) {
                    Log.e(TAG, "Terjadi kesalahan saat mengirim laporan.", t);
                    Toast.makeText(ReportActivity.this, "Kesalahan: " + t.getMessage(), Toast.LENGTH_SHORT).show();
                }
            });
        } catch (IOException e) {
            Log.e(TAG, "Gagal membuat file sementara", e);
            Toast.makeText(this, "Gagal memproses file!", Toast.LENGTH_SHORT).show();
        }
    }

    private File createCacheFile(Uri uri) throws IOException {
        // Ambil nama asli file
        String fileName = getFileName(uri);
        if (fileName == null) {
            fileName = "file_" + System.currentTimeMillis(); // Nama default jika tidak ditemukan
        }

        // Buat file sementara di cache
        File tempFile = new File(getCacheDir(), fileName);
        try (InputStream inputStream = getContentResolver().openInputStream(uri);
             FileOutputStream outputStream = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
        }
        return tempFile;
    }

    private String getFileName(Uri uri) {
        try (Cursor cursor = getContentResolver().query(uri, null, null, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            }
        }
        return null; // Jika tidak ditemukan
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (cachedFile != null && cachedFile.exists()) {
            cachedFile.delete(); // Hapus file sementara jika aplikasi dihentikan
        }
    }
}

Setelah halaman pembuatan laporan, maka berikut ini halaman maps xml dan javanya:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Top Bar -->
    <LinearLayout
        android:id="@+id/top_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="@color/white"
        android:padding="16dp"
        android:elevation="4dp">

        <!-- Title -->
        <TextView
            android:id="@+id/title_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:text="Titik Posisi MAPS"
            android:textSize="18sp"
            android:textColor="@color/black"
            android:gravity="center_vertical" />
    </LinearLayout>

    <!-- Search Bar -->
    <EditText
        android:id="@+id/search_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/top_bar"
        android:textColorHint="@color/grey"
        android:textColor="@color/grey"
        android:hint="Cari Lokasi"
        android:padding="12dp"
        android:background="@android:color/white"
        android:drawableLeft="@android:drawable/ic_menu_search"
        android:drawablePadding="8dp"
        android:imeOptions="actionSearch"
        android:inputType="text"
        android:elevation="2dp" />

    <!-- Map View -->
    <org.osmdroid.views.MapView
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/search_bar" />

    <!-- Button Laporkan Sekarang -->
    <Button
        android:id="@+id/btn_report"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="Laporkan Sekarang"
        android:padding="12dp"
        android:textSize="18sp"
        android:background="@color/lavender"
        android:textColor="@android:color/white" />
</RelativeLayout>

diatas merupakan kode tampilan maps xmlnya, dan dibawah ini kode untuk mengimplementasikan aktivitas peta di Android menggunakan osmdroid, yang memungkinkan pengguna mencari lokasi, melihat posisi mereka, dan melaporkan lokasi. Aplikasi menggunakan FusedLocationProviderClient untuk mendapatkan lokasi perangkat dan menampilkan marker di peta. Pengguna dapat mencari lokasi melalui kolom pencarian, dan lokasi yang dipilih akan dikirim ke server dengan ID laporan melalui permintaan POST. Setelah laporan berhasil dikirim, aplikasi menampilkan kode laporan. Kode juga mengelola izin lokasi dan memberikan umpan balik kepada pengguna jika terjadi kesalahan.

package com.mopro;

import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;

import org.json.JSONException;
import org.json.JSONObject;
import org.osmdroid.config.Configuration;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.Marker;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Locale;

public class Maps extends AppCompatActivity {
    private static final String API_URL = "https://getkey.my.id/api/v1/Location";
    private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
    private MapView mapView;
    private EditText searchBar;
    private Button btnReport;
    private GeoPoint lastSearchedPoint;

    private int idReport; // ID Report dari Intent

    // Location client
    private FusedLocationProviderClient fusedLocationClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Konfigurasi osmdroid
        Configuration.getInstance().setUserAgentValue(getPackageName());
        setContentView(R.layout.activity_maps);

        // Ambil ID report dari intent
        idReport = getIntent().getIntExtra("id_report", -1);

        if (idReport != -1) {
            Log.d("MapsActivity", "ID Report diterima: " + idReport);
        } else {
            Log.e("MapsActivity", "ID Report tidak ditemukan!");
        }

        // Inisialisasi komponen berdasarkan ID di XML
        mapView = findViewById(R.id.map);
        searchBar = findViewById(R.id.search_bar);
        btnReport = findViewById(R.id.btn_report);

        // Konfigurasi MapView
        mapView.setTileSource(TileSourceFactory.MAPNIK);
        mapView.setBuiltInZoomControls(true);
        mapView.setMultiTouchControls(true);

        // Inisialisasi FusedLocationProviderClient
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        // Meminta permission lokasi jika belum diberikan
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{
                    android.Manifest.permission.ACCESS_FINE_LOCATION,
                    android.Manifest.permission.ACCESS_COARSE_LOCATION
            }, LOCATION_PERMISSION_REQUEST_CODE);
        } else {
            getDeviceLocation();
        }

        setInitialLocation();

        // Listener untuk pencarian lokasi
        searchBar.setOnEditorActionListener((v, actionId, event) -> {
            if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) {
                String location = searchBar.getText().toString().trim();
                if (!location.isEmpty()) {
                    searchLocation(location);
                } else {
                    Toast.makeText(this, "Masukkan lokasi yang valid", Toast.LENGTH_SHORT).show();
                }
                return true;
            }
            return false;
        });

        // Listener untuk tombol "Laporkan Sekarang"
        btnReport.setOnClickListener(v -> {
            if (lastSearchedPoint != null) {
                saveLocationToServer(lastSearchedPoint.getLatitude(), lastSearchedPoint.getLongitude(), "Lokasi yang dilaporkan");
            } else {
                Toast.makeText(this, "Tidak ada lokasi untuk dilaporkan", Toast.LENGTH_SHORT).show();
            }
        });

    }

    private void setInitialLocation() {
        GeoPoint defaultLocation = new GeoPoint(3.595195, 98.672223);
        mapView.getController().setCenter(defaultLocation);
        mapView.getController().setZoom(15.0);
        mapView.invalidate();
        addMarker(defaultLocation, "Posisi Default", "Lokasi awal");
    }

    private void getDeviceLocation() {
        try {
            Task<android.location.Location> locationResult = fusedLocationClient.getLastLocation();
            locationResult.addOnSuccessListener(this, location -> {
                if (location != null) {
                    GeoPoint currentLocation = new GeoPoint(location.getLatitude(), location.getLongitude());
                    mapView.getController().setCenter(currentLocation);
                    mapView.getController().setZoom(15.0);
                    mapView.invalidate();
                    addMarker(currentLocation, "Lokasi Anda", "Lat: " + location.getLatitude() + ", Lon: " + location.getLongitude());
                } else {
                    Toast.makeText(Maps.this, "Lokasi perangkat tidak tersedia", Toast.LENGTH_SHORT).show();
                }
            });
        } catch (SecurityException e) {
            Log.e("Maps", "Security exception: " + e.getMessage());
        }
    }

    private void searchLocation(String location) {
        Geocoder geocoder = new Geocoder(this, Locale.getDefault());
        try {
            List<Address> addresses = geocoder.getFromLocationName(location, 1);
            if (addresses != null && !addresses.isEmpty()) {
                Address address = addresses.get(0);
                GeoPoint point = new GeoPoint(address.getLatitude(), address.getLongitude());
                lastSearchedPoint = point;
                mapView.getOverlays().clear();
                addMarker(point, location, address.getAddressLine(0));
                mapView.getController().setCenter(point);
                mapView.getController().setZoom(15.0);
                mapView.invalidate();
                Toast.makeText(this, "Lokasi ditemukan: " + location, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "Lokasi tidak ditemukan", Toast.LENGTH_SHORT).show();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(this, "Terjadi kesalahan: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private void addMarker(GeoPoint point, String title, String snippet) {
        Marker marker = new Marker(mapView);
        marker.setPosition(point);
        marker.setTitle(title);
        marker.setSnippet(snippet);
        marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
        mapView.getOverlays().add(marker);
    }

    private void saveLocationToServer(double latitude, double longitude, String description) {
        new SaveLocationTask().execute(idReport, latitude, longitude, description);
    }

    private class SaveLocationTask extends AsyncTask<Object, Void, JSONObject> {
        @Override
        protected JSONObject doInBackground(Object... params) {
            int idReport = (int) params[0];
            double latitude = (double) params[1];
            double longitude = (double) params[2];
            String description = (String) params[3];

            try {
                URL url = new URL(API_URL);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("POST");
                connection.setDoOutput(true);

                String data = "id_report=" + idReport + "&latitude=" + latitude + "&longitude=" + longitude + "&description=" + description;
                OutputStream os = connection.getOutputStream();
                os.write(data.getBytes());
                os.flush();
                os.close();

                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                reader.close();
                return new JSONObject(response.toString());
            } catch (Exception e) {
                Log.e("Maps", "Error: " + e.getMessage());
                return null;
            }
        }

        @Override
        protected void onPostExecute(JSONObject result) {
            if (result != null) {
                try {
                    String status = result.getString("status");
                    if ("success".equals(status)) {
                        String kode = result.getString("kode");
                        Intent intent = new Intent(Maps.this, Kode.class);
                        intent.putExtra("kode", kode);
                        startActivity(intent);
                        finish();
                    } else {
                        String message = result.getString("message");
                        Toast.makeText(Maps.this, message, Toast.LENGTH_SHORT).show();
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            } else {
                Toast.makeText(Maps.this, "Terjadi kesalahan.", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

Nah, pada kode diatas merupakan penjelasan singkat dan penting mengenai fitur utama dari aplikasi LaporIN, jika sobat programmer ingin mengotak atik kode lengkapnya bisa download disini Project Aplikasi LaporIN [Sudah include semua, dari database, api, dan skrip project] dan sobat programmer bisa memodifnya skrip laporIN sesuai dengan keinginan sobat. Berikut ini merupakan tampilan aplikasi LaporIN:

LaporIN

Terimakasih sudah membaca artikel ini hingga akhir, jika terdapat kalimat atau bahasa yang kurang di mengerti silahkan hubungi kami, atau berkomentar di artikel ini.

Posting Komentar